three 原始着色器材质 RawShaderMaterial

112 阅读2分钟

RawShaderMaterial 这个材质没有私有属性,全部属性由材质基类与着色器材质属性 继承

RawShaderMaterial 可以让你在 Three.js 中直接编写自己的 GLSL(着色器语言)代码,以实现自定义的渲染效果。相比于 ShaderMaterial,RawShaderMaterial 不会自动处理一些默认的着色器内容,所有的逻辑都需要你自己编写。这为你提供了更大的灵活性,但也要求你对 WebGL 和 GLSL 有一定的理解。

Three.js 提供了很多现成的材质(如 MeshBasicMaterial, MeshStandardMaterial 等),这些材质内部封装了大量的渲染逻辑,开发者只需要简单设置参数即可。但有时,你可能希望实现一些特殊的渲染效果,这时 RawShaderMaterial 就非常有用。

这个材质最最要的是要了解顶点着色器与片元着色器

  • 在three 中所有的几何体 所有的几何体都是有三角形组成,而顶点是指的这些三角形,顶点着色器的 每一个顶点都会经过 顶点着色器的main计算位置? 下面是一个使用顶点着色器改变顶点位置的例子
  • 在three 中所有的颜色都经过 片元着色器中的 main 计算得出当前像素点的颜色值然后渲染出来,下面是一个使用片元着色器渲染像素的例子.
    // 立方体的 8 个顶点
    V0 = (1, 1, 1)
    V1 = (1, -1, 1)
    V2 = (-1, 1, 1)
    V3 = (-1, -1, 1)
    V4 = (1, 1, -1)
    V5 = (1, -1, -1)
    V6 = (-1, 1, -1)
    V7 = (-1, -1, -1)
    // 面 1:由顶点 V0、V1、V2 和 V2、V1、V3 组成。
    // 面 2:由顶点 V0、V4、V5 和 V0、V5、V1 组成。
    // (依此类推,为其他面定义三角形)

    const topPoint = ` 
        uniform float time;
        attribute vec3 position;
        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;
        void main() {
            // 基于顶点位置和时间的波动效果
            vec3 newPosition = position;
            newPosition.z += sin(newPosition.x * 4.0 + time) * 0.8; // X 方向上的波动
            newPosition.z += sin(newPosition.y * 4.0 + time) * 0.2; // Y 方向上的波动

            gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
        }
    `
    const colorFn = `
        void main() {
            gl_FragColor = vec4(0.3, 0.6, 1.0, 1.0); // 蓝色
        }
    `

    // 创建自定义的顶点和片元着色器材质
    const material = new THREE.RawShaderMaterial({
        vertexShader: topPoint,
        fragmentShader: colorFn,
        side: THREE.DoubleSide,
        uniforms: {
            time: { value: 0.0 }
        }
    });
    
        // 定义立方体的顶点
    const vertices = new Float32Array([
        1,  1,  1,   // V0
        1, -1,  1,   // V1
        -1,  1,  1,   // V2
        -1, -1,  1,   // V3
        1,  1, -1,   // V4
        1, -1, -1,   // V5
        -1,  1, -1,   // V6
        -1, -1, -1    // V7
    ]);

    // 定义立方体的面(每个面由两个三角形组成)
    const indices = new Uint16Array([
        0, 1, 2,  2, 1, 3, // 前面
        4, 5, 6,  6, 5, 7, // 后面
        0, 2, 4,  4, 2, 6, // 左面
        1, 5, 3,  3, 5, 7, // 右面
        2, 3, 6,  6, 3, 7, // 上面
        0, 4, 1,  1, 4, 5  // 下面
    ]);
    
    // 创建 BufferGeometry
    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
    geometry.setIndex(new THREE.BufferAttribute(indices, 1));

    // 创建网格并添加到场景中
    const mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);