ThreeJS 着色器编程基础入门

4 阅读3分钟

本文档涵盖Three.js中着色器编程的基础概念和实现方法,基于实际代码示例进行讲解。

最终效果如图: 懂王在风中凌乱

1. 着色器基础概念

着色器(Shader)是运行在GPU上的小程序,用于计算3D场景中每个像素的颜色。在Three.js中,有两种主要的着色器:

  • 顶点着色器(Vertex Shader):处理每个顶点的位置变换
  • 片元着色器(Fragment Shader):确定每个像素的最终颜色

1.1 着色器导入和初始化

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as dat from "dat.gui";

// 顶点着色器
import basicVertexShader from "../shader/raw/vertex.glsl";
// 片元着色器
import basicFragmentShader from "../shader/raw/fragment.glsl";

2. 着色器材质创建

2.1 RawShaderMaterial vs ShaderMaterial

RawShaderMaterial直接使用GLSL代码,不会自动添加默认的uniforms和attributes:

// 创建原始着色器材质
const rawShaderMaterial = new THREE.RawShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader,
  side: THREE.DoubleSide,
  uniforms: {
    uTime: {
      value: 0,
    },
    uTexture: {
      value: texture,
    },
  },
});

2.2 基础着色器材质

// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: `
    void main(){
        gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
    }
  `,
  fragmentShader: `
    void main(){
        gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
    }
  `,
});

3. 顶点着色器详解

顶点着色器负责处理3D空间中的顶点位置,以下是一个包含动画效果的顶点着色器:

precision lowp float;
attribute vec3 position;
attribute vec2 uv;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

// 获取时间
uniform float uTime;

varying vec2 vUv;
varying float vElevation;

void main(){
    vUv = uv;
    vec4 modelPosition = modelMatrix * vec4( position, 1.0 );
    
    // 添加基于时间的波浪动画
    modelPosition.z = sin((modelPosition.x+uTime) * 10.0)*0.05 ;
    modelPosition.z += sin((modelPosition.y+uTime)  * 10.0)*0.05 ;
    vElevation = modelPosition.z;

    gl_Position = projectionMatrix * viewMatrix * modelPosition ;
}

4. 片元着色器详解

片元着色器负责确定每个像素的颜色,以下是一个处理纹理和高度的片元着色器:

precision lowp float;
varying vec2 vUv;
varying float vElevation;

uniform sampler2D uTexture; 

void main(){
    // 根据UV,取出对应的颜色
    float height = vElevation + 0.05 * 20.0;
    vec4 textureColor = texture2D(uTexture,vUv);
    textureColor.rgb*=height;
    gl_FragColor = textureColor;
}

5. Uniforms统一变量

Uniforms是在JavaScript代码和着色器之间传递数据的变量:

const rawShaderMaterial = new THREE.RawShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader,
  side: THREE.DoubleSide,
  uniforms: {
    uTime: {
      value: 0,  // 时间变量,用于动画
    },
    uTexture: {
      value: texture,  // 纹理变量
    },
  },
});

在动画循环中更新uniform值:

const clock = new THREE.Clock();
function animate(t) {
  const elapsedTime = clock.getElapsedTime();
  // 更新着色器中的时间uniform
  rawShaderMaterial.uniforms.uTime.value = elapsedTime;
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

6. 几何体与着色器结合

使用平面几何体展示着色器效果:

// 创建平面
const floor = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1, 64, 64),  // 细分更多,波浪效果更明显
  rawShaderMaterial
);

scene.add(floor);

7. 基础着色器示例

创建一个简单的黄色平面着色器:

// 创建基础着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: `
    void main(){
        gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
    }
  `,
  fragmentShader: `
    void main(){
        gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);  // 黄色
    }
  `,
});

8. 着色器开发最佳实践

  1. 精度声明:在片元着色器中声明精度

    precision lowp float;  // 低精度
    precision mediump float;  // 中等精度
    precision highp float;  // 高精度
    
  2. 变量类型

    • attribute:每个顶点独有的数据(如位置、UV坐标)
    • uniform:所有顶点共享的数据(如时间、纹理)
    • varying:在顶点着色器和片元着色器之间传递的数据
  3. 性能优化:避免在着色器中使用复杂运算,尽可能在CPU端预计算

  4. 调试技巧:通过将中间计算结果输出到颜色来调试着色器

总结

本章介绍了Three.js中着色器编程的基础知识,包括:

  1. 着色器的基本概念和类型
  2. 如何创建和使用着色器材质
  3. 顶点着色器和片元着色器的编写
  4. 如何通过uniforms在JavaScript和着色器间传递数据
  5. 基础的着色器动画实现

通过掌握这些基础知识,可以进一步探索更复杂的着色器效果。