书本源代码 https://download.csdn.net/download/qfire/10371055
2009年,Khronos建立了WebGL工作小组,开始基于OpenGL ES着手建立WebGL规范,并于2011年发布了WebGL规范的第1个版本。本书主要基于第1版的WebGL规范编写,后续更新目前都是以草案的形式发布,如有需要,也可参考。www.khronos.org/registry/webgl/specs/1.0/
1.1 WebGL程序的结构
1.2 Canvas是什么?
在HTML5出现之前,如果你想在网页上显示图像,只能使用HTML提供的原生方案<img>标签。用这个标签显示图像虽然简单,但只能显示静态的图片,不能进行实时绘制和渲染。因此,后来出现了一些第三方解决方案,如Flash Player等。HTML5的出现改变了一切,它引入了<canvas>标签,允许JavaScript动态绘制图形。
实例
清空
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Clear canvas</title>
</head>
<body οnlοad="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>
function main() {
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if (!gl) {
console.log("Failed to get the rendering context for WebGL");
return;
}
//RGBA
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//清空
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制点
//gl.drawColor(1.0, 0.0, 0.0, 1.0);
gl.drawPoint(0, 0, 0, 10); //点的位置和大小
}
绘制一个10个像素大的红色的点,WebGL处理的是三维图形,所以我们有必要为这个点指定三维坐标。
WebGL依赖于一种新的称为着色器的绘图机制。着色器提供了灵魂且强大的绘制二维或三维图形的方法,所有WebGL程序必须使用它。着色器不仅强大,而且更复杂,仅仅通过一条简单的绘图命令是不能操作它的。
//顶点着色器程序
var VSHADER_SOURCE =
'void main() {\n' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n' + //设置坐标
' gl_PointSize = 10.0; \n' + //设置尺寸
'}\n';
//片元着色器程序
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + //设置颜色
'}\n';
function main() {
var canvas = document.getElementById('webgl');
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 ;
}
//RGBA
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//清空
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制点
gl.drawArrays(gl.POINTS, 0, 1); //点的位置和大小
}
WebGL需要两种着色器。
- 顶点着色器(Vertex shader):顶点着色器是用来描述顶点特性(如位置、颜色等)的程序。
- 片元着色器(Fragment shader):进行逐片元处理过程如光照的程序。片元是一个WebGL术语,你可以将其理解为像素。
vec4(x, y, z, w);齐次坐标(x, y, z, w)等价于三维坐标(x/w, y/w, z/w),齐次坐标的存在,使得用矩阵乘法来描述顶点变换成为可能,三维图形系统在计算过程中,通常使用齐次坐标来表示顶点的三维坐标。
gl.drawArrays()可以用来绘制各种图形
1.3 WebGL坐标系统
' gl_Position = vec4(0.5, 0.5, 0.0, 1.0); \n' + //设置坐标
' gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n' + //设置颜色
注:WebGL不需要交换颜色缓冲区
1.4 绘制一点实例
将位置信息从JavaScript程序中传给顶点着色器。有两种方式可以做到:attribute变量和uniform变量。attribute变量传输的是那些与顶点相关的数据,而uniform变量传输的是那些对于所有顶点都相同(或与顶点无关)的数据。
//顶点着色器程序
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position; \n' + //设置坐标
' gl_PointSize = 10.0; \n' + //设置尺寸
'}\n';
//片元着色器程序
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n' + //设置颜色
'}\n';
function main() {
var canvas = document.getElementById('webgl');
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 ;
}
//获取attribute变量的存储位置
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.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
//RGBA
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//清空
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制点
gl.drawArrays(gl.POINTS, 0, 1); //点的位置和大小
}
![](https://i-blog.csdnimg.cn/blog_migrate/9c0334b235d0a61dd28d69f86e88509c.png)
//顶点着色器程序
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position; \n' + //设置坐标
' gl_PointSize = 10.0; \n' + //设置尺寸
'}\n';
//片元着色器程序
var FSHADER_SOURCE =
'precision mediump float;\n' +
'uniform vec4 u_FragColor;\n' + //uniform变量
'void main() {\n' +
' gl_FragColor = u_FragColor;\n' + //设置颜色
'}\n';
function main() {
var canvas = document.getElementById('webgl');
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 ;
}
//获取attribute变量的存储位置
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 u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
if (u_FragColor < 0) {
console.log("failed to get the storage location of u_FragColor");
return;
}
//注册鼠标
canvas.onmousedown = function(ev) { click(ev, gl, canvas, a_Position, u_FragColor)};
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
//RGBA
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//清空
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制点
//gl.drawArrays(gl.POINTS, 0, 1); //点的位置和大小
}
var g_points = []; //
var g_colors = [];
function click(ev, gl, canvas, a_Position, u_FragColor) {
var x = ev.clientX;
var y = ev.clientY;
var rect = ev.target.getBoundingClientRect();
x = ((x-rect.left) - canvas.width/2)/(canvas.width/2);
y = (canvas.height/2 - (y-rect.top))/(canvas.height/2);
//将坐标存储到g_points数组中
g_points.push([x, y]);
//将点的颜色存储到g_colors数组中
if (x >= 0.0 && y >= 0.0) { //第一象限
g_colors.push([1.0, 0.0, 0.0, 1.0]); //红色
} else if (x < 0.0 && y < 0.0) { // 第三象限
g_colors.push([0.0, 1.0, 0.0, 1.0]); //绿色
} else {
g_colors.push([1.0, 1.0, 1.0, 1.0]); //白色
}
//清空
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];
//将点的位置传输到a_Position变量中
gl.vertexAttrib3f(a_Position, xy[0], xy[1], 0.0);
//将点的颜色传输到u_FragColor变量中
gl.uniform4f(u_FragColor, rgba[0], rgba[1], rgba[2], rgba[3]);
//绘制点
gl.drawArrays(gl.POINTS, 0, 1);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/300be74f7101b8b1977b844037381687.png)