返回

用GLSL编程实现动态彩色冲击波的动画效果

见解分享

  1. 准备工作

首先,我们需要准备一个GLSL着色器。着色器是一种程序,它可以在图形硬件上运行,以生成图像。我们将使用WebGL来实现我们的着色器,WebGL是一个JavaScript API,它允许我们在浏览器中运行GLSL着色器。

// 顶点着色器
const vertexShaderSource = `
  attribute vec4 a_position;

  void main() {
    gl_Position = a_position;
  }
`;

// 片段着色器
const fragmentShaderSource = `
  precision highp float;

  uniform float u_time;
  uniform vec2 u_resolution;

  void main() {
    // 计算圆形坐标
    vec2 position = gl_FragCoord.xy - 0.5 * u_resolution;
    float distance = length(position);

    // 计算颜色
    float color = 0.0;
    color += smoothstep(0.0, 0.1, distance);
    color += smoothstep(0.1, 0.2, distance);
    color += smoothstep(0.2, 0.3, distance);

    // 输出颜色
    gl_FragColor = vec4(color, color, color, 1.0);
  }
`;

2. 构建着色器程序

接下来,我们需要将顶点着色器和片段着色器组合成一个着色器程序。着色器程序是可以在图形硬件上运行的完整程序。

// 创建着色器程序
const program = gl.createProgram();

// 附加顶点着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
gl.attachShader(program, vertexShader);

// 附加片段着色器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
gl.attachShader(program, fragmentShader);

// 链接着色器程序
gl.linkProgram(program);

// 使用着色器程序
gl.useProgram(program);

3. 设置Uniform变量

现在,我们需要设置一些Uniform变量,这些变量可以在着色器程序中使用。Uniform变量是可以在着色器程序中访问的全局变量。

// 设置u_time变量
const u_timeLocation = gl.getUniformLocation(program, "u_time");
gl.uniform1f(u_timeLocation, 0.0);

// 设置u_resolution变量
const u_resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2fv(u_resolutionLocation, [gl.canvas.width, gl.canvas.height]);

4. 绘制图像

最后,我们可以使用着色器程序来绘制图像。

// 清空画布
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

// 绑定顶点数据
const vertices = new Float32Array([-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 绑定位置属性
const a_positionLocation = gl.getAttribLocation(program, "a_position");
gl.vertexAttribPointer(a_positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_positionLocation);

// 绘制图像
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);

5. 动画

为了实现动画,我们需要不断更新u_time变量的值。

function animate() {
  // 请求下一次动画帧
  requestAnimationFrame(animate);

  // 更新时间
  const time = Date.now() * 0.001;
  gl.uniform1f(u_timeLocation, time);

  // 绘制图像
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
}

// 启动动画
animate();

现在,你应该就可以看到一个动态的彩色冲击波动画效果了。