WebGL - 着色器:初学者指南
你好,有抱负的程序开发者们!今天,我们将踏上一段令人兴奋的旅程,探索 WebGL 着色器的世界。如果你以前从未写过一行代码,也不用担心——我将作为你的友好向导,带你游历这个计算机图形学的多彩景观。
着色器是什么?
在我们开始之前,让我们先了解一下着色器是什么。想象你正在画一幅画。画布是你的电脑屏幕,而着色器就像是神奇的画笔,告诉电脑如何为每个像素上色。酷吧?
数据类型
在着色器世界中,我们有一些特殊的数据类型来工作。让我们看看它们:
数据类型 | 描述 | 示例 |
---|---|---|
float | 单精度浮点数 | 3.14 |
vec2 | 二维向量 | vec2(1.0, 2.0) |
vec3 | 三维向量 | vec3(1.0, 2.0, 3.0) |
vec4 | 四维向量 | vec4(1.0, 2.0, 3.0, 4.0) |
mat2 | 2x2 矩阵 | mat2(1.0, 2.0, 3.0, 4.0) |
mat3 | 3x3 矩阵 | mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0) |
mat4 | 4x4 矩阵 | 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) |
如果这些看起来让你觉得不知所措,别担心——我们会一步一步地使用它们!
限定符
限定符就像是我们放在变量上的特殊标签。它们告诉着色器如何处理这些变量。这里有几个主要的限定符:
限定符 | 描述 |
---|---|
attribute | 每个顶点变化的输入值 |
uniform | 对所有顶点都保持不变的输入值 |
varying | 从顶点着色器传递到片段着色器的值 |
顶点着色器
顶点着色器就像是我们 3D 模型的骨架。它计算出我们的模型中的每个点(顶点)应该位于屏幕上的哪个位置。下面是一个简单的顶点着色器:
attribute vec3 aVertexPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
}
让我们分解一下:
- 我们声明了一个名为
aVertexPosition
的attribute
—— 这是我们的顶点的位置。 - 我们有两个
uniform
矩阵 —— 这些帮助我们定位并将我们的 3D 模型投影到 2D 屏幕上。 - 在
main
函数中,我们计算出我们的顶点的最终位置。
片段着色器
如果顶点着色器是骨架,片段着色器就是皮肤。它决定了每个像素的颜色。下面是一个简单的片段着色器:
precision mediump float;
void main(void) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
这个着色器将所有东西都涂成了红色!vec4(1.0, 0.0, 0.0, 1.0)
表示全红、无绿、无蓝和全不透明。
存储和编译着色器程序
现在我们已经写好了我们的着色器,我们需要告诉 WebGL 关于它们的信息。以下是如何在 JavaScript 中做到这一点的:
function getShader(gl, id) {
const shaderScript = document.getElementById(id);
if (!shaderScript) return null;
const str = shaderScript.text;
let shader;
if (shaderScript.type === "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type === "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
这个函数做了几件事:
- 它在 HTML 文档中找到我们的着色器代码。
- 它创建了一个正确类型的着色器(顶点或片段)。
- 它编译着色器并检查错误。
组合程序
最后,我们需要将我们的顶点和片段着色器组合成一个程序:
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("无法初始化着色器");
}
gl.useProgram(shaderProgram);
这段代码创建了一个程序,附加了我们的着色器,链接了程序,并告诉 WebGL 使用它。
就这样!你已经迈出了进入 WebGL 着色器世界的第一步。记住,就像学习任何新语言一样,这需要练习。如果一开始不太明白,不要气馁——继续尝试,很快你就能在网页浏览器中创建惊人的 3D 图形了!
在我教学的这些年里,我见证了无数学生从完全的初学者成长为着色器大师。我的一个学生甚至使用这些技能为她的毕业项目创建了一个虚拟艺术画廊——想象一下,在网页浏览器中漫步于 3D 博物馆!
那么,你会用你的新着色器技能创造什么呢?唯一限制你的,就是你的想象力!祝编码愉快,未来的图形大师们!
Credits: Image by storyset