欢迎来到WebGL教学系列的第四课。这次我们来显示一些3D物体。本课是基于NeHe OpenGL教学系列的第五课。
如果你的浏览器已经支持WebGL,请点击此处,你将看到本课WebGL的现场版;如果不支持,你从此处可以获取一个支持WebGL的浏览器。
本课代码与前一课代码的不同之处完全集中于initBuffers和drawScene这两个函数。如果你现在滚动到drawScene函数,你将在第一行的地方看到细微的改变:保留场景中两个物体当前旋转状态的变量被更名了,它们以前是rTri和 rSquare,现在是:
var rPyramid = 0;
var rCube = 0;
设置好代码之后,我们来看看如何绘制锥体。就像在前面的课程里对三角形所做的那样,我们让它围绕Y轴旋转:
mvRotate(rPyramid, [0, 1, 0]);
然后绘制它。在上一课里,绘制彩色三角形的代码与绘制同样漂亮的锥体的新代码之间的唯一区别在于后者有更为丰富的矢量和颜色,这一切将在 initbuffers函数(我们稍后将看到)中进行处理。这就意味着除了缓冲区名字不同之外,代码是完全相同的。
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pyramidVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, pyramidVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, pyramidVertexPositionBuffer.numItems);
很简单吧。现在让我们来看看关于立方体的代码。第一步先旋转它,这一次和仅仅绕x轴旋转不同,我们将绕一个(从观察者的角度看)向上、向右并朝向你的轴上旋转立方体:
mvRotate(rCube, [1, 1, 1]);
下一步绘制立方体。这里涉及的东西多一些,我们有三种方法来绘制一个立方体:
1. 使用一个单一的三角形带。如果整个立方体都是同一种颜色,这将相当容易——我们利用一直使用的顶点位置来绘制立方体的一个面,接着添加另外两个点绘制另一个面,然后再添加两个点绘制第三个面,以此类推。这非常有效。不幸的是,我们想要立方体的每个面有不同的颜色。因为每个顶点指定了立方体的一个内角,同时每个内角又被三个面所共有,我们需要指定每个顶点三次。这样做如此复杂,以至于我甚至不想试图去解释它……
2. 我们可以通过绘制六个独自的正方形来绘制立方体,它们中的每个面包含各自的顶点位置和颜色集合。本课的第一个版本就是这样做的,而且它运行得很好。然而,这并非最佳的实现方式,因为每次在你的场景中指示WebGL绘制另一个对象时会耗费大量的时间。如果能较少地去调用drawArrays函数的话,那它将是比较好的方法。
3. 最后的选择是将立方体指定为六个正方形,每一个正方形由两个三角形构成,不过要将所有这些图形送给WebGL让它一次绘制完成。这和我们处理三角形带的方法有点相似,但是由于现在我们每次都完整地定义三角形,而不是像以前那样简单地通过在前一个三角形上添加一个单独的点来定义一个三角形,因此很容易指定每条边的颜色。它还有一个好处就是编码方式最为干净优美。让我来介绍一个新函数drawElements——它就是我们要去实现的方法:-)首先,我们将包含立方体顶点位置的缓冲区和在initBuffers函数中用合适的属性产生的颜色缓冲区关联起来,这就像我们处理锥体那样:
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, cubeVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
接着我们绘制三角形。这里有点小问题。我们考虑一下立方体的正面;我们现在有正面的四个顶点位置,同时它们每一个都有一个与之相关的颜色。然而,它需要使用两个三角形来绘制。由于我们现在使用的是各自指定自身顶点的简单三角形,而不是共享顶点的三角形带,所以我们不得不为此总共指定六个顶点。但问题是我们只能从缓冲区中为它提供四个。
我们所需要做的是指定如下方法:“绘制一个由缓冲区数组中前三个顶点缓冲区构成的三角形,接着绘制另一个由数组中第一个、第三个和第四个顶点缓冲区构成的三角形”。这样我们就能绘制出立方体的正面;然后我们使用类似的方法来绘制余下的部分。这就是我们要做的。
在这里,我们使用“元素缓冲区数组”和一个新函数drawElements。就像我们一直使用的缓冲区数组那样,元素缓冲区数组将在 initBuffers函数中填充相应的值,同时使用基于零点索引顶点位置和颜色的数组方法来保留一份顶点集合的列表(稍后我们会看到)。
我们利用立方体的元素数组保存当前的缓冲区(WebGL可以保留不同的缓冲区数组和元素缓冲区数组,因此我们在调用gl.bindBuffer时必须指定我们需要绑定哪一个缓冲区),接着我们将模型视图矩阵传到图形卡上,最后调用drawElements函数绘制三角形。
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
这就是drawScene函数。余下的代码都在initBuffers函数中,浅显易懂。我们用新名字来定义缓冲区以反映正在处理新的一类物体,同时我们为立方体的顶点索引缓冲区新增一项:
var pyramidVertexPositionBuffer;
var pyramidVertexColorBuffer;
var cubeVertexPositionBuffer;
var cubeVertexColorBuffer;
var cubeVertexIndexBuffer;
我们对锥体所有正面的顶点位置缓冲区填充数值,同时 numItems有相应的变化:
pyramidVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
var vertices = [ // Front face 0.0, 1.0, 0.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, // Right face 0.0, 1.0, 0.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, // Back face 0.0, 1.0, 0.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, // Left face 0.0, 1.0, 0.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0 ];
gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertices), gl.STATIC_DRAW);
pyramidVertexPositionBuffer.itemSize = 3;
pyramidVertexPositionBuffer.numItems = 12;…
锥体的顶点颜色缓冲区也如此:
pyramidVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
var colors = [
// Front face
1.0, 0.0, 0.0, 1.0,
0.0,1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
// Right face
1.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 0.0, 1.0,
// Back face
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
// Left face
1.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 0.0, 1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(colors), gl.STATIC_DRAW);
pyramidVertexColorBuffer.itemSize = 4;
pyramidVertexColorBuffer.numItems = 12;…
对于立方体的顶点位置缓冲区的处理如下:
cubeVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertices), gl.STATIC_DRAW);
cubeVertexPositionBuffer.itemSize = 3;
cubeVertexPositionBuffer.numItems = 24;
颜色缓冲区稍微复杂些,因为我们使用一个循环来产生一个顶点颜色的列表,所以我们不得不指定每种颜色四次,每个顶点一次。
cubeVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
var colors = [
[1.0, 0.0, 0.0, 1.0],
// Front face
[1.0, 1.0, 0.0, 1.0],
// Back face
[0.0, 1.0, 0.0, 1.0],
// Top face
[1.0, 0.5, 0.5, 1.0],
// Bottom face
[1.0, 0.0, 1.0, 1.0],
// Right face
[0.0, 0.0, 1.0, 1.0],
// Left face
];
var unpackedColors = [] for (var i in colors)
{
var color = colors[i];
for (var j=0; j < 4; j++) {
unpackedColors = unpackedColors.concat(color); } }
gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(unpackedColors), gl.STATIC_DRAW);
cubeVertexColorBuffer.itemSize = 4;
cubeVertexColorBuffer.numItems = 24;
最后,我们定义元素缓冲区数组(提示:gl.bindBuffer和gl.bufferData函数的第一个参数是不同的):
cubeVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
var cubeVertexIndices = [
0, 1, 2,
0, 2, 3,
// Front face
4, 5, 6,
4, 6, 7,
// Back face
8, 9, 10,
8, 10, 11,
// Top face
12, 13, 14,
12, 14, 15,
// Bottom face
16, 17, 18,
16, 18, 19,
// Right face
20, 21, 22,
20, 22, 23
// Left face
]
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(cubeVertexIndices), gl.STATIC_DRAW);
cubeVertexIndexBuffer.itemSize = 1;
cubeVertexIndexBuffer.numItems = 36;
记住,在这个缓冲区中的每个数字是顶点位置和颜色缓冲区的一个索引。因此,结合drawScene函数绘制三角形的指令,第一行代码意味着我们利用顶点0,1和2获得一个三角形。接着利用顶点 0,2和3获得另一个三角形。由于两个三角形颜色相同且相邻,于是利用顶点0,1,2和3就可以获得一个正方形。重复这样的操作就可以获得立方体的所有面,最后立方体也就绘制好了!
- 大小: 2.6 KB
分享到:
相关推荐
超图三维地图开发结合WebGL和Cesium技术,为用户提供了一种高效且直观的方式来展示地理空间数据。WebGL是一种在浏览器中实现3D图形的JavaScript API,它基于OpenGL标准,无需插件即可在任何支持的现代浏览器上运行。...
WebGL 是一种基于 OpenGL ES 的 JavaScript API,用于在任何兼容的 Web 浏览器中进行三维图形渲染。它使得开发者可以在网页上实现交互式的3D图形,无需借助插件。这个"webgl-guide"教程是为想要学习和掌握 WebGL 的...
它基于OpenGL ES 2.0标准,并且是HTML5 Canvas的一部分,使得开发者可以在网页上直接创建引人入胜的三维视觉体验。 在"webgl教程DEMO"中,我们可以深入学习WebGL的基础概念和技术,通过实践DEMO来理解其工作原理。...
随着信息时代的不断地发展和完善,对于地理信息服务、GIS技术、VR、可视化技术等技术的要求越来越高,特别是三维空间数据的真实性要求越来越苛刻,导致传统的二维GIS技术不能满足第三维方向上的集合位置信息、空间...
这个技术允许开发者在浏览器环境下创建交互式的三维场景,无需任何插件。"WEBGL教程.pdf"很可能是详细解释如何使用WebGL的文档。 在开始学习WebGL之前,首要任务是确保你的浏览器支持WebGL。由于它还不是所有浏览器...
WebGL是一种基于OpenGL标准的JavaScript API,用于在任何兼容的Web浏览器中进行三维图形渲染,无需插件。它使得开发者可以在网页上实现交互式的3D图形,极大地拓展了Web应用的可能性。而Three.js是建立在WebGL基础上...
WebGL是一种基于OpenGL标准的JavaScript API,用于在任何兼容的Web浏览器中进行三维图形渲染,无需插件。它是HTML5技术的重要组成部分,特别是在构建交互式、动态和视觉丰富的Web应用程序时。这个“webgl图文教程”...
WebGL开发教程还提到了一系列的学习课程,包括如何绘制一个三角形和一个正方形、如何添加颜色、如何给物体添加运动以及如何创建一些真实的三维物体。这些课程内容涵盖了WebGL的基本概念、API使用、场景设置、光照...
WebGL是一种可以在浏览器中实现三维效果的规范,而WebGL教程就是指导人们如何利用WebGL技术创建三维动画效果的方法。Three.js是基于WebGL的一个开源JavaScript库,它使得开发者能够用更简单的语法,以JavaScript编写...
WebGL是一种在浏览器环境中渲染3D图形的标准技术,它允许开发者直接在网页上创建交互式的三维场景。Three.js是这个领域的一个流行库,它为WebGL提供了一套易于使用的API,降低了开发者的入门难度。 【描述】"教程-...
2. **几何与坐标系**:讲解三维空间中的坐标系、向量和矩阵运算,这些都是WebGL中的核心概念。 3. **颜色和光照**:如何使用色彩和光照模型来创建逼真的3D效果。 4. **纹理映射**:如何应用图像到3D模型表面,以...
本教程将带你了解如何使用VRML来制作三维网页,让你的网站脱颖而出,增添更多互动性和趣味性。 **1. VRML基本概念** VRML是一种基于文本的、用于描述3D物体和场景的语言,它基于SGI公司于1994年提出的开放标准。...
在Web开发领域,WebGL是一种JavaScript API,用于在任何兼容的Web浏览器中进行三维图形渲染,无需插件。它利用了OpenGL的底层图形接口,使得开发者能够创建复杂的3D场景并直接在网页上展示。本项目主要探讨如何使用...
- **WebGL**是一种新兴的标准技术,用于在Web浏览器中进行三维(3D)图形渲染,并且它是HTML5家族技术的一部分。 - WebGL不需要任何插件支持,它直接在网页中运行,为开发人员提供了强大的3D图形处理能力。 - 本书...
WebGL 是一种基于 OpenGL ES 2.0 的 JavaScript API,用于在任何兼容的 Web 浏览器中实现交互式三维图形。它无需插件,直接嵌入到 HTML5 页面中,为网页带来了强大的3D图形渲染能力。"webgl-presentation" 是一个...
WebGL是一种在网页上实现3D图形编程的技术,它基于OpenGL标准,并且通过JavaScript与HTML5的Canvas元素结合,使得浏览器可以直接渲染复杂的三维图形。"awesome-webgl"是一个专门收集和整理WebGL相关库、资源和教程的...
WebGL是一种基于OpenGL标准的JavaScript API,用于在任何兼容的Web浏览器中实现三维图形渲染。它使得网页开发者能够在不依赖插件的情况下,在网页上展示复杂的3D图形和交互式内容。"WebGl中文标准原代码注释解析"是...
通过JavaScript,我们可以向WebGL上下文发送指令,这些指令包括设置颜色、形状、光照、纹理等,构建出复杂的三维场景。 1. **基础概念**: - **画布元素(Canvas)**: 在HTML中,`<canvas>`元素是WebGL的画布,...
这个压缩包文件"JAVA3D的网络三维技术的设计与实现.zip"很可能包含了一套详细的教程或者研究文档,探讨了如何利用Java3D来设计和实现网络上的三维应用程序。 在Java3D中,开发者可以使用类似于OpenGL或Direct3D的...
在本项目中,我们将深入探讨如何使用JavaScript来创建一个三维地球模型,并模拟卫星在其轨道上的运动。这个初学者级别的教程将引导你理解基本的WebGL技术、物理学中的天体运动规律以及JavaScript编程技巧。 首先,...