准备工作已经做完,下面开始渲染
javascript
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0.5, 0.7, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
设置视口
- gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
- 设置Webgl的视口。视口定义了渲染输出在画布区域上的矩形区域,这里设置了整个canvas区域作为视口,canvas是以左上角为原点坐标(0,0)
- canvas画布坐标系,辅助理解
设置清除颜色并清除缓冲区
- gl.clearColor(0.5, 0.7, 1.0, 1.0);
- 设置清除颜色,四个参数分别代表红、绿、蓝和透明度通道的值。
- 清除颜色之后,画布的颜色
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
- 设置清除颜色缓冲区和深度缓冲区
- COLOR_BUFFER_BIT表示颜色缓冲区
- DEPTH_BUFFER_BIT表示深度缓冲区
- 清除缓冲区是为了确保每一帧在渲染之前,缓冲区的内容都是初始状态,避免上一帧的渲染结果对当前帧产生影响。
启用深度测试和背面剔除
- gl.enable(gl.DEPTH_TEST);
- 启用深度测试。深度测试用于确定场景中哪些片段应该被绘制在前面,哪些应该被遮挡。可以简单理解css中的z-index;
- gl.enable(gl.CULL_FACE);
- 启用背面剔除。在3D图形中,一个物体通常是由多个三角形组成,每个三角形有正面以及背面。背面剔除可以提高渲染性能,因为对于不透明物体,通常只需要绘制正面即可,通过背面剔除,减少需要处理的片段数量
- 正面:在视角下,如果一个面是通过逆时针顺序定义的顶点绘制的,则被认为是正面
- 背面:在视角下,如果一个面是通过顺时针顺序定义的顶点绘制的,则被认为是背面
- gl.frontFace(gl.CCW),设置逆时针为正面(默认)
- gl.frontFace(gl.CW), 设置顺时针为正面
javascript
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(
positionLoc, // location
3, // size (components per iteration)
gl.FLOAT, // type of to get from buffer
false, // normalize
0, // stride (bytes to advance each iteration)
0, // offset (bytes from start of buffer)
);
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.enableVertexAttribArray(normalLoc);
gl.vertexAttribPointer(
normalLoc, // location
3, // size (components per iteration)
gl.FLOAT, // type of to get from buffer
false, // normalize
0, // stride (bytes to advance each iteration)
0, // offset (bytes from start of buffer)
);
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.enableVertexAttribArray(texcoordLoc);
gl.vertexAttribPointer(
texcoordLoc, // location
2, // size (components per iteration)
gl.FLOAT, // type of to get from buffer
false, // normalize
0, // stride (bytes to advance each iteration)
0, // offset (bytes from start of buffer)
);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.useProgram(prg);
设置顶点数据
- gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
- 将之前创建的存储顶点位置数据的缓冲区(positionBuffer)绑定到ARRAY_BUFFER目标上,以便后续对这个缓冲区进行操作
- gl.enableVertexAttribArray(positionLoc)
- 启用顶点属性数组,通过gl.getAttribLocaton(prg,'position')获取到的位置属性。使得在顶点着色器中可以访问这个属性。
- gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
- positionLoc是属性的位置。
- 3表示每个顶点的位置由三个分量(X,Y,Z坐标)组成(如果画二维图形,一个顶点只需要2个坐标,不需要Z坐标)
- gl.Float表示从缓冲区读取到的数据类型是浮点数
- false表示不归一化处理
- 0表示步长为0,即连续存储,没有间隔
- 0表示偏移量为0,从缓冲区的起始位置开始读取
设置顶点法线数据
- 绑定法线数据缓冲区。
- 启用顶点属性数组(针对法线属性)。
- 使用
gl.vertexAttribPointer
设置法线属性的参数,同样每个法线由三个分量组成
设置顶点纹理坐标数据
- 绑定纹理坐标数据缓冲区。
- 启用顶点属性数组(针对纹理坐标属性)。
- 使用
gl.vertexAttribPointer
设置纹理坐标属性的参数,这里每个纹理坐标由两个分量(U、V)组成。所以是2
绑定索引缓冲区
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
- 将存储顶点索引数据的缓冲区(indexBuffer)绑定到ELEMENT_ARRAY_BUFFER目标上,用于在绘制时指定哪些顶点来构建三角形。
使用着色器程序
- gl.useProgram(prg)
- 使用之前创建并链接好的着色器程序prg,使得后续渲染操作将使用这个程序进行顶点和片段进行处理