学习渲染器的时候,往往很是困惑,今天偶有所得,写出来给大家分享一下,适合初学者,直接上代码,通过代码里的注释学习,最直接有效。随便找个编辑器,写一个HTML文件,内容如下
<html>
<head>
<title>WebGL - Simple triangle</title>
</head>
<body onload="InitDemo();">
<canvas id="game-surface" width="800" height="600">
Your browser does not support HTML5
</canvas>
<br />
<i>Demo is above this text</i>
<script src="app.js"></script>
</body>
</html>
这个html再简单不过了,包含一个app.js文件,页面加载时,调用app.js里的InitDemo方法,下面贴上 app.js的代码
/*
顶点着色器: 一般负责位置,需要更新的值是 gl_Position
片元着色器: 一般负责颜色,需要更新的值是 gl_FragColor
本例:把属性都定义在顶点着色器中,通过varying这个指定来传递fragColor值
*/
var vertexShaderText =
[
'precision mediump float;',
'',
'attribute vec2 vertPosition;',
'attribute vec3 vertColor;',
'varying vec3 fragColor;',
'',
'void main()',
'{',
' fragColor = vertColor;',
' gl_Position = vec4(vertPosition, 0.0, 1.0);',
'}'
].join('\n');
var fragmentShaderText =
[
'precision mediump float;',
'',
'varying vec3 fragColor;',
'void main()',
'{',
' gl_FragColor = vec4(fragColor, 1.0);',
'}'
].join('\n');
var InitDemo = function () {
console.log('This is working');
// Step 1: 创建GL,通过html的canvas元素创建gl上下文。
var canvas = document.getElementById('game-surface');
var gl = canvas.getContext('webgl');
if (!gl) {
console.log('WebGL not supported, falling back on experimental-webgl');
gl = canvas.getContext('experimental-webgl');
}
if (!gl) {
alert('Your browser does not support WebGL');
}
gl.clearColor(0.75, 0.85, 0.8, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Step 2:创建着色器,作用是建立着色器定义与gl之间的关联
// 以下这段代码基本都比较固定,不会有多少变化,有两个动作
// 1、创建着色器:读取着色器定义,编译,
// 2、创建程序:着色器绑定程序,验证有效性。
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, vertexShaderText);
gl.shaderSource(fragmentShader, fragmentShaderText);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.error('ERROR compiling vertex shader!', gl.getShaderInfoLog(vertexShader));
return;
}
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.error('ERROR compiling fragment shader!', gl.getShaderInfoLog(fragmentShader));
return;
}
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('ERROR linking program!', gl.getProgramInfoLog(program));
return;
}
gl.validateProgram(program);
if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) {
console.error('ERROR validating program!', gl.getProgramInfoLog(program));
return;
}
// Step 3:创建数据缓存,这一步是关键。也比较难懂,这一步是要打通着色器里定义的属性与这里定义
// 的缓存数据之间的连接,关键点是通过gl获取着色器里定义的属性变量的指针,让它指向缓存数据的正确
// 位置。
// triangleVertices说明:你可以按照你的方式组织数据,这里的数据是指定一个顶点,接着指定其颜色
// 一个顶点数据包括x,y两个值;颜色有R、G、B规定其颜色,这样的说明你要在接下来的调用里通过代码告诉
// gl。另外一点,gl里指定的坐标点:都是0到1之间的值,可以认为画布中心点是(0,0)点,如下所示:
// (-1,1) -------- (1,1)
// | | |
// | | |
// |----- (0,0) --- |
// | | |
// | | |
// (-1,-1)---------(1,-1)
var triangleVertices =
[ // X, Y, R, G, B
0.0, 0.5, 1.0, 1.0, 0.0,
-0.5, -0.5, 0.7, 0.0, 1.0,
0.5, -0.5, 0.1, 1.0, 0.6
];
// 以下两个结构可以打开注释,试试结果
// var triangleVertices =
// [ // X, Y, R, G, B
// 0.0, 1.0, 1.0, 1.0, 0.0,
// -1.0, -1.0, 0.7, 0.0, 1.0,
// 1.0, -1.0, 0.1, 1.0, 0.6
// ];
// var triangleVertices = [
// -1, 1, 1.0, 1.0, 0.0,
// -1, -1, 0.7, 0.0, 1.0,
// 1, -1, 0.1, 1.0, 0.6,
// -1, 1, 1.0, 1.0, 0.0,
// 1, 1, 0.2, 0.5, 1.0,
// 1, -1, 0.1, 1.0, 0.6
// ];
var triangleVertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
// 获取属性变量的位置指针
var positionAttribLocation = gl.getAttribLocation(program, 'vertPosition');
var colorAttribLocation = gl.getAttribLocation(program, 'vertColor');
// 绑定数据
gl.vertexAttribPointer(
positionAttribLocation, // 属性位置指针
2, // 一个 vertPosition 属性包含两个元素
gl.FLOAT, // 元素类型
gl.FALSE,
5 * Float32Array.BYTES_PER_ELEMENT, // 两个完整元素起始点之间的跨距,所以是5
0 // 第一个元素读取的位置,也可以认为是偏移。
);
gl.vertexAttribPointer(
colorAttribLocation, // 属性位置指针
3, // 一个 vertColor 属性包含三个元素
gl.FLOAT, // 元素类型
gl.FALSE,
5 * Float32Array.BYTES_PER_ELEMENT, // 两个完整元素起始点之间的跨距,所以是5
2 * Float32Array.BYTES_PER_ELEMENT // 第一个元素读取的位置,也可以认为是偏移。这里是2,从第三个元素开始取。
);
gl.enableVertexAttribArray(positionAttribLocation);
gl.enableVertexAttribArray(colorAttribLocation);
//
// Step 4:渲染
//
gl.useProgram(program);
gl.drawArrays(gl.TRIANGLES, 0, 3);
};
打开一个浏览器,运行html文件,效果如下:
如果使用代码里另外两个数据缓存,效果如下:
以上已经在代码中解释清楚,希望对初学者有帮助!