- 书名:WebGL Programming Guide
- 语言:English
- 作者:Kouichi Matsuda、Rodger Lea
- 版本:1th Edition
- OS: Mac Catalina 10.15.4
- Hardware: Intel Core i9/16G 2667MHz DDR4
- 编译器版本:vscode
- 浏览器:Chrome
Chapter 1 WebGL简述
相识WebGL起源,如下图:
相识WebGL架构方式,如下图:
Chapter 2 WebGL的第一步
Example 1 使用<canvas>构建图形
DrawRectangle.html 如下:
- <!DOCTYPE html>
- <html lang="eng">
- <head>
- <meta charset="utf-8"/>
- <title>
- Draw a blue rectangle (canvas version)
- </title>
- </head>
- <body onload="main()">
- <canvas id = "example" width="400" height="400">
- Please use a browser that supports "canvas"
- </canvas>
- <script src="DrawRectangle.js">
- </script>
- </body>
- </html>
复制代码 DrawRectangle.js 如下:
- // DrawRectangle.js
- function main() {
- // Rectriee <canvas> element
- var canvas = document.getElementById("example");
- if (!canvas) {
- console.log("Failed to retrieve the <canvas> element");
- return;
- }
- // Get the rendering context for 2DCG
- var ctx = canvas.getContext("2d");
- // Draw a blue rectangle
- ctx.fillStyle = 'rgba(0, 0, 255, 1.0)'; // Set a blue color
- ctx.fillRect(120, 10, 150, 150); // Fill a rectangle with the color
- }
复制代码 运行结果如下图:
注意:
- 这是一个使用<canvas>的例子
- 坐标左上角为(0,0),x轴往右为正,y轴往下为正,如下图:
Example 2 WebGL Program: Clear Drawing Area
HelloCanvas.html 如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8"/>
- <title> Clear canvas </title>
- </head>
- <body onload="main()">
- <canvas id = "webgl" width="400" height="400">
- Please use the browser supporting "canvas"
- </canvas>
-
- <script src="../../lib/webgl-utils.js"></script>
- <script src="../../lib/webgl-debug.js"></script>
- <script src="../../lib/cuon-utils.js"></script>
- <script src="HelloCanvas.js"></script>
- </body>
- </html>
复制代码 HelloCanvas.js 如下:
- // HelloCanvas.js
- function main() {
- // Retrieve <canvas> element
- var canvas = document.getElementById("webgl");
- // Get the rendering context for WebGL
- var gl = getWebGLContext(canvas);
- if(!gl) {
- console.log('Failed to get the rendering context for WebGL');
- return;
- }
- // Spectify the color for clearing <canvas>
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
- // Clear <canvas>
- gl.clear(gl.COLOR_BUFFER_BIT);
- }
复制代码 步伐输出结果:
注意:
- 步伐调用了webgl库文件
- main()处置处罚流程如下图:
Example 3 绘制点(版本1)
HelloPoint1.html 如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8"/>
- <title>Draw a point (1)</title>
- </head>
- <body onload="main()">
- <canvas id = "webgl" width="400" height="400">
- Please use the browser supporting "canvas".
- </canvas>
- <script src="../../lib/webgl-utils.js"></script>
- <script src="../../lib/webgl-debug.js"></script>
- <script src="../../lib/cuon-utils.js"></script>
- <script src="HelloPoint1.js"></script>
- </body>
- </html>
复制代码 HelloPoint1.js 如下:
- // HelloPoint1.js
- // Vertex shader program
- var VSHADER_SOURCE =
- ' void main() {\n' +
- ' gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n' + // Coordinates
- ' gl_PointSize = 10.0;\n' + // Set the point size
- ' }\n';
- // Frame shader program
- var FSHADER_SOURCE =
- 'void main() {\n' +
- ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color
- '}\n';
- function main() {
- // Retrieve <canvas> element
- var canvas = document.getElementById("webgl");
- // Get the rendering context for WebGL
- var gl = getWebGLContext(canvas, true);
- if(!gl) {
- console.log('Failed to get the rendering context for WebGL');
- return;
- }
- // Initialize shaders
- if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
- console.log('Failed to initialize shaders.');
- return;
- }
- // Spectify the color for clearing <canvas>
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
- // Clear <canvas>
- gl.clear(gl.COLOR_BUFFER_BIT);
- // Draw a point
- gl.drawArrays(gl.POINTS, 0, 1);
- }
复制代码 步伐运行结果:
在Safari浏览器会报INVALID_OPERATION错误,但是在Chrome浏览器运行正常,原因暂时不明,如下图所示:有知道原因的大侠烦请留言告知,谢谢。
JavaScript步伐显示处置处罚流程
WebGL步伐处置处罚流程
着色器的一样寻常性处置处罚流程
WebGL坐标体系
右手坐标系 ,手指所指的方向为正向
<canvas>绘制区域与WebGL坐标体系,注意:<canvas>左上角为原点,使用int标示坐标位置。而WebGL默认原点在中心,且使用float范例标示坐标位置。
Example 4 绘制点(版本2)
两种差别的顶点变量范例: attribute variable和uniform variable
attirbute variable 定义的格式:
属性变量赋值过程:

示例代码:
- // HelloPoint2.js
- // Vertex shader program
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' +
- ' gl_PointSize = 10.0;\n' +
- '}\n';
- // Frame shader program
- var FSHADER_SOURCE =
- 'void main() {\n' +
- ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color
- '}\n';
- function main() {
- // Retrieve <canvas> element
- var canvas = document.getElementById("webgl");
- // Get the rendering context for WebGL
- var gl = getWebGLContext(canvas, true);
- if (!gl) {
- console.log('Failed to get the rendering context for WebGL');
- return;
- }
- // Initialize shaders
- if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
- console.log('Failed to initialize shaders.');
- return;
- }
- // Get the storage location of attribute variable
- 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;
- }
- // Pass vertext position to attribute variable
- gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
- // Spectify the color for clearing <canvas>
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
- // Clear <canvas>
- gl.clear(gl.COLOR_BUFFER_BIT);
- // Draw a point
- gl.drawArrays(gl.POINTS, 0, 1);
- }
复制代码 html文件与HelloPoint1格式基本相同,除了javascript的文件名不一致。如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8"/>
- <title>Draw a point (1)</title>
- </head>
- <body onload="main()">
- <canvas id = "webgl" width="400" height="400">
- Please use the browser supporting "canvas".
- </canvas>
- <script src="../../lib/webgl-utils.js"></script>
- <script src="../../lib/webgl-debug.js"></script>
- <script src="../../lib/cuon-utils.js"></script>
- <script src="HelloPoint2.js"></script>
- </body>
- </html>
复制代码 步伐运行效果:
gl.vertexAttribute3f()映射齐次坐标
gl.vertexAttribute3f()映射齐次坐标时第4个参数默认为1.0,如下图:
WebGL函数命名规则
Example 5 使用鼠标点击来绘制点
HTML代码如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8"/>
- <title>Draw a point (1)</title>
- </head>
- <body onload="main()">
- <canvas id = "webgl" width="400" height="400">
- Please use the browser supporting "canvas".
- </canvas>
- <script src="../../lib/webgl-utils.js"></script>
- <script src="../../lib/webgl-debug.js"></script>
- <script src="../../lib/cuon-utils.js"></script>
- <script src="ClickedPoints.js"></script>
- </body>
- </html>
复制代码 JAVA Script代码如下:
- // ClickedPoints.js
- // Vertex shader program
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'attribute float a_PointSize;\n' +
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' +
- ' gl_PointSize = a_PointSize;\n' +
- '}\n';
- // Frame shader program
- var FSHADER_SOURCE =
- 'void main() {\n' +
- ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color
- '}\n';
- function main() {
- // Retrieve <canvas> element
- var canvas = document.getElementById("webgl");
- // Get the rendering context for WebGL
- var gl = getWebGLContext(canvas, true);
- if (!gl) {
- console.log('Failed to get the rendering context for WebGL');
- return;
- }
- // Initialize shaders
- if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
- console.log('Failed to initialize shaders.');
- return;
- }
- // Get the storage location of attribute variable
- 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;
- }
- var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
- // Pass vertext position to attribute variable
- gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
- gl.vertexAttrib1f(a_PointSize, 10.0);
- // Register function (event handler) to be called on a mouse press
- canvas.onmousedown = function(ev) {
- click(ev, gl, canvas, a_Position);
- };
- // Spectify the color for clearing <canvas>
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
- // Clear <canvas>
- gl.clear(gl.COLOR_BUFFER_BIT);
- }
- var g_points = []; // The array for a mouse press
- function click(ev, gl, canvas, a_Position) {
- var x = ev.clientX; // x coordinate of a mouse pointer
- var y = ev.clientY; // y coordinate of a mouse pointer
- var rect = ev.target.getBoundingClientRect();
- x = ((x - rect.left) - canvas.height / 2) / (canvas.height / 2);
- y = (canvas.width / 2 - (y - rect.top)) / (canvas.width / 2);
- // Store the coordinates to g_points array
- g_points.push(x);
- g_points.push(y);
- // Clear <canvas>
- gl.clear(gl.COLOR_BUFFER_BIT);
- var len = g_points.length;
- for(var i = 0; i < len; i += 2) {
- // Pass the position of a point to a_Position variable
- gl.vertexAttrib3f(a_Position, g_points[i], g_points[i+1], 0.0);
- // Draw a point
- gl.drawArrays(gl.POINTS, 0, 1);
- }
- }
复制代码 步伐执行如下图:

