跟月影学可视化
月影
前奇虎 360 奇舞团团长,可视化 UI 框架 SpriteJS 核心开发者,《JavaScript 王者归来》作者
30206 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 54 讲
跟月影学可视化
15
15
1.0x
00:00/00:00
登录|注册

20 | 如何用WebGL绘制3D物体?

让立方体旋转
变换WebGL坐标系
法向量矩阵
构造法向量
构造圆柱体
模型矩阵
投影矩阵
计算立方体的顶点数据
扩展顶点到3维
顶点信息
片元着色器
顶点着色器
WebGL绘制3D图形
2D图形绘制
小试牛刀
要点总结
构造和使用法向量
WebGL绘制圆柱体
WebGL绘制三维立方体
WebGL绘制3D图形
如何用WebGL绘制3D物体?

该思维导图由 AI 生成,仅供参考

你好,我是月影。这一节课开始,我们学习 3D 图形的绘制。
之前我们主要讨论的都是 2D 图形的绘制,实际上 WebGL 真正强大之处在于,它可以绘制各种 3D 图形,而 3D 图形能够极大地增强可视化的表现能力。
用 WebGL 绘制 3D 图形,其实在基本原理上和绘制 2D 图形并没有什么区别,只不过是我们把绘图空间从二维扩展到三维,所以计算起来会更加复杂一些。
今天,我们就从绘制最简单的三维立方体,讲到矩阵、法向量在三维空间中的使用,这样由浅入深地带你去了解,如何用 WebGL 绘制出各种 3D 图形。

如何用 WebGL 绘制三维立方体

首先,我们来绘制熟悉的 2D 图形,比如矩形,再把它拓展到三维空间变成立方体。代码如下:
// vertex shader 顶点着色器
attribute vec2 a_vertexPosition;
attribute vec4 color;
varying vec4 vColor;
void main() {
gl_PointSize = 1.0;
vColor = color;
gl_Position = vec4(a_vertexPosition, 1, 1);
}
// fragment shader 片元着色器
#ifdef GL_ES
precision highp float;
#endif
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}
...
// 顶点信息
renderer.setMeshData([{
positions: [
[-0.5, -0.5],
[-0.5, 0.5],
[0.5, 0.5],
[0.5, -0.5],
],
attributes: {
color: [
[1, 0, 0, 1],
[1, 0, 0, 1],
[1, 0, 0, 1],
[1, 0, 0, 1],
],
},
cells: [[0, 1, 2], [0, 2, 3]],
}]);
renderer.render();
上面的 3 段代码,分别对应顶点着色器、片元着色器和基本的顶点信息。通过它们,我们就在画布上绘制出了一个红色的矩形。接下来,要想把 2 维矩形拓展到 3 维,我们的第一步就是要把顶点扩展到 3 维。这一步的操作比较简单,我们只需要把顶点从 vec2 扩展到 vec3 就可以了。
// vertex shader
attribute vec3 a_vertexPosition;
attribute vec4 color;
varying vec4 vColor;
void main() {
gl_PointSize = 1.0;
vColor = color;
gl_Position = vec4(a_vertexPosition, 1);
}
然后,我们需要计算立方体的顶点数据。我们知道一个立方体有 8 个顶点,这 8 个顶点能组成 6 个面。在 WebGL 中,我们就需要用 12 个三角形来绘制它。如果每个面的属性相同,我们就可以复用 8 个顶点来绘制。而如果属性不同,比如每个面要绘制成不同的颜色,或者添加不同的纹理图片,我们还得把每个面的顶点分开。这样的话,我们一共需要 24 个顶点。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

WebGL绘制3D物体技术总结: 本文深入介绍了使用WebGL绘制3D物体的技术细节。首先讨论了绘制3D图形的基本原理,强调了将绘图空间从二维扩展到三维的复杂性。随后详细介绍了通过代码实现绘制简单的三维立方体的步骤,包括顶点着色器、片元着色器和顶点信息的设置。作者还提到了开启深度检测和启用深度缓冲区的重要性,并介绍了使用gl-renderer库来简化这些步骤。文章还讨论了投影矩阵的概念,以及如何通过投影矩阵将WebGL的坐标系从左手系转换为右手系,从而实现正确的坐标显示。接着,展示了如何实现立方体的旋转效果,并介绍了绘制圆柱体的方法。最后,讲解了构造和使用法向量的重要性,并展示了在shader中实现点光源效果的方法。 在顶点着色器中,计算了点光源与几何体法线的夹角余弦,用于在片元着色器中叠加光照效果。通过法向量和法向量矩阵的运用,实现了点光源光照效果。文章还提到了构造非正立方体和绘制正四面体的方法,以及如何在这些几何体上实现点光源光照效果。 总的来说,本文通过具体的代码示例和技术讲解,帮助读者深入了解了WebGL绘制3D物体的基本原理和实现方法,为读者提供了丰富的技术知识和实践经验。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《跟月影学可视化》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(6)

  • 最新
  • 精选
  • 阿鑫
    正四面体光照效果,https://stupidehorizon.github.io/graphics/demo/07_3d_box/ 一开始没注意每个面的法向量方向,结果有的面发向量朝里了,还 debugger 了半天。

    作者回复: 赞

    2020-08-28
    2
    3
  • H
    老师写的文章还不错!!!
    2022-01-07
    1
  • 有一种踏实
    正四面体,就是取正立方体的四个非共棱顶点组成 function tetrahedron(size, colors = [[1, 0, 0, 1]]) { const h = 0.5 * size; const vertices = [ [-h, -h, -h], // 0 [-h, h, -h], // 1 [h, h, -h], // 2 [h, -h, -h], // 3 [-h, -h, h], // 4 [-h, h, h], // 5 [h, h, h], // 6 [h, -h, h], // 7 ]; const positions = []; const color = []; const cells = []; const normal = []; let colorIdx = 0; let cellsIdx = 0; const colorLen = colors.length; function triangle(a, b, c) { [a, b, c].forEach((i) => { positions.push(vertices[i]); color.push(colors[colorIdx % colorLen]); }); cells.push([0, 1, 2].map(i => i + cellsIdx)); const tmp1 = []; const tmp2 = []; const norm = []; cross(norm, subtract(tmp1, vertices[b], vertices[a]), subtract(tmp2, vertices[c], vertices[a])); normalize(norm, norm); normal.push(norm, norm, norm); colorIdx++; cellsIdx += 3; } triangle(1, 4, 6); triangle(1, 6, 3); triangle(1, 3, 4); triangle(6, 4, 3); return { positions, color, cells, normal }; }
    2024-02-02归属地:上海
  • 蹦哒
    老师、同学们,立方体每个面的颜色为啥不会插值,而是同一个颜色呢?
    2023-03-06归属地:北京
  • JackWang
    老师,为什么我按照您的方法渲染后,发现圆柱体两个圆经常会被截断啊
    2022-03-29
  • 卖烧烤夫斯基
    老师是不是隐藏了一些webgl原始的细节。例如缓冲处理,着色器的初始化编译等。
    2021-03-17
收起评论
显示
设置
留言
6
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部