参考文档:Learn OpenGL, extensive tutorial resource for learning Modern OpenGL
MDN:使用着色器将颜色应用于 WebGL - Web API | MDN (mozilla.org)
李伟的博客:李伟的博客 (yxyy.name)
李伟课件地址:buglas/webgl-lesson (github.com)
1. GLSL 基础语法
GLSL(OpenGL Shading Language)是一种专门用于编写着色器的编程语言。它的语法与 C 语言非常相似,包括数据类型、变量声明、控制结构等。
-
数据类型:GLSL 支持多种基本数据类型,包括标量类型(如
float
,int
,bool
)以及向量和矩阵类型(如vec2
,vec3
,mat4
)。 -
控制结构:GLSL 支持常见的控制结构,如
if-else
,for
,while
。
2. 顶点着色器
顶点着色器(Vertex Shader)负责处理每个顶点的属性数据,例如位置、法线、颜色等。在 Cesium 中,你通常会通过 JavaScript 将顶点数据传递给顶点着色器。
-
属性(attribute):用于从外部传递给顶点着色器的每个顶点的数据。
attribute vec3 position;
uniform mat4 modelViewProjectionMatrix;
void main() {
gl_Position = modelViewProjectionMatrix * vec4(position, 1.0);
}
attribute 变量是只有顶点着色器才能使用它的。
js 可以通过attribute 变量向顶点着色器传递与顶点相关的数据。
- 在顶点着色器中声明attribute 变量。
- 在js中获取attribute 变量
- 修改attribute 变量
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
void main(){
gl_Position = a_Position;
gl_PointSize = 50.0;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
</script>
<script type="module">
import {initShaders} from '../jsm/Utils.js';
const canvas = document.getElementById('canvas');
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;
const gl = canvas.getContext('webgl');
const vsSource = document.getElementById('vertexShader').innerText;
const fsSource = document.getElementById('fragmentShader').innerText;
initShaders(gl, vsSource, fsSource);
const a_Position=gl.getAttribLocation(gl.program,'a_Position');
gl.vertexAttrib3f(a_Position,0.0,0.0,0.0);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 1);
</script>
-
统一变量(uniform):用于从应用程序(例如 JavaScript)传递给着色器的全局数据,在渲染过程中不改变。
uniform mat4 modelMatrix;
3. 片元着色器
片元着色器(Fragment Shader)负责计算每个片元(像素)的颜色,并将结果输出到屏幕。
-
颜色计算:片元着色器用于计算颜色值,通常与光照计算和纹理映射有关。
-
纹理映射:片元着色器可以使用纹理(texture)来生成复杂的图像效果。
uniform sampler2D texture;
varying vec2 texCoords;
void main() {
gl_FragColor = texture2D(texture, texCoords);
}
4. 深度和模板测试
深度测试(Depth Test)和模板测试(Stencil Test)用于决定片元是否应该被绘制。深度测试确保只有最近的物体被绘制,模板测试则可以用来创建复杂的剪切效果。
-
深度测试:比较片元的深度值来决定是否覆盖当前深度缓冲中的值。
-
模板测试:使用模板缓冲区来决定是否绘制片元。
5. 纹理处理
纹理,通常指的就是二维的栅格图像,我们可以将其作为webgl图形的贴图。纹理,就是属于图像,其图像的建立和显示会遵循栅格系统里的规范。比如,所有图像都是由像素组成的,在webgl里我们把像素称为片元,像素是按照相互垂直的行列排列的。
纹理处理在 GLSL 中非常重要,尤其是在实现视觉效果和数据处理时。例如,你可以使用深度纹理来进行深度缓冲区的操作。
-
采样器:GLSL 中的采样器对象用于访问纹理数据。
uniform sampler2D myTexture;
- 深度纹理:用于存储深度信息,通常用于阴影映射和可视性分析。
uniform sampler2DShadow shadowMap;
6. 矩阵和向量操作
在 GLSL 中,矩阵和向量操作非常常见,尤其是在处理 3D 图形时。例如,你需要使用矩阵来进行模型变换、视图变换和投影变换。
-
向量操作:
vec3 normal = normalize(vec3(0.0, 1.0, 0.0));
-
矩阵操作:
mat4 modelViewMatrix = viewMatrix * modelMatrix;
vec4 transformedVertex = modelViewMatrix * vec4(position, 1.0);