欢迎来到我的第二课WebGL教程!这个时间我们来学习怎样向场景里面添加颜色。它是以Nehe的OpenGL教程第三课为基础的。
这儿是这节课的代码在支持WebGL的浏览器运行看起来的效果:
一个小的忠告:这些教程所针对的人群是具有一定的编程知识,但是没有真正的3D图形编程经验;目的是使你入门并且知道这些代码是怎样运行的,以至于你能够尽快开始制作自己的3D网页。如果你还没有学习第一课,在你学习这一课之前最好去学习一下第一课——这里我将只解释这节课与上节课不同的代码。
依然,在这节教程中可能有bugs和错误的地方。如果你指出了一些错误,请在评论里让我知道,我将会尽快更正它。
有两种方法你能够得到这个示例的代码:当你看现场演示的时候,查看源代码或是如果你使用GitHub,你能够复制它(还有以后的教程)从那个代码库。两者选一,一旦你有了代码,加载到你最喜欢的文本编辑器里看一看。
大部分代码和第一课是非常相似的。从头至尾,我们:
定义顶点渲染器和片段渲染器,使用含有"x-shader/x-vertex"和"x-shader/x-fragment"的<script>标签;
通过initGL函数初始化WebGL文本;
使用getShader和initShaders函数将渲染器导入到WebGL program中;
定义模型视图矩阵mvMatrix函数,并通过实用函数调用loadIdentity、multMatrix、mvTranslate函数来操纵它;
定义投影矩阵pMatrix函数,用一个透视实用函数perspective来操纵它;
定义setMatrixUniforms函数来将模型视图和投影矩阵推至JavaScript/WebGL设备上以至于渲染器能够识别;
使用initBuffers函数加载包含场景对象信息的缓冲;
使用drawScene函数绘制场景;
定义函数webGLStart设置好一切;
最后,我们提供要求展示图形的最少的HTML代码。
与第一课代码改变的地方是渲染器、initBuffers函数和drawScene函数。为了解释它们运行的改变,你需要知道一点关于WebGL的渲染管道。这儿是原理图:
这个简易图显示,在drawScene函数中传入JavaScript函数的数据是怎样转变为在屏幕中WebGL canvas里显示的像素的。它只是显示了在这节课中需要解释的步骤;我们将会在以后的教程中关注更加详细的信息。
在最高的层次上,工作过程是这样的:你每一次调用像drawArray这样的函数,WebGL就会处理你之前以属性的形式(像在第一课中设置的顶点缓存)和以一致变量的形式(我们用来组建投影和模型视图矩阵)给它的数据,并且将这些数据传到顶点渲染器。
在这个过程中,为每一个顶点调用顶点渲染器,为每一个顶点设置合适的属性,一致变量也被传入,但是正如它的名字所表示的,一致变量被调用的过程中它们没有改变。顶点渲染器用这些数据来填充图形——在第一课,顶点渲染器使用投影和模型视图矩阵来使得这些顶点都能形成透视的效果,使得这些顶点根据我们的模型视图状态来移动——并且将这些数据转化为易变变量。顶点渲染器能够输出许多种类型的易变变量;有一种特殊的类型是必须输出的,gl_positon,它包含顶点的坐标当渲染器处理完后。
当顶点渲染器完成任务后,WebGL要求将易变变量所代表的3D图像变为2D图像,然后WebGL为图像里的每一个像素调用一次片段渲染器(在3D图形系统里,你也能听到将片段渲染器称为像素渲染器,就是这个原因)。当然,这也意味着在图像里面不含有顶点的像素也会被片段渲染器处理。因此,WebGL在填充这样的像素时采用了一种方法,叫做线性插值——对于组成三角形顶点的位置,这个过程是填充被顶点划定的空间,这样形成了一个可见的三角形。片段渲染器的目的是返回每一个插值点的颜色,并且是在叫gl_FragColor的易变变量中完成的。
一旦片段渲染器完成了这些,它的结果被WebGL处理了(我们将会在以后的课程中讨论)并且它们被导入到帧缓存(frame buffer)里面,帧缓存就是最终在屏幕上显示的东西。
如果顺利的话,到现在为止这节课所教的怎样让顶点获得颜色从JavaScript代码一直到片段渲染器的重要技巧是非常清楚了,尽管现在还没有分析具体的代码。
我们使用的方法是利用这个事实:我们能够在顶点渲染器外面传入一些易变变量,不仅仅是顶点位置,然后再从片段渲染器中取回它们。因此,我们将颜色传入顶点渲染器,然后直接转化为片段渲染器可拾取的易变变量。
很方便,我们可以直接得到颜色的线性变化。顶点渲染器计算顶点之间的片段时,所有的易变变量按线性插值的方法计算,不仅仅是位置。两点之间的颜色线性插值是一个平滑的变化效果,就像你看到的上面那张图片里的三角形的效果。
让我们来看看代码;我们来看看与第一课不同的地方。首先,是顶点渲染器。它改变了很多,这儿是新代码:
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
这些代码的意思是说我们有两个属性——不同顶点的输入值——分别叫做aVertexPosition和aVertexColor,有两个一致变量叫做uMVMatrix和uPMatrix,还有一个以易变变量的形式的输出值叫做vColor。
在渲染器的主体部分,我们计算gl_Position(被定义为每一个顶点渲染器的易变变量)实际上和第一课的方法相同,我们所做的是将颜色从输入的属性值转化为输出的易变变量。
一旦每一个顶点都被这样运行出来,插值用来运算之间的片段,这些都被传入到片段渲染器:
#ifdef GL_ES
precision highp float;
#endif
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
这里,在设置浮点精确度的模板代码之后,我们获取包含经过线性插值运算后的平滑混合颜色数据的易变变量vColor。
这是这节课与上节课在渲染器里所有的不同。还有两个其它的不同。第一个非常小;在initShaders函数中我们获得两个属性的参数而不是一个;额外的一行代码用红色标记着:
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
这个获得属性的代码,在上一课中在某种程度上我已经解释过,现在应该是十分清楚了:这是我们获得想要传入顶点渲染器为每个顶点设置属性的参数的办法。在第一课,我们只是获得顶点位置属性。现在,足够明显,我们也得到了颜色属性。
这一课剩下的改变是initBuffers函数,现在需要为顶点位置和顶点颜色设置缓存了,还有drawScene函数,需要把它们两个都传入WebGL。
首先来看看initBuffers函数,我们定义新的全局变量来为三角形和四边形存储颜色缓存:
var triangleVertexPositionBuffer;
var triangleVertexColorBuffer;
var squareVertexPositionBuffer;
var squareVertexColorBuffer;
然后,我们创建三角形顶点位置缓存之后,我们指明它的顶点颜色:
function initBuffers() {
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
triangleVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
var colors = [
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
triangleVertexColorBuffer.itemSize = 4;
triangleVertexColorBuffer.numItems = 3;
我们提供的颜色数据是一个数列,每一个值对应一个点,就像位置。然而,在这两个数组缓存中有一个有趣的不同:一个顶点的位置可以被三个数指明,X、Y和Z坐标,而每个顶点的颜色被四个元素所指明——红、绿、蓝和alpha值。Alpha,如果你对它不熟悉,是不透明度的一个度量值(0是透明的,1完全不透明),在后面的教程中是非常有用的。缓存中每项元素的改变导致需要改变相应的itemSize。
下一步,我们为四边形写同样的代码;此时,我们给每一面设置相同的颜色,所以我们用循环来生成缓存数据:
squareVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
squareVertexPositionBuffer.itemSize = 3;
squareVertexPositionBuffer.numItems = 4;
squareVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
colors = []
for (var i=0; i < 4; i++) {
colors = colors.concat([0.5, 0.5, 1.0, 1.0]);
}
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
squareVertexColorBuffer.itemSize = 4;
squareVertexColorBuffer.numItems = 4;
现在我们有了图形的所有的数据在四个缓存中,下一个不同的地方是使得drawScene函数使用新的数据。新的代码仍然用红色标识,应该很容易理解:
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
loadIdentity();
mvTranslate([-1.5, 0.0, -7.0])
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
mvTranslate([3.0, 0.0, 0.0])
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
}
下一个不同的地方……等一下,没有下一个不同的地方!这就是在我们的WebGL场景里添加颜色所必须有的,如果顺利的话,你现在轻松的掌握了渲染器的基础知识和它们之间数据的传输方法。
这就是这一课所有的内容——它比上一课要容易!如果你有任何的问题,评论,或者改正,请给我留言。
下一课,我们将在屏幕中添加点运动,旋转三角形和四边形。
- 大小: 48.1 KB
- 大小: 40.2 KB
分享到:
相关推荐
这个“webgl教程DEMO”很可能是为了教授和展示如何利用WebGL技术来创建交互式的网页图形。WebGL允许开发者在浏览器环境中无需插件就能直接绘制复杂的3D场景,极大地拓展了网页应用的视觉表现力。 在WebGL中,开发者...
2. **着色器(Shaders)**:WebGL使用两种类型的着色器——顶点着色器和片段着色器。顶点着色器处理几何形状的顶点,片段着色器则决定像素颜色。 3. **缓冲区(Buffers)**:用于存储顶点数据,如位置、颜色和纹理...
WebGL是一种基于OpenGL标准的JavaScript API,用于在...这个离线WebGL教程应该涵盖了这些基础知识,以及更深入的技术,例如纹理映射、动画制作、碰撞检测等,帮助初学者逐步掌握WebGL编程,创建令人惊叹的3D Web体验。
在Three.js实战教程中,你可能会学到如何创建一个基本的3D场景,包括设置相机、添加几何体、应用材质、配置光源、设置渲染循环以及动画制作等步骤。此外,可能还会涉及纹理映射、碰撞检测、物理引擎集成、用户交互等...
- MDN Web Docs提供了详细的WebGL教程和API参考。 - Three.js和 Babylon.js 是两个流行的WebGL库,简化了WebGL的使用,适合初学者快速入门。 6. **实践项目**: “WebGL-Basis-master”可能包含一个简单的WebGL...
一个简单的WebGL实例可能涉及创建一个立方体并为其添加颜色和纹理。这需要定义立方体的顶点坐标、颜色和纹理坐标,编写着色器代码,设置缓冲区,加载纹理,然后在渲染循环中绘制立方体。 #### 结论 WebGL为网页开发...
WebGL开发教程还提到了一系列的学习课程,包括如何绘制一个三角形和一个正方形、如何添加颜色、如何给物体添加运动以及如何创建一些真实的三维物体。这些课程内容涵盖了WebGL的基本概念、API使用、场景设置、光照...
【标题】"编码WebGL教程成绩单"涉及到的是利用Three.js库进行WebGL编程的学习与实践。WebGL是一种在浏览器环境中渲染3D图形的标准技术,它允许开发者直接在网页上创建交互式的三维场景。Three.js是这个领域的一个...
2. **着色器(Shaders)**:WebGL 使用 GLSL(OpenGL Shading Language)编写的着色器程序,包括顶点着色器(处理几何数据)和片段着色器(决定像素颜色)。 3. **顶点(Vertex)**:定义图形形状的基本元素,顶点着色...
4. **纹理映射**:为3D物体添加颜色和细节,通过纹理坐标将图像贴合到模型表面。 5. **深度测试**:处理3D物体的遮挡关系,确保正确的渲染顺序。 五、TypeScript与WebGL的结合 TypeScript可以为WebGL提供更高级别的...
2. **编写顶点着色器和片段着色器**:这是WebGL的核心部分,负责在GPU上处理图形数据。顶点着色器处理每个顶点,片段着色器处理像素颜色。 3. **发送顶点数据**:定义3D形状的几何信息,如顶点坐标,然后将其上传到...
2. **着色器语言(GLSL)**:GLSL是OpenGL Shading Language的缩写,是编写WebGL着色器所使用的语言。着色器分为顶点着色器和片段着色器,分别处理顶点坐标变换和像素颜色。学习者需要了解如何编写这两种着色器,并...
2. **WebGL API**: - **缓冲区(Buffers)**: 用于存储顶点、颜色、纹理坐标等数据。 - **纹理(Textures)**: 用于为3D模型添加细节,如图片或视频。 - **矩阵运算**: 平移、旋转、缩放等变换,用于定位和操作...
6. **纹理(Textures)**:用于给3D模型添加细节,如颜色、纹理图案等。 7. **缓冲区(Buffers)**:用于存储顶点、颜色、法线等数据,便于GPU高效处理。 8. **状态机(State Machine)**:WebGL有一系列的状态,...
这很可能是教程中的第四课,它可能涵盖了WebGL的基本使用方法,包括如何初始化WebGL上下文、设置视口、加载着色器、创建几何形状、以及处理颜色和光照等基本概念。通过这个文件,学习者可以逐步了解如何构建一个简单...
- [Mozilla Developer Network WebGL教程](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial) - [WebGL Fundamentals](https://webglfundamentals.org/) 通过以上的介绍,我们可以看出WebGL是...
WebGL编程指南源码是针对WebGL技术的一本详尽教程,旨在帮助开发者掌握在Web浏览器中实现交互式三维图形编程的技术。WebGL是一种基于OpenGL标准的JavaScript API,它允许在任何兼容HTML5的浏览器中进行硬件加速的3D...
这个“WebGL实战学习代码”压缩包很可能是包含了一系列教程或者示例代码,帮助学习者深入理解和实践WebGL技术。 WebGL基于OpenGL ES 2.0标准,通过JavaScript与HTML5 Canvas元素结合,让开发者能够在网页上直接绘制...
在"HTML5 WebGL入门学习资料(整套)"中,你将找到一系列从基础到进阶的WebGL教程,名为WebGL_Lessons_01_to_16。这些课程可能会涵盖以下关键知识点: 1. **基础概念**:首先,你会了解到WebGL的基本工作原理,包括...