注册变乱处置处罚
<canvas>鼠标点击变乱(包括左键、右键、中键)
canvas.onmousedown = function(ev) { click(ev, gl, canvas, a_Position); };
上例同样也是一个匿名函数,如许的写法可以使变乱调用main()里声明的变量,并通过参数转达的方式转达给click函数
浏览器点击变乱的坐标体系
WebGL坐标体系与<canvas>坐标体系的区别
坐标转换关系见下图:
Example 6 改变点击点的颜色
在4个象限中定义差别的颜色,第二和第四象限使用白色,第一象限使用红色,第三象限使用绿色。
使用了片段着色器同一变量(uniform variable)传送点颜色值,当鼠标点击差别象限范围,将对应的颜色指发送给绑定的片段着色器变量。
- // ColoredPoints.js
- // Vertex shader program
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' + // Coordinates
- ' gl_PointSize = 10.0;\n' + // Set the point size
- '}\n';
- // Fragment shader program
- var FSHADER_SOURCE =
- 'precision mediump float;\n' +
- 'uniform vec4 u_FragColor;\n' + // uniform variable
- 'void main() {\n' +
- ' gl_FragColor = u_FragColor;\n' + // Set the color
- '}\n';
- function main() {
- // Retrieve <canvas> element
- var canvas = document.getElementById('webgl');
- // Get the rendering context for WebGL
- var gl = getWebGLContext(canvas);
- if (!gl) {
- console.log('Failed to get the rendering context for WebGL');
- return;
- }
- // Initialize shaders
- if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
- console.log('Failed to initialize shaders.');
- return;
- }
- // Get the storage location of attribute variable
- 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;
- }
-
- // Get the storage location of u_FragColor variable
- var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
- if (!u_FragColor) {
- console.log('Failed to get the storage location of u_FragColor');
- return;
- }
- // Register function (event handler) to be called on mouse press
- canvas.onmousedown = function(ev) {
- click(ev, gl, canvas, a_Position, u_FragColor);
- }
- // Specify the color for clearing <canvas>
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
-
- // Clear <canvas>
- gl.clear(gl.COLOR_BUFFER_BIT);
- }
- var g_points = []; // The array of a mouse press
- var g_colors = []; // The array to store the color of a point
- function click(ev, gl, canvas, a_Position, u_FragColor) {
- var x = ev.clientX; // x coordinate of a mouse pointer
- var y = ev.clientY; // y coordinate of a mouse pointer
- var rect = ev.target.getBoundingClientRect();
- x = ((x - rect.left) - canvas.height / 2) / (canvas.height / 2);
- y = (canvas.width / 2 - (y - rect.top)) / (canvas.width / 2);
- // Store the coordinates to g_Points array
- g_points.push([x, y]);
- // Store the color to g_colors array
- if (x >= 0.0 && y >= 0.0) { // First quadrant
- g_colors.push([1.0, 0.0, 0.0, 1.0]); // Red
- } else if (x < 0.0 && y < 0.0) { // Third quadrant
- g_colors.push([0.0, 1.0, 0.0, 1.0]); // Green
- } else { // Others
- g_colors.push([1.0, 1.0, 1.0, 1.0]); // White
- }
- // Clear <canvas>
- gl.clear(gl.COLOR_BUFFER_BIT);
- var len = g_points.length;
- for(var i = 0; i < len; i++) {
- var xy = g_points[i];
- var rgba = g_colors[i];
- // Pass the position of a point to a_Position variable
- gl.vertexAttrib3f(a_Position, xy[0], xy[1], 0.0);
- // Pass the color of a point to u_FragColor variable
- gl.uniform4f(u_FragColor, rgba[0], rgba[1], rgba[2], rgba[3]);
- // Draw a point
- gl.drawArrays(gl.POINTS, 0, 1);
- }
- }
复制代码 运行画面截图:

两种方法转达到片段着色器

Chapter 3 绘制和变换三角形
Example 1 绘制多个点
使用缓冲区对象
- var vertices = new Float32Array([
- 0.0, 0.5, -0.5, -0.5, 0.5, -0.5
- ]);
- var n = 3; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
复制代码 使用缓冲区对象的5个步调:
- 创建缓冲区对象 gl.createBuffer()
- 绑定缓冲区对象到目的
- 写入数据到缓冲区对象
- 赋值缓冲区对象到属性变量
- 开启匹配
创建缓冲区对象
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
复制代码
绑定缓冲区对象目的
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
复制代码
写入数据到缓冲区对象
- // Write data into the buffer object
- gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
复制代码
赋值缓冲区对象到属性变量
- // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
复制代码
开启匹配
- // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position);
复制代码
步伐范例:
- // MulitPoint.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'void main() {\n' + ' gl_Position = a_Position;\n' + // Coordinates ' gl_PointSize = 10.0;\n' + // Set the point size '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.POINTS, 0, n);}function initVertexBuffers(gl) { var vertices = new Float32Array([
- 0.0, 0.5, -0.5, -0.5, 0.5, -0.5
- ]);
- var n = 3; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果:

Example 2 绘制三角形
基本图元

步伐示例:
- // HelloTriangle.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'void main() {\n' + ' gl_Position = a_Position;\n' + // Coordinates '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point 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; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果

LINES、LINE_STRIP、LINE_LOOP
Example 3 绘制矩形
使用TRIANGLE_STRIP
步伐示例
- // HelloQuand.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'void main() {\n' + ' gl_Position = a_Position;\n' + // Coordinates '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);}function initVertexBuffers(gl) { var vertices = new Float32Array([ -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5 ]); var n = 4; // The number of vertices // Create a buffer object
- var vertexBuffer = gl.createBuffer(); if (!vertexBuffer) { console.log('Failed to create the buffer object'); return -1; } // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果

使用TRIANGLE_FAN
- // HelloQuandFan.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'void main() {\n' + ' gl_Position = a_Position;\n' + // Coordinates '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.TRIANGLE_FAN, 0, n);}function initVertexBuffers(gl) { var vertices = new Float32Array([ -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5 ]); var n = 4; // The number of vertices // Create a buffer object
- var vertexBuffer = gl.createBuffer(); if (!vertexBuffer) { console.log('Failed to create the buffer object'); return -1; } // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果

第2个图形覆盖了第一个图形

Example 4 移动、旋转、缩放
移动
步伐示例:
- // TranslatedTriangle.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'uniform vec4 u_Translation;\n' + 'void main() {\n' + ' gl_Position = a_Position + u_Translation;\n' + // Coordinates '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';// The translation distance for x, y, and z directionvar Tx = 0.5, Ty = 0.5, Tz = 0.0;function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Pass the translation distance to the vertex shader var u_Translation = gl.getUniformLocation(gl.program, 'u_Translation'); if (u_Translation == null) { console.log('Failed to get the storage location of u_Translation'); return; } gl.uniform4f(u_Translation, Tx, Ty, Tz, 0.0); // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point 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; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果:

旋转
绕z轴逆时针旋转β角度


vec4范例成原访问方法:

