对应《WebGL编程指南》代码:19-ColoredTriangle
要点:【WebGL之巅】17-颜色与纹理-绘制三个不同颜色的顶点 、gl.drawArrays、几何形状的装配和光栅化
知识点
一、几何形状的装配和光栅化
在顶点着色器和片元着色器之间,有这样两个步骤:
图形装配过程 :这一步是将两个孤立的顶点坐标装配成几何图形。几何图形的类比由gl.drawArrays的第一个参数决定
光栅化过程 :将装配好的几何图形转化为片元。
通过上图可以理解,gl_Position实际上是几何图形装配 阶段的输入数据。注意几何图形装配过程又被称为图元装配过程 ,因为被装配出的基本图形(点线面)又被称为图元 。
下图展示了顶点着色器和片元着色器之间图形装配与光栅化的过程 。
总结下来就是:
(1)根据 gl.drawArrays()
的参数n,将执行顶点着色器n 次(执行顶点着色器结果:将坐标传入并存储在装配区)
(2)开始装配图形。使用传入的点坐标,根据 gl.drawArrays()
的第一个参数信息(如:gl.TRANGLES)来决定如何装配。
(3)光栅化:将图形转化为片元(像素 ),片元数目就是这个三角形最终在屏幕上所覆盖的像素数。
二、调用片元着色
一旦光栅化过程结束后,程序就开始逐片调用片元着色器,有多少像素就调用多少次,每次处理一个片元。对于每个片元,片元着色器计算出该片元的颜色并写入颜色缓冲区,直到最后一个片元处理完成,浏览器会显示出最终结果。
为了证明片元着色器对每个片元都执行了一次,实例2 根据片元的位置来确定片元颜色。
三、varying变量的作用和颜色内插过程
顶点着色器的varying变量v_Color在传入片元着色器之前经过了内插过程,所以,片元着色器中的v_Color与顶点着色器中的v_Color实际上并不是一回事。这也正是将这种变量称为“varying”(变化的)变量的原因。
例如:考虑一条两个端点的颜色不同的线段。一个端点为红色,另一个为蓝色。我们在顶点着色器变量中向varying变量v_Color赋上这两个颜色,那么WebGL就会自动地计算出线段上所有的点(片元/像素)的颜色,并赋值给片元着色器中的varying变量v_Color ,如下图所示:
在这个例子中RGBA中的R值从1.0降低到0.0,B值从0.0上升到1.0,线段上所有的片元颜色值都会被恰当地计算出来——这个过程就被称为内插过程 。
实例1
对比【WebGL之巅】17-颜色与纹理-绘制三个不同颜色的顶点 只修改了第52行gl.drawArrays的第一个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 var VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'attribute vec4 a_Color;\n' + 'varying vec4 v_Color;\n' + 'void main() {\n' + 'gl_Position = a_Position;\n' + 'gl_PointSize = 10.0;\n' + 'v_Color = a_Color;\n' + '}\n' ; var FSHADER_SOURCE= 'precision mediump float;\n' + 'varying vec4 v_Color;\n' + 'void main(){\n' + 'gl_FragColor = v_Color;\n' + '}\n' ; function main ( ) { var canvas = document .getElementById("webgl" ); if (!canvas) { console .log("Failed to retrieve the <canvas> element" ); return ; } var gl = getWebGLContext(canvas); if (!gl) { console .log("Failed to get the rendering context for WebGL" ); return ; } if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console .log("Failed to initialize shaders." ); return ; } var n = initVertexBuffers(gl); if (n < 0 ) { console .log('Failed to set the positions of the vertices' ); return ; } gl.clearColor(0.0 , 0.0 , 0.0 , 1.0 ); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0 , n); } function initVertexBuffers (gl ) { var verticesColors = new Float32Array ( [0.0 , 0.5 , 1.0 , 0.0 , 0.0 , -0.5 , -0.5 , 0.0 , 1.0 , 0.0 , 0.5 , -0.5 , 0.0 , 0.0 , 1.0 ] ); var n=3 ; var verteColorBuffer = gl.createBuffer(); if (!verteColorBuffer){ console .log("Failed to create thie buffer object" ); return -1 ; } gl.bindBuffer(gl.ARRAY_BUFFER, verteColorBuffer); gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW); var FSIZE = verticesColors.BYTES_PER_ELEMENT; var a_Position = gl.getAttribLocation(gl.program, 'a_Position' ); if (a_Position < 0 ){ console .log("Failed to get the storage location of a_Position" ); return -1 ; } gl.vertexAttribPointer(a_Position, 2 , gl.FLOAT, false , FSIZE*5 , 0 ); gl.enableVertexAttribArray(a_Position); var a_Color = gl.getAttribLocation(gl.program, 'a_Color' ); if (a_Color < 0 ){ console .log("Failed to get the storage location of a_Position" ); return -1 ; } gl.vertexAttribPointer(a_Color, 3 , gl.FLOAT, false , FSIZE*5 , FSIZE*2 ); gl.enableVertexAttribArray(a_Color); return n; }
效果
实例2
根据片元的位置来确定片元颜色。该程序在【WebGL之巅】07-绘制三角形 基础上修改。
修改代码1:
1 2 3 4 5 6 7 8 9 var FSHADER_SOURCE= 'precision mediump float;\n' + 'uniform float u_Width;\n' + 'uniform float u_Height;\n' + 'void main(){' + 'gl_FragColor = vec4(gl_FragCoord.x/u_Width,0.0,gl_FragCoord.y/u_Height,1.0);\n' + '}' ;
分析:
gl_FragCoord:该内置变量的第一个分量和第二个分量表示片元在canvas坐标系统中的坐标值。
修改代码2:
1 2 3 4 5 var u_Width = gl.getUniformLocation(gl.program, 'u_Width' );var u_Height = gl.getUniformLocation(gl.program, 'u_Height' );gl.uniform1f(u_Width, gl.drawingBufferWidth); gl.uniform1f(u_Height, gl.drawingBufferHeight);
gl.drawingBufferWidth:颜色缓冲区的宽度
gl.drawingBufferHeight:颜色缓冲区的高度
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 var VSHADER_SOURCE = 'attribute vec4 a_Position;' + 'void main(){' + 'gl_Position=a_Position;' + '}' ; var FSHADER_SOURCE= 'precision mediump float;\n' + 'uniform float u_Width;\n' + 'uniform float u_Height;\n' + 'void main(){' + 'gl_FragColor = vec4(gl_FragCoord.x/u_Width,0.0,gl_FragCoord.y/u_Height,1.0);\n' + '}' ; function main ( ) { var canvas = document .getElementById("webgl" ); if (!canvas){ console .log("Failed to retrieve the <canvas> element" ); return ; } var gl = getWebGLContext(canvas); if (!gl){ console .log("Failed to get the rendering context for WebGL" ); return ; } if (!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){ console .log("Failed to initialize shaders." ); return ; } var n = initVertexBuffers(gl); if (n < 0 ) { console .log('Failed to set the positions of the vertices' ); return ; } gl.clearColor(0.0 , 0.0 , 0.0 , 1.0 ); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0 , n); } function initVertexBuffers (gl ) { var vertices = new Float32Array ([ 0.0 , 0.5 , -0.5 , -0.5 , 0.5 , -0.5 ]); var n=3 ; var vertexBuffer = gl.createBuffer(); if (!vertexBuffer){ console .log("Failed to create thie buffer object" ); return -1 ; } gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); var a_Position = gl.getAttribLocation(gl.program, 'a_Position' ); if (a_Position < 0 ){ console .log("Failed to get the storage location of a_Position" ); return -1 ; } gl.vertexAttribPointer(a_Position, 2 , gl.FLOAT, false , 0 , 0 ); var u_Width = gl.getUniformLocation(gl.program, 'u_Width' ); var u_Height = gl.getUniformLocation(gl.program, 'u_Height' ); gl.uniform1f(u_Width, gl.drawingBufferWidth); gl.uniform1f(u_Height, gl.drawingBufferHeight); gl.enableVertexAttribArray(a_Position); return n; }
效果
从左上方到右下方的渐变效果
Tips:
Please indicate the source and original author when reprinting or quoting this article.