2019 一个着色器Shader的代码剖析

学习渲染器的时候,往往很是困惑,今天偶有所得,写出来给大家分享一下,适合初学者,直接上代码,通过代码里的注释学习,最直接有效。随便找个编辑器,写一个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文件,效果如下:
在这里插入图片描述
如果使用代码里另外两个数据缓存,效果如下:
在这里插入图片描述
在这里插入图片描述
以上已经在代码中解释清楚,希望对初学者有帮助!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

科技与文明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值