步伐示例
- // RotatedTriangle.js// Vertex shader programvar VSHADER_SOURCE = // x' = x cos b - y sin b // y' = x sin b + y cos b // z' = z 'attribute vec4 a_Position;\n' + 'uniform float u_CosB, u_SinB;\n' + 'void main() {\n' + ' gl_Position.x = a_Position.x * u_CosB - a_Position.y * u_SinB;\n' + ' gl_Position.y = a_Position.x * u_SinB + a_Position.y * u_CosB;\n' + ' gl_Position.z = a_Position.z;\n' + ' gl_Position.w = 1.0;\n' + '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';// Rotation anglevar ANGLE = 90.0;function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; // β α } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Pass the data required to rotate the shape to the vertex shader var radian = Math.PI * ANGLE / 180.0; // Convert to radians var cosB = Math.cos(radian); var sinB = Math.sin(radian); var u_CosB = gl.getUniformLocation(gl.program, 'u_CosB'); var u_SinB = gl.getUniformLocation(gl.program, 'u_SinB'); if(u_CosB == null || u_SinB == null) { console.log('Failed to get uniform value u_CosB or u_SinB'); return; } gl.uniform1f(u_CosB, cosB); gl.uniform1f(u_SinB, sinB); // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point 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; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果:

变换矩阵:旋转
旋转矩阵:
变换矩阵:移动
平移矩阵:
WebGL 使用的是列主矩阵,所以在构建矩阵是,要转置一下,下面为旋转矩阵转置后的代码:
- // Note: WebGL is column major order
- var xformMatrix = new Float32Array([
- cosB, sinB, 0.0, 0.0,
- -sinB, cosB, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0
- ]);
复制代码 步伐示例:
- // RotatedTriangleMatrix.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'uniform mat4 u_xformMatrix;\n' + 'void main() {\n' + ' gl_Position = u_xformMatrix * a_Position;\n' + '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';// Rotation anglevar ANGLE = 90.0;function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; // α } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Pass the data required to rotate the shape to the vertex shader var radian = Math.PI * ANGLE / 180.0; // Convert to radians var cosB = Math.cos(radian); var sinB = Math.sin(radian); // Note: WebGL is column major order
- var xformMatrix = new Float32Array([
- cosB, sinB, 0.0, 0.0,
- -sinB, cosB, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0
- ]); // Pass the rotation matrix to the vertex shader var u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix'); if(u_xformMatrix == null) { console.log('Failed to get uniform value u_CosB or u_SinB'); return; } gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix); // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point 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; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果:

变换矩阵:缩放

步伐示例:
- // ScalingTriangleMatrix.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'uniform mat4 u_xformMatrix;\n' + 'void main() {\n' + ' gl_Position = u_xformMatrix * a_Position;\n' + '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';var Sx = 1.0, Sy = 1.5, Sz = 1.0;function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; // α } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Note: WebGL is column major order var xformMatrix = new Float32Array([ Sx, 0.0, 0.0, 0.0, 0.0, Sy, 0.0, 0.0, 0.0, 0.0, Sz, 0.0, 0.0, 0.0, 0.0, 1.0 ]); // Pass the rotation matrix to the vertex shader var u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix'); if(u_xformMatrix == null) { console.log('Failed to get uniform value u_CosB or u_SinB'); return; } gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix); // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point 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; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果:

Chapter 4 更多幻化和基本动画
移动并旋转
组合多个变换:
矩阵变革为逆向进行,如下图:


步伐示例:
- // RotatedTranslatedTriangle.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'uniform mat4 u_ModelMatrix;\n' + 'void main() {\n' + ' gl_Position = u_ModelMatrix * a_Position;\n' + '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; // α } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Create Matrix4 object for model transformation var modelMatrix = new Matrix4(); // Calculate a model matrix var ANGLE = 60.0; // Rotation angle; var Tx = 0.5; // Translation distance //modelMatrix.setTranslate(Tx, 0, 0); // Mulitpy modelMatrix by the calculated translation matrix //modelMatrix.rotate(ANGLE, 0, 0, 1); // Set rotation matrix modelMatrix.setRotate(ANGLE, 0, 0, 1); // Set rotation matrix modelMatrix.translate(Tx, 0, 0); // Mulitpy modelMatrix by the calculated translation matrix // Pass the rotation matrix to the vertex shader var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix'); if(u_ModelMatrix == null) { console.log('Failed to get uniform value u_ModelMatrix'); return; } gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.TRIANGLES, 0, n);}function initVertexBuffers(gl) { var vertices = new Float32Array([ 0.0, 0.3, -0.3, -0.3, 0.3, -0.3 ]); var n = 3; // The number of vertices // Create a buffer object
- var vertexBuffer = gl.createBuffer(); if (!vertexBuffer) { console.log('Failed to create the buffer object'); return -1; } // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行结果:

两种矩阵变换次序的比较如下图:

