跳到主要内容
3D Playground
WebGL 与着色器第 3 / 12 节

Uniform:让着色器动起来

入门WebGL 2

什么是 uniform

attribute 每个顶点不同,uniform 则在一次绘制调用内对所有顶点和片元都相同。它是 CPU 给 GPU 传参数的主要方式:时间、画布尺寸、鼠标位置、颜色、矩阵……

glsl
uniform float u_time;        // 秒
uniform vec2  u_resolution;  // 画布像素尺寸
uniform vec2  u_mouse;       // 鼠标像素坐标(左下角为原点)

设置 uniform 的三步

  1. 链接后用 gl.getUniformLocation(program, "u_time") 查到位置。只查一次,把结果缓存起来。
  2. 绘制前先 gl.useProgram(program):uniform 属于当前程序。
  3. 用类型匹配的函数赋值:uniform1f、uniform2f、uniform3fv、uniform1i、uniformMatrix4fv……类型写错不会报错,只会静默失败。

本例用 gl.getActiveUniform 遍历程序里所有活跃的 uniform,自动建好查找表。注意:着色器里声明了但没用到的 uniform 会被编译器优化掉,查到的位置是 null。

三个经典 uniform

  • u_time 让一切动起来。花瓣半径是 sin(petals * angle + u_time * 2.0) 的函数,每帧只改一个数字,GPU 就重新算出所有顶点。
  • u_resolution 用来修正宽高比。裁剪空间永远是 -1 到 1 的正方形,把 x 乘以 高 / 宽,圆才不会被拉扁。
  • u_mouse 来自 pointermove 事件。DOM 的 y 轴向下,GL 的 y 轴向上,记得翻转,并乘上设备像素比。

不用缓冲区也能画

花朵的顶点完全由 gl_VertexID(当前是第几个顶点)计算出来:每 3 个顶点一个三角形,第 0 个在中心,另外两个在圆周上。WebGL2 只要求绑定一个 VAO,不需要任何 attribute。

glsl
int tri = gl_VertexID / 3, corner = gl_VertexID % 3;
把鼠标移到画布上,背景的光晕会跟着你:这就是 u_mouse 在片元着色器里的作用。

核心 API

gl.getUniformLocationgl.getActiveUniformgl.uniform1fgl.uniform2fgl.uniform3fvgl.uniform1igl_VertexID

动手试试

  1. 1把 u_petals 设为 0,花会变成什么?再试试 12。
  2. 2新增一个 uniform u_twist,让花瓣角度随半径扭转。
  3. 3删掉 p.x 乘以宽高比的那一行,然后改变窗口大小。
运行中