动画
请求浏览器调用tick()
- // Current rotation angle of a triangle
- var currentAngle = 0.0;
- // Create Matrix4 object for model transformation
- var modelMatrix = new Matrix4();
- // Start to draw a triangle
- var tick = function() {
- currentAngle = animate(currentAngle); // Update the rotation angle
- draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix);
- requestAnimationFrame(tick); // Request that the browser calls tick
- };
- tick();
复制代码
步伐示例:
- // RotatingTriangle.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'uniform mat4 u_ModelMatrix;\n' + 'void main() {\n' + ' gl_Position = u_ModelMatrix * a_Position;\n' + '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';// Rotation angle (degrees/second)var ANGLE_STEP = 45.0;function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; // α } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Pass the rotation matrix to the vertex shader var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix'); if(u_ModelMatrix == null) { console.log('Failed to get uniform value u_ModelMatrix'); return; } // Current rotation angle of a triangle var currentAngle = 0.0; // Create Matrix4 object for model transformation var modelMatrix = new Matrix4(); // Start to draw a triangle var tick = function() { currentAngle = animate(currentAngle); // Update the rotation angle draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix); requestAnimationFrame(tick); // Request that the browser calls tick }; tick();}function initVertexBuffers(gl) { var vertices = new Float32Array([
- 0.0, 0.5, -0.5, -0.5, 0.5, -0.5
- ]);
- var n = 3; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) { // Set up rotation matrix modelMatrix.setRotate(currentAngle, 0, 0, 1); // Pass the rotation matrix to the vertex shader gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.TRIANGLES, 0, n);}// Last time when this function was calledvar g_last = Date.now();function animate(angle) { // Calculate the elapsed time var now = Date.now(); var elapsed = now - g_last; // milliseconds g_last = now; // Update the current rotation angle (adjusted by the elapsed time) var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0; return newAngle %= 360;}
复制代码 运行结果:

带按钮的旋转动画
步伐示例:
- // RotatingTriangleWithButtons.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'uniform mat4 u_ModelMatrix;\n' + 'void main() {\n' + ' gl_Position = u_ModelMatrix * a_Position;\n' + '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';// Rotation angle (degrees/second)var ANGLE_STEP = 45.0;function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; // α } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Pass the rotation matrix to the vertex shader var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix'); if(u_ModelMatrix == null) { console.log('Failed to get uniform value u_ModelMatrix'); return; } //注册按钮变乱 //旋转速率+ document.getElementById("btnUp").onclick = function(e) { ANGLE_STEP += 5.0; }; //旋转速率- document.getElementById("btnDown").onclick = function(e) { ANGLE_STEP -= 5.0; }; // Current rotation angle of a triangle var currentAngle = 0.0; // Create Matrix4 object for model transformation var modelMatrix = new Matrix4(); // Start to draw a triangle var tick = function() { currentAngle = animate(currentAngle); // Update the rotation angle draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix); requestAnimationFrame(tick); // Request that the browser calls tick }; tick();}function initVertexBuffers(gl) { var vertices = new Float32Array([
- 0.0, 0.5, -0.5, -0.5, 0.5, -0.5
- ]);
- var n = 3; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) { // Set up rotation matrix modelMatrix.setRotate(currentAngle, 0, 0, 1); // Pass the rotation matrix to the vertex shader gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.TRIANGLES, 0, n);}// Last time when this function was calledvar g_last = Date.now();function animate(angle) { // Calculate the elapsed time var now = Date.now(); var elapsed = now - g_last; // milliseconds g_last = now; // Update the current rotation angle (adjusted by the elapsed time) var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0; return newAngle %= 360;}
复制代码 步伐截图:

Chapter 5 使用颜色和纹理图像
转达其它信息到顶点着色器
将顶点坐标缓冲区和点的巨细缓冲区同时赋值给顶点着色器表现图:

示例步伐:
- // MulitAttributeSize.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'attribute float a_PointSize;\n' + 'void main() {\n' + ' gl_Position = a_Position;\n' + // Coordinates ' gl_PointSize = a_PointSize;\n' + // Set the point size '}\n';// Fragment shader programvar FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the color '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.POINTS, 0, n);}function initVertexBuffers(gl) { var vertices = new Float32Array([ 0.0, 0.5, -0.5, -0.5, 0.5, -0.5 ]); var n = 3; // The number of vertices var sizes = new Float32Array([ 10.0, 20.0, 30.0 // Point sizes ]); // Create a buffer object
- var vertexBuffer = gl.createBuffer(); var sizeBuffer = gl.createBuffer(); if (!vertexBuffer || !sizeBuffer) { console.log('Failed to create the buffer object'); return -1; } // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); // Write point sizes to the buffer object and enable it gl.bindBuffer(gl.ARRAY_BUFFER, sizeBuffer); gl.bufferData(gl.ARRAY_BUFFER, sizes, gl.STATIC_DRAW); var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize'); if (a_PointSize < 0) { console.log('Failed to get the storage location of a_PointSize'); return; } gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(a_PointSize); return n;}
复制代码 运行截图:

使用步长和偏移量将多范例数组发往顶点着色器
将点的巨细混入到点的坐标数组中,代码见下
- var verticesSizes = new Float32Array([
- // Vertex coordinates and size of a point
- 0.0, 0.5, 10.0, // The 1st vertex
- -0.5, -0.5, 20.0, // The 2nd vertex
- 0.5, -0.5, 30.0 // The 3rd vertex
- ]);
复制代码 其中前两个是点的x、y坐标,第3个是点的巨细
起首创建缓冲区对象,然后将缓冲区对象绑定到gl.ARRAY_BUFFER,末了将数组绑定到缓冲区对象:
- var vertexSizeBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexSizeBuffer);
- gl.bufferData(gl.ARRAY_BUFFER, verticesSizes, gl.STATIC_DRAW);
复制代码 取得每个元素的巨细:
- var FSIZE = verticesSizes.BYTES_PER_ELEMENT;
复制代码 关联上顶点着色器中的变量:
- var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
- var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
复制代码 顶点位置使用3个成员一组步长的方式,偏移量为0(第5和第6个参数):
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 3, 0);
复制代码 点的巨细,使用偏移量为2(第5和第6个参数):
- gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, FSIZE * 3, FSIZE * 2);
复制代码 末了分别开启两个缓冲区,使其见效:
- gl.enableVertexAttribArray(a_Position);
- gl.enableVertexAttribArray(a_PointSize);
复制代码 表现图如下:
webgl内部在使用偏移量的情形下的表现图:
使用可变变量转达到片段着色器
同一变量(uniform)不能转达可变的变量.
定一个含有顶点坐标+颜色值的数组:
- var verticesSizes = new Float32Array([
- // Vertex coordinates and color
- 0.0, 0.5, 1.0, 0.0, 0.0, // The 1st vertex
- -0.5, -0.5, 0.0, 1.0, 0.0, // The 2nd vertex
- 0.5, -0.5, 0.0, 0.0, 1.0 // The 3rd vertex
- ]);
复制代码 其中,每行的3,4,5项分别表现颜色的R,G,B的值,第1,2项为坐标值。
使用偏移量来区分写入缓冲区的位置:
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0);
- gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2);
复制代码 第1举动位置缓冲区,占用2个元素,gl.FLOAT范例,不进行归一化,5个一组,偏移量0
第2举动位置缓冲区,占用3个元素,gl.FLOAT范例,不进行归一化,5个一组,偏移量2
在顶点着色器中,设置可变变量v_Color:
- // Vertex shader program
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'attribute vec4 a_Color;\n' +
- 'varying vec4 v_Color;\n' + // varying variable
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' + // Coordinates
- ' gl_PointSize = 10.0;\n' + // Set the point size
- ' v_Color = a_Color;\n' + // Pass the data to the fragment shader
- '}\n';
复制代码 在片段着色器中,引入可变变量v_Color,并复制给保留变量gl_FragColor:
- // Fragment shader program
- var FSHADER_SOURCE =
- '#ifdef GL_ES\n'+
- ' precision mediump float;\n' +
- '#endif\n'+
- 'varying vec4 v_Color;\n' +
- 'void main() {\n' +
- ' gl_FragColor = v_Color;\n' + // Receive the data from the vertex shader
- '}\n';
复制代码 其余和上一个列题一致,不再重复。
从顶点着色器转达数据到片段着色器的方法:
- 可变变量(varying variable)只支持浮点型
- 当顶点着色器上的可变变量名称及范例与片段着色器上的可变变量名称及范例相同时,自动会完成数据转达的动作。
示例步伐:
- // MulitAttributeColor.js// Vertex shader program
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'attribute vec4 a_Color;\n' +
- 'varying vec4 v_Color;\n' + // varying variable
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' + // Coordinates
- ' gl_PointSize = 10.0;\n' + // Set the point size
- ' v_Color = a_Color;\n' + // Pass the data to the fragment shader
- '}\n';// Fragment shader program
- var FSHADER_SOURCE =
- '#ifdef GL_ES\n'+
- ' precision mediump float;\n' +
- '#endif\n'+
- 'varying vec4 v_Color;\n' +
- 'void main() {\n' +
- ' gl_FragColor = v_Color;\n' + // Receive the data from the vertex shader
- '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.POINTS, 0, n);}function initVertexBuffers(gl) { var verticesSizes = new Float32Array([
- // Vertex coordinates and color
- 0.0, 0.5, 1.0, 0.0, 0.0, // The 1st vertex
- -0.5, -0.5, 0.0, 1.0, 0.0, // The 2nd vertex
- 0.5, -0.5, 0.0, 0.0, 1.0 // The 3rd vertex
- ]); var n = 3; // The number of vertices // Create a buffer object var vertexSizeBuffer = gl.createBuffer(); if (!vertexSizeBuffer) { console.log('Failed to create the buffer object'); return -1; } // Write point sizes to the buffer object and enable it gl.bindBuffer(gl.ARRAY_BUFFER, vertexSizeBuffer); gl.bufferData(gl.ARRAY_BUFFER, verticesSizes, gl.STATIC_DRAW); var FSIZE = verticesSizes.BYTES_PER_ELEMENT; // Get the storage location of a_Position, allocate buffer, & enable 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; } gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0); gl.enableVertexAttribArray(a_Position); // Enable allocation // Get the storage location of a_PointSize, allocate buffer, & enable var a_Color = gl.getAttribLocation(gl.program, 'a_Color'); if (a_Color < 0) { console.log('Failed to get the storage location of a_Color'); return; } gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2); gl.enableVertexAttribArray(a_Color); return n;}
复制代码 运行截图:

带有颜色差值的三角形
顶点着色器和片段着色器之间的组装和光栅化

片段着色器的生成

修改每个片段的颜色值
步伐示例:
- // HelloTriangleFragCoord.js// Vertex shader programvar VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'void main() {\n' + ' gl_Position = a_Position;\n' + // Coordinates '}\n';// Fragment shader programvar FSHADER_SOURCE = 'precision mediump float;\n' + 'uniform float u_Width;\n' + 'uniform float u_Height;\n' + 'void main() {\n' + ' gl_FragColor = vec4(gl_FragCoord.x/u_Width, 0.0, gl_FragCoord.y/u_Height, 1.0);\n' + // Set the color '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point 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; // The number of vertices
- // Create a buffer object
- var vertexBuffer = gl.createBuffer();
- if (!vertexBuffer) {
- console.log('Failed to create the buffer object');
- return -1;
- }
- // Bind the buffer object to traget
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- // Write data into the buffer object
- 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; } // Assign the buffer object to a_Position variable
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); var u_Width = gl.getUniformLocation(gl.program, 'u_Width'); if (!u_Width) { console.log('Failed to get the storage location of u_Width'); return; } var u_Height = gl.getUniformLocation(gl.program, 'u_Height'); if (!u_Height) { console.log('Failed to get the storage location of u_Height'); return; } // Pass the width and hight of the <canvas> gl.uniform1f(u_Width, gl.drawingBufferWidth); gl.uniform1f(u_Height, gl.drawingBufferHeight); // Enable the assignment to a_Position variable
- gl.enableVertexAttribArray(a_Position); return n;}
复制代码 运行截图:

变量的函数性和差值过程
可变变量的差值化:

颜色的差值化范例,红色-蓝色:

步伐示例:
- // ColoredTriangle.js// Vertex shader program
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'attribute vec4 a_Color;\n' +
- 'varying vec4 v_Color;\n' + // varying variable
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' + // Coordinates
- ' gl_PointSize = 10.0;\n' + // Set the point size
- ' v_Color = a_Color;\n' + // Pass the data to the fragment shader
- '}\n';// Fragment shader program
- var FSHADER_SOURCE =
- '#ifdef GL_ES\n'+
- ' precision mediump float;\n' +
- '#endif\n'+
- 'varying vec4 v_Color;\n' +
- 'void main() {\n' +
- ' gl_FragColor = v_Color;\n' + // Receive the data from the vertex shader
- '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Set the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear <canvas> gl.clear(gl.COLOR_BUFFER_BIT); // Draw a point gl.drawArrays(gl.TRIANGLES, 0, n);}function initVertexBuffers(gl) { var verticesSizes = new Float32Array([
- // Vertex coordinates and color
- 0.0, 0.5, 1.0, 0.0, 0.0, // The 1st vertex
- -0.5, -0.5, 0.0, 1.0, 0.0, // The 2nd vertex
- 0.5, -0.5, 0.0, 0.0, 1.0 // The 3rd vertex
- ]); var n = 3; // The number of vertices // Create a buffer object var vertexSizeBuffer = gl.createBuffer(); if (!vertexSizeBuffer) { console.log('Failed to create the buffer object'); return -1; } // Write point sizes to the buffer object and enable it gl.bindBuffer(gl.ARRAY_BUFFER, vertexSizeBuffer); gl.bufferData(gl.ARRAY_BUFFER, verticesSizes, gl.STATIC_DRAW); var FSIZE = verticesSizes.BYTES_PER_ELEMENT; // Get the storage location of a_Position, allocate buffer, & enable 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; } gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0); gl.enableVertexAttribArray(a_Position); // Enable allocation // Get the storage location of a_PointSize, allocate buffer, & enable var a_Color = gl.getAttribLocation(gl.program, 'a_Color'); if (a_Color < 0) { console.log('Failed to get the storage location of a_Color'); return; } gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2); gl.enableVertexAttribArray(a_Color); return n;}
复制代码 运行截图:

将图像贴到矩形上
构建纹理映射的步调
- 预备要映射到多少图形上的图像
- 指定多少形状的图像映射方法
- 装载图像并对其配置使其可以大概在webgl中使用
- 在片段着色器中从图像中提取纹理像素,并相应地设置对应的片段。
纹理坐标系
纹理坐标映射到顶点坐标
- var verticesTexCoords = new Float32Array([
- // Vertices coordinates, textures coordinates
- -0.5, 0.5, 0.0, 1.0,
- -0.5, -0.5, 0.0, 0.0,
- 0.5, 0.5, 1.0, 1.0,
- 0.5, -0.5, 1.0, 0.0,
- ]);
复制代码
创建纹理对象,这里请求服务器家在一个图片(image.src = '.../resources/sky.jpg'),而这是异步执行的。当图片被夹在完成后,会触发image.onload变乱,而这个变乱也是异步执行的。
- var texture = gl.createTexture(); // Create a texture object
- // Get the storage location of the u_Sampler
- var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
- var image = new Image(); // Create an image object
- // Register the event handler to be called on loading an image
- image.onload = function(){ loadTexture(gl, n, texture, u_Sampler, image); };
- // Tell the browser to load an image
- image.src = '../resources/sky.jpg';
复制代码 创建纹理对象的内部情形表现图:
翻转图像的Y轴
纹理对象装载后,必要反转坐标。由于图像(jpg、png、bmp等)的坐标与webgl不一致,得反转一下坐标(注意,不是反转图片)
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // Flip the image's y axis
复制代码
激活纹理单位
纹理单位的数量因体系和硬件差别有所差异,但最少支持8个纹理单位,分别为gl.TEXTURE0~gl.TEXTURE7。另外在使用纹理单位前,必须先激活一下纹理单位。
- // Enable the texture unit 0
- gl.activeTexture(gl.TEXTURE0);
复制代码 将纹理对象绑定到目的
纹理范例包括二维纹理及立方体纹理贴图,本书只涉及二维纹理。
注意:绑定操作现实上完成了两个任务:一个是启动纹理对象并绑定它到目的;另一个是绑定它到纹理单位。
- // Bind the texture object to the target
- gl.bindTexture(gl.TEXTURE_2D, texture);
复制代码 执行后WEBGL内部变革表现图:
设置纹理对象的纹理参数
指定纹理图像映射到形状时如那边置处罚纹理图像。
- // Set the texture parameters
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
复制代码 4种映射方式如下图所示:
映射完毕后,webgl内部的表现图如下:
将纹理指定给纹理对象
- // Set the texture image
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
复制代码 指定图像后,webgl内部的表现图如下:
将纹理单位转达给片段着色器
起首从片段着色器中关联变量
- var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
复制代码 然后通过image对象的onload函数转达给loadTexture
- var image = new Image(); // Create an image object
- image.onload = function(){ loadTexture(gl, n, texture, u_Sampler, image); };
复制代码 末了将纹理单位转达个u_Sampler,其中第2个参数表现纹理管理器对象第0个纹理对象。
- // Set the texture unit 0 to the sampler
- gl.uniform1i(u_Sampler, 0);
复制代码 而在片段着色器中定义了u_Sampler的同一变量
- // Fragment shader program <- (Part 2)
- var FSHADER_SOURCE =
- '#ifdef GL_ES\n' +
- 'precision mediump float;\n' +
- '#endif\n' +
- 'uniform sampler2D u_Sampler;\n' +
- 'varying vec2 v_TexCoord;\n' +
- 'void main() {\n' +
- ' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
- '}\n';
复制代码 使用着色器语言,将 u_Sampler, v_TextCoor发送给函数texture2D,并将结果返回给保留变量gl_FragColor。其中v_TextCoor为纹理映射坐标,来自顶点着色器。
执行后,webgl内部表现图如下:
将纹理坐标从顶点着色器转达到片段着色器
顶点着色器中将纹理坐标a_TexCoord通过可变变量v_TexCoord转达给片段着色器。
- // Vertex shader program <- (Part 1)
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'attribute vec2 a_TexCoord;\n' +
- 'varying vec2 v_TexCoord;\n' +
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' +
- ' v_TexCoord = a_TexCoord;\n' +
- '}\n';
复制代码 而纹理坐标在initVertexBuffer被关联:
- // Create the buffer object
- var vertexTexCoordBuffer = gl.createBuffer();
- // Write the vertex coords and textures coords to the object buffer
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
- gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
- var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
- var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
- gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
- gl.enableVertexAttribArray(a_TexCoord); // Enable buffer allocation
复制代码 纹理坐标在数组中被定义(第3,第4项):
- var verticesTexCoords = new Float32Array([
- // Vertices coordinates, textures coordinates
- -0.5, 0.5, 0.0, 1.0,
- -0.5, -0.5, 0.0, 0.0,
- 0.5, 0.5, 1.0, 1.0,
- 0.5, -0.5, 1.0, 0.0,
- ]);
复制代码 在判定着色器中检索纹理颜色
在片段着色器中,使用texture2D将纹理和坐标映射到绘制的形状上,本例是个矩形。webgl使用差值颜色提取的方式,将颜色从纹理中提取出来赋值给gl_FragColor内置保留变量。
- 'void main() {\n' +
- ' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
- '}\n';
复制代码 在本例中使用了RGBA的返回格式,因为图片是jpg/png形式。
步伐示例
- // TexturedQuad.js// Vertex shader program <- (Part 1)
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'attribute vec2 a_TexCoord;\n' +
- 'varying vec2 v_TexCoord;\n' +
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' +
- ' v_TexCoord = a_TexCoord;\n' +
- '}\n';// Fragment shader program <- (Part 2)
- var FSHADER_SOURCE =
- '#ifdef GL_ES\n' +
- 'precision mediump float;\n' +
- '#endif\n' +
- 'uniform sampler2D u_Sampler;\n' +
- 'varying vec2 v_TexCoord;\n' +
- 'void main() {\n' +
- ' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
- '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices <- (part 3) var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Specify the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Setting the textures if (!initTextures(gl, n)) { console.log('Failed to intialize the texture.'); return; }}function initVertexBuffers(gl) { var verticesTexCoords = new Float32Array([
- // Vertices coordinates, textures coordinates
- -0.5, 0.5, 0.0, 1.0,
- -0.5, -0.5, 0.0, 0.0,
- 0.5, 0.5, 1.0, 1.0,
- 0.5, -0.5, 1.0, 0.0,
- ]); var n = 4; // The number of vertices // Create the buffer object var vertexTexCoordBuffer = gl.createBuffer(); if (!vertexTexCoordBuffer) { console.log('Failed to create the buffer object'); return -1; } // Write the vertex coords and textures coords to the object buffer gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW); var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT; // Get the storage location of a_Position, allocate buffer, & enable 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; } gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0); gl.enableVertexAttribArray(a_Position); // Enable buffer allocation // Allocate the texture coordinates to a_TexCoord, and enable it. var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord'); if (a_TexCoord < 0) { console.log('Failed to get the storage location of a_TexCoord'); return; } gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2); gl.enableVertexAttribArray(a_TexCoord); // Enable buffer allocation return n;}function initTextures(gl, n) { // <- (Part 4) var texture = gl.createTexture(); // Create a texture object if (!texture) { console.log('Failed to create the texture object'); return false; } // Get the storage location of the u_Sampler var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler'); if (!u_Sampler) { console.log('Failed to get the storage location of u_Sampler'); return false; } var image = new Image(); // Create an image object if (!image) { console.log('Failed to create the image object'); return false; } // Register the event handler to be called on loading an image image.onload = function(){ loadTexture(gl, n, texture, u_Sampler, image); }; // Tell the browser to load an image image.src = '../resources/sky.jpg'; return true;}function loadTexture(gl, n, texture, u_Sampler, image) { // <- (Part 5) gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // Flip the image's y axis // Enable the texture unit 0 gl.activeTexture(gl.TEXTURE0); // Bind the texture object to the target gl.bindTexture(gl.TEXTURE_2D, texture); // Set the texture parameters gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); // Set the texture image gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); // Set the texture unit 0 to the sampler gl.uniform1i(u_Sampler, 0); gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas> gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // Draw a rectangle}
复制代码 运行结果:

将纹理循环映射
修改纹理映射关系,如下:
- var verticesTexCoords = new Float32Array([
- // Vertices coordinates, textures coordinates
- -0.5, 0.5, -0.3, 1.7,
- -0.5, -0.5, -0.3, -0.2,
- 0.5, 0.5, 1.7, 1.7,
- 0.5, -0.5, 1.7, -0.2
- ]);
复制代码 映射关系表现图(见右)其余内容保持不变,执行步伐后,运行结果(见左)如下:
边缘填充与镜像填充
gl.TEXTURE_WRAP_S: 水平方向的填充, gl.TEXTURE_WRAP_T:垂直方向的填充。
填充方法:gl.CLAMP_TO_EDGE:使用边缘颜色;gl.MIRRORED_REPEAT:使用镜像重复填充。
- // Set the texture parameters
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
复制代码 上面代码水平使用了边缘颜色填充,垂直使用了纹理镜像填充。运行结果如下图:
复合多个纹理
与前文TexturedQuad.js的7处差别
1. 片段着色器使用了两个纹理变量,并使用它们各自的纹理映射颜色的乘积作为终极颜色赋值给gl_FragColor。
- var FSHADER_SOURCE =
- '#ifdef GL_ES\n' +
- 'precision mediump float;\n' +
- '#endif\n' +
- 'uniform sampler2D u_Sampler0;\n' +
- 'uniform sampler2D u_Sampler1;\n' +
- 'varying vec2 v_TexCoord;\n' +
- 'void main() {\n' +
- ' vec4 color0 = texture2D(u_Sampler0, v_TexCoord);\n' +
- ' vec4 color1 = texture2D(u_Sampler1, v_TexCoord);\n' +
- ' gl_FragColor = color0 * color1;\n' +
- '}\n';
复制代码 2. 初始化纹理函数initTextures中,声明了两个纹理对象,然后两个纹理文件,关联两个同一变量。
- var texture0 = gl.createTexture(); // Create a texture objec
- var texture1 = gl.createTexture(); // create another texture object
- // Get the storage location of the u_Sampler
- var u_Sampler0 = gl.getUniformLocation(gl.program, 'u_Sampler0');
- var u_Sampler1 = gl.getUniformLocation(gl.program, 'u_Sampler1');
- var image0 = new Image(); // Create an image object
- var image1 = new Image(); // Create another image object
- // Register the event handler to be called on loading an image
- image0.onload = function(){ loadTexture(gl, n, texture0, u_Sampler0, image0,
- 0); };
- image1.onload = function(){ loadTexture(gl, n, texture1, u_Sampler1, image1,
- 1); };
- // Tell the browser to load an image
- image0.src = '../resources/sky.jpg';
- image1.src = '../resources/circle.gif';
复制代码 3. 定义两个全局变量,用来记录两个纹理是否各自预备就绪已经做好了映射预备。这是因为图像时异步加载的,并不清晰哪个先加载,所以放入两个变量,确保都为true才认为两个图像都映射完毕。
- // Specify whether the texture unit is ready to use
- var g_texUnit0 = false, g_texUnit1 = false;
复制代码 4. 修改loadTexture参数,增加纹理单位编号参数:
- function loadTexture(gl, n, texture, u_Sampler, image, texUnit) {
- ...
- }
复制代码 5. 每个纹理参数调用loadTexture时,各自执行自己的纹理激活状态
- // make the texture unit active
- if (texUnit == 0) {
- gl.activeTexture(gl.TEXTURE0);
- g_texUnit0 = true;
- } else {
- gl.activeTexture(gl.TEXTURE1);
- g_texUnit1 = true;
- }
复制代码 6. 修改各自关联的对象
- // Set the texture unit number to the sampler
- gl.uniform1i(u_Sampler, texUnit);
复制代码 7. 在两个纹理全部映射完毕的前提下才开启绘制图像。确保两个图像都映射完毕(为true),因为图像加载是异步的。
- if (g_texUnit0 && g_texUnit1) {
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // Draw a rectangle
- }
复制代码 两个图像映射完毕后的webgl内部表现图:
步伐示例
- // TexturedQuad.js// Vertex shader program <- (Part 1)
- var VSHADER_SOURCE =
- 'attribute vec4 a_Position;\n' +
- 'attribute vec2 a_TexCoord;\n' +
- 'varying vec2 v_TexCoord;\n' +
- 'void main() {\n' +
- ' gl_Position = a_Position;\n' +
- ' v_TexCoord = a_TexCoord;\n' +
- '}\n';// Fragment shader program <- (Part 2)var FSHADER_SOURCE =
- '#ifdef GL_ES\n' +
- 'precision mediump float;\n' +
- '#endif\n' +
- 'uniform sampler2D u_Sampler0;\n' +
- 'uniform sampler2D u_Sampler1;\n' +
- 'varying vec2 v_TexCoord;\n' +
- 'void main() {\n' +
- ' vec4 color0 = texture2D(u_Sampler0, v_TexCoord);\n' +
- ' vec4 color1 = texture2D(u_Sampler1, v_TexCoord);\n' +
- ' gl_FragColor = color0 * color1;\n' +
- '}\n';function main() { // Retrieve <canvas> element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to initialize shaders.'); return; } // Set the positions of vertices <- (part 3) var n = initVertexBuffers(gl); if (n < 0) { console.log('Failed to set the positions of the vertices'); return; } // Specify the color for clearing <canvas> gl.clearColor(0.0, 0.0, 0.0, 1.0); // Setting the textures if (!initTextures(gl, n)) { console.log('Failed to intialize the texture.'); return; }}function initVertexBuffers(gl) { var verticesTexCoords = new Float32Array([ // Vertices coordinates, textures coordinates -0.5, 0.5, 0.0, 1.0, -0.5, -0.5, 0.0, 0.0, 0.5, 0.5, 1.0, 1.0, 0.5, -0.5, 1.0, 0.0 ]); var n = 4; // The number of vertices // Create the buffer object var vertexTexCoordBuffer = gl.createBuffer(); if (!vertexTexCoordBuffer) { console.log('Failed to create the buffer object'); return -1; } // Write the vertex coords and textures coords to the object buffer gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW); var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT; // Get the storage location of a_Position, allocate buffer, & enable 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; } gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0); gl.enableVertexAttribArray(a_Position); // Enable buffer allocation // Allocate the texture coordinates to a_TexCoord, and enable it. var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord'); if (a_TexCoord < 0) { console.log('Failed to get the storage location of a_TexCoord'); return; } gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2); gl.enableVertexAttribArray(a_TexCoord); // Enable buffer allocation return n;}function initTextures(gl, n) { // <- (Part 4) var texture0 = gl.createTexture(); // Create a texture object if (!texture0) { console.log('Failed to create the texture0 object'); return false; } var texture1 = gl.createTexture(); // create another texture object if (!texture1) { console.log('Failed to create the texture1 object'); return false; } // Get the storage location of the u_Sampler var u_Sampler0 = gl.getUniformLocation(gl.program, 'u_Sampler0'); if (!u_Sampler0) { console.log('Failed to get the storage location of u_Sampler0'); return false; } var u_Sampler1 = gl.getUniformLocation(gl.program, 'u_Sampler1'); if (!u_Sampler1) { console.log('Failed to get the storage location of u_Sampler1'); return false; } var image0 = new Image(); // Create an image object if (!image0) { console.log('Failed to create the image0 object'); return false; } var image1 = new Image(); // Create another image object if (!image1) { console.log('Failed to create the image1 object'); return false; } // Register the event handler to be called on loading an image image0.onload = function(){ loadTexture(gl, n, texture0, u_Sampler0, image0, 0); }; image1.onload = function(){ loadTexture(gl, n, texture1, u_Sampler1, image1, 1); }; // Tell the browser to load an image image0.src = '../resources/sky.jpg'; image1.src = '../resources/circle.gif'; return true;}// Specify whether the texture unit is ready to use
- var g_texUnit0 = false, g_texUnit1 = false;function loadTexture(gl, n, texture, u_Sampler, image, texUnit) { // <- (Part 5) gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // Flip the image's y axis // make the texture unit active
- if (texUnit == 0) {
- gl.activeTexture(gl.TEXTURE0);
- g_texUnit0 = true;
- } else {
- gl.activeTexture(gl.TEXTURE1);
- g_texUnit1 = true;
- } // Bind the texture object to the target gl.bindTexture(gl.TEXTURE_2D, texture); // Set the texture parameters gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); // Set the texture image gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); // Set the texture unit number to the sampler
- gl.uniform1i(u_Sampler, texUnit); gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas> if (g_texUnit0 && g_texUnit1) {
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // Draw a rectangle
- }}
复制代码 运行结果

Chapter 6 OpenGL ES着色语言
初识GLSL ES 着色器
根本
- GLSL ES类C语言,巨细写敏感
- 每行末端使用分号(;)结束
执行次序
始终从main()开始,且main()不能有任何参数,返回值为void
解释
数据范例
- 数值范例:包括integer、float。不带小数点将被视作整数。
- 布尔范例:true、false
- GLSL ES不支持string字符串范例
变量
- a~z,A~Z,_,0-9
- 数字不能放在第一位
- 不能使用关键字和保留字
- 不能使用gl_、webgl_、_webgl_开头的保留字作为变量名称
GLSL ES是一种强范例语言
定义变量的结构
<data type> <variable name>
例如:vec4 a_Position
基本范例
范例转换
int(float), int (bool), float(int), float(bool), bool(int), bool(float)
向量范例和矩阵范例
支持的向量范例
- vec2, vec3, vec4
- ivec2, ivec3, ivec4
- bvec2, bvec3, bvec4
支持的矩阵范例
赋值与构造
向量的赋值与构造
- vec3 v3 = vec3(1.0, 0.0, 0.5); // sets v3 to(1.0, 0.0, 0.5)
- vec2 v2 = vec2(v3); // sets v2 to (1.0, 0.0) using the 1st and 2nd elements of v3
- vec4 v4 = vec4(1.0); // sets v4 to (1.0, 1.0, 1.0, 1.0)
- vec4 v4b = vec4(v2, v4); // sets (1.0, 0.0, 1.0, 1.0) to v4b
复制代码 矩阵的赋值与构造
注意:矩阵是列主形式的。
- // two vec2 are used to construct a mat2
- vec2 v2_1 = vec2(1.0, 3.0);
- vec2 v2_2 = vec2(2.0, 4.0);
- mat2 m2_1 = mat2(v2_1, v2_2); // 1.0 2.0
- // 3.0 4.0
- // vec4 is used to construct mat2
- vec4 v4 = vec4(1.0, 3.0, 2.0, 4.0);
- mat2 m2_2 = mat2(v4); // 1.0 2.0
- // 3.4 4.0
-
- // Two floating point numbers and vec2 are used to construct a mat2
- mat2 m2 = mat2(1.0, 3.0, v2_2); // 1.0 2.0
- // 3.0 4.0
- //If a single value is specified to a matrix constructor, a matrix is constructed using the value as its diagonal elements:
- mat4 m4 = mat4(1.0); // 1.0 0.0 0.0 0.0
- // 0.0 1.0 0.0 0.0
- // 0.0 0.0 1.0 0.0
- // 0.0 0.0 0.0 1.0
- mat4 m4 = mat4(1.0, 2.0, 3.0); // Error. mat4 requires 16 elements.
复制代码 访问成员
使用点(.)操作符
- vec3 v3 = vec3(1.0, 2.0, 3.0); // sets v3 to(1.0, 2.0, 3.0)
- float f;
- f = v3.x; // sets f to 1.0
- f = v3.y; // sets f to 2.0
- f = v3.z; // sets f to 3.0
- f = v3.r; // sets f to 1.0
- f = v3.s; // sets f to 1.0
- f = v3.w; // w requires access to the fourth element, which doesn't exist.
- vec2 v2;
- v2 = v3.xy; // sets v2 to (1.0, 2.0)
- v2 = v3.yz; // sets v2 to (2.0, 3.0). Any component can be omitted
- v2 = v3.xz; // sets v2 to (1.0, 3.0). You can skip any component.
- v2 = v3.yx; // sets v2 to (2.0, 1.0). You can reverse the order.
- v2 = v3.xx; // sets v2 to (1.0, 1.0). You can repeat any component.
- vec3 v3a;
- v3a = v3.zyx; // sets v3a to (3.0, 2.0, 1.0). You can use all names.
- vec4 position = vec4(1.0, 2.0, 3.0, 4.0);
- position.xw = vec2(5.0, 6.0); // position = (5.0, 2.0, 3.0, 6.0)
复制代码 使用[]操作符
- mat4 m4 = mat4 ( 1.0, 2.0, 3.0, 4.0,
- 5.0, 6.0, 7.0, 8.0,
- 9.0, 10.0, 11.0, 12.0,
- 13.0, 14.0, 15.0, 16.0);
- vec4 v4 = m4[0]; // Retrieve the 1st column from m4: (1.0, 2.0, 3.0, 4.0)
- float m23 = m4[1][2]; // sets m23 to the third component of the second
- // column of m4 (7.0).
- float m32 = m4[2].y; // sets m32 to the second component of the third
- // column of m4 (10.0).
- const int index = 0; // "const" keyword specifies the variable is a
- // read-only variable.
- vec4 v4a = m4[index]; // is the same as m4[0]
- vec4 v4b = m4[index + 1]; // is the same as m4[1]
- int index2 = 0;
- vec4 v4c = m4[index2]; // Error: because index2 is not a constant index.
复制代码 向量与矩阵的操作
向量与标量操作
- // The following example uses the + operator, but the -, *, and /
- // operators also have the same effect.
- v3b = v3a + f; // v3b.x = v3a.x + f;
- // v3b.y = v3a.y + f;
- // v3b.z = v3a.z + f;
复制代码 向量与向量操作
- // The following example uses the + operator, but the -, *, and /
- // operators also have the same effect.
- v3c = v3a + v3b; // v3a.x + v3b.x;
- // v3a.y + v3b.y;
- // v3a.z + v3b.z;
复制代码 矩阵与标量操作
- // The following example uses the + operator, but the -, *, and /
- // operators also have the same effect.
- m3b = m3a * f; // m3b[0].x = m3a[0].x * f; m3b[0].y = m3a[0].y * f;
- // m3b[0].z = m3a[0].z * f;
- // m3b[1].x = m3a[1].x * f; m3b[1].y = m3a[1].y * f;
- // m3b[1].z = m3a[1].z * f;
- // m3b[2].x = m3a[2].x * f; m3b[2].y = m3a[2].y * f;
- // m3b[2].z = m3a[2].z * f;
复制代码 矩阵与向量相乘
- v3b = m3a * v3a; // v3b.x = m3a[0].x * v3a.x + m3a[1].x * v3a.y
- // + m3a[2].x * v3a.z;
- // v3b.y = m3a[0].y * v3a.x + m3a[1].y * v3a.y
- // + m3a[2].y * v3a.z;
- // v3b.z = m3a[0].z * v3a.x + m3a[1].z * v3a.y
- // + m3a[2].z * v3a.z;
复制代码 向量与矩阵相乘
- v3b = v3a * m3a; // v3b.x = v3a.x * m3a[0].x + v3a.y * m3a[0].y
- // + v3a.z * m3a[0].z;
- // v3b.y = v3a.x * m3a[1].x + v3a.y * m3a[1].y
- // + v3a.z * m3a[1].z;
- // v3b.z = v3a.x * m3a[2].x + v3a.y * m3a[2].y
- // + v3a.z * m3a[2].z;
复制代码 矩阵与矩阵相乘
- m3c = m3a * m3b; // m3c[0].x = m3a[0].x * m3b[0].x + m3a[1].x * m3b[0].y
- // + m3a[2].x * m3b[0].z;
- // m3c[1].x = m3a[0].x * m3b[1].x + m3a[1].x * m3b[1].y
- // + m3a[2].x * m3b[1].z;
- // m3c[2].x = m3a[0].x * m3b[2].x + m3a[1].x * m3b[2].y
- // + m3a[2].x * m3b[2].z;
- // m3c[0].y = m3a[0].y * m3b[0].x + m3a[1].y * m3b[0].y
- // + m3a[2].y * m3b[0].z;
- // m3c[1].y = m3a[0].y * m3b[1].x + m3a[1].y * m3b[1].y
- // + m3a[2].y * m3b[1].z;
- // m3c[2].y = m3a[0].y * m3b[2].x + m3a[1].y * m3b[2].y
- // + m3a[2].y * m3b[2].z;
- // m3c[0].z = m3a[0].z * m3b[0].x + m3a[1].z * m3b[0].y
- // + m3a[2].z * m3b[0].z;
- // m3c[1].z = m3a[0].z * m3b[1].x + m3a[1].z * m3b[1].y
- // + m3a[2].z * m3b[1].z;
- // m3c[2].z = m3a[0].z * m3b[2].x + m3a[1].z * m3b[2].y
- // + m3a[2].z * m3b[2].z;
复制代码 结构体
赋值与构造
结构体的构造
- struct light { // defines the structure "light"
- vec4 color;
- vec3 position;
- }
- light l1, l2; // declares variable "l1" and "l2" of the type "light"
复制代码 或简化为
- struct light { // declares structure and its variable all together
- vec4 color; // color of a light
- vec3 position; // position of a light
- } l1; // variable "l1" of the structure
复制代码 结构体的构造
按结构体成员定义的次序构造结构体。
访问结构体成员
使用点(.)操作符
- vec4 color = l1.color;
- vec3 position = l1.position;
复制代码 结构体的操作
操作符:=、==、!=。
注意:结构体内含有数组大概采样器时不支持此类操作
数组
类C数组,不支持push(), pop(),定义数组是要指定数组巨细,并指定数组范例如下:
- float floatArray[4]; // declares an array consisting of four floats
- vec4 vec4Array[2]; // declares an array consisting of two vec4s
复制代码 数组巨细必须是常量,下面代码是错误的
- int size = 4;
- vec4 vec4Array[size]; // Error. If you declare "const int size = 4;"
- // it will not result in an error
复制代码 访问数组的成员可以使用[]操作符,如下示例:
当给向量数构成员赋值时可以通过向量赋值如下:
- vec4Array[0] = vec4(4.0, 3.0, 6.0, 1.0);
- vec4Array[1] = vec4(3.0, 2.0, 0.0, 1.0);
复制代码 标量与数构成员相乘、向量与向量成员相乘示例:
- // multiplies the second element of floatArray by 3.14
- float f = floatArray[1] * 3.14;
- // multiplies the first element of vec4Array by vec4(1.0, 2.0, 3.0, 4.0);
- vec4 v4 = vec4Array[0] * vec4(1.0, 2.0, 3.0, 4.0);
复制代码 采样器
webgl支持两种范例的采样器,分别为sampler2D和samplerCube用来存储纹理对象。使用纹理对象应该定义为uniform范例,如下:
- uniform sampler2D u_Sampler;
复制代码 在转达纹理到纹理单位时,使用如下代码,第2个参数为纹理单位序号,序号从0到7。
- gl.uniform1i(u_Sampler, 0);
复制代码 操作符优先级
条件控制流与迭代器
if语句用法同C,其规范如下:
- if (conditional-expression1) {
- commands here are executed if conditional-expression1 is true.
- } else if (conditional-expression2) {
- commands here are executed if conditional-expression1 is false but
- conditionalexpression2 is true.
- } else {
- commands here are executed if conditional-expression1 is false and
- conditionalexpression2 is false.
- }
复制代码 for语句用法同C,其规范如下:
- for (for-init-statement; conditional-expression; loop-index-expression) {
- the commands which you want to execute repeatedly.
- }
复制代码 同样也支持continue和break语句。不支持while和do...while语句。也不支持case语句。
函数
函数的一样寻常定义如下:
- returnType functionName(type0 arg0, type1 arg1, ..., typen argn) {
- do some computation
- return returnValue;
- }
复制代码 当函数无返回值时,定义返回范例void。当函数无参数时,参数列表定义为void。
原型声明
同C语言一样,被调函数原型定义在主调函数前面时,才能在主调函数背面出现被调函数的定义。如下代码:
- float luma(vec4); // a prototype declaration
- main() {
- ...
- float brightness = luma(color); // luma() is called before it is defined.
- ...
- }
- float luma (vec4 color) {
- return 0.2126 * color.r + 0.7162 * color.g + 0.0722 * color.b;
- }
复制代码 参数限定符
参数限定符包括:
- in 转达进一个值到函数,可修改,但不影响主调函数
- const in 转达进一个值到函数,不可修改
- out 从函数转达出一个值到被调函数,类似引用转达
- inout 既能转达进函数也能转达出函数,类似引用转达
代码示例:主调函数
- luma2(color, brightness); // the result is stored into "brightness"
- // same as brightness = luma(color)
复制代码 被调函数:
- void luma2 (in vec3 color, out float brightness) {
- brightness = 0.2126 * color.r + 0.7162 * color.g + 0.0722 * color.b;
- }
复制代码 这里从主调函数输入vec3范例的变量color,在函数内部盘算后通过out限定符定义的brightness转达出函数,转达给主调函数的brightness。
内置函数
全局变量与局部变量
同C语言,函数内部是局部变量,函数外部是全局变量。
存储限定符
属性变量,同一变量,可变变量三个存储限定符在webgl中的表现图
const常量
类似C语言,常量存储限定符,示例代码如下,常量初始化,初始化后不可变更:
- const int lightspeed = 299792458; // light speed (m/s)
- const vec4 red = vec4(1.0, 0.0, 0.0, 1.0); // red
- const mat4 identity = mat4(1.0); // identity matrix
复制代码 attribute变量
属性变量必须定义为全局变量,通过它可以将顶点坐标转达给顶点着色器。同样,属性变量支持向量和矩阵范例,如下:
- attribute vec4 a_Color;
- attribute float a_PointSize;
复制代码 本质上,属性变量、同一变量、可变变量的数量不能无穷制使用,但有一个最小支持量,如下:
uniform变量
同一变量是只读的,不可变更转达进来的值。它既可以放在顶点着色器中也可以放在片段着色器中。另外,同一变量可定义为局部变量也可以定义为全局变量。
如果在片段着色器中使用了和顶点着色中相同名称的同一变量,其存储数据将被两个着色器共享。
下面为定义同一变量示例:
- uniform mat4 u_ViewMatrix;
- uniform vec3 u_LightPosition;
复制代码 varying变量
可变变量必须定义为全局变量。在变量名称相同的情况下,可以使用它将数据从顶点着色器转达到片段着色器中。示例如下:
- varying vec2 v_TexCoord;
- varying vec4 v_Color;
复制代码 精度限定符
为了提高服从及节流存储成本、电池耗电量等原因,可限定属范例的精度。存储精度分为三级:highp、mediump、lowp。定义的方法如下:
- #ifdef GL_ES
- precision mediump float;
- #endif
复制代码 三种精度限定符所表现的范围如下:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |