three ShaderMaterial 着色器材质

71 阅读4分钟

clipping 在使用 裁剪时要注意这个属性需要众uniforms 中传入剪切平面然后在片元着色器中计算是否渲染

defaultAttributeValues 这个属性用来定义顶点着色器与片元着色器的默认值

defines 预处理器 用来处理顶点着色器与片元着色器中预定义值

ShaderMaterial 有十九个属性 一个方法

  • clipping 定义此材质是否支持剪裁; 如果渲染器传递clippingPlanes uniform,则为true。默认值为false。
    // 创建裁剪平面,位置为 Y=0
    const clipPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
    const planeHelper = new THREE.PlaneHelper(clipPlane, 10, 0xff0000);
    scene.add(planeHelper);
    // 创建一个 ShaderMaterial
    const material = new THREE.ShaderMaterial({
        uniforms: {
            color: { value: new THREE.Color(0xff0000) },
            clipPlane: { value: new THREE.Vector4(clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.constant) } // 将裁剪平面传递给着色器
        },
        vertexShader: `
            varying vec3 vPosition;
            void main() {
                vPosition = position;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        `,
        fragmentShader: `
            uniform vec3 color;
            uniform vec4 clipPlane;  // 接收裁剪平面
            varying vec3 vPosition;
            void main() {
                // 裁剪逻辑
                if (dot(vPosition, clipPlane.xyz) + clipPlane.w < 0.0) {
                    discard;  // 丢弃片元
                }
                gl_FragColor = vec4(color, 1.0);
            }
        `,
        clipping: true,  // 启用材质的裁剪功能
        clipShadows: true  // 剪裁时处理阴影
    });
    // 创建几何体和网格
    const geometry = new THREE.BoxGeometry(5, 5, 5);
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
  • defaultAttributeValues 当渲染的几何体不包含这些属性但材质包含这些属性时,这些默认值将传递给shaders。这可以避免在缓冲区数据丢失时出错。 这样就可以在着色器中调用设置的默认值
    const defaultAttributeValues = {
        'color': [ 1, 1, 1 ],
        'uv': [ 0, 0 ],
        'uv1': [ 0, 0 ]
    };
    
        // 创建自定义 ShaderMaterial
    const material = new THREE.ShaderMaterial({
        vertexShader: `
            attribute float customAttribute;
            void main() {
                vec3 transformed = position * customAttribute;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0);
            }
        `,
        fragmentShader: `
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
            }
        `,
        defaultAttributeValues: {
            customAttribute: [1.0] // 设置自定义属性的默认值为 1.0
        }
    });

    // 创建几何体和网格
    const geometry = new THREE.BoxGeometry(10, 10, 10);
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
  • defines 使用 #define 指令在GLSL代码为顶点着色器和片段着色器定义自定义常量;每个键/值对产生一行定义语句:
    defines: {
        FOO: 15,
        BAR: true
    }
    const material = new THREE.ShaderMaterial({
        vertexShader: `
            varying vec3 vPosition;
            void main() {
                vPosition = position;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        `,
        fragmentShader: `
            varying vec3 vPosition;
        #ifdef COLOR_RED
            const vec3 color = vec3(1.0, 0.0, 0.0); // 红色
        #elif defined(COLOR_GREEN)
            const vec3 color = vec3(0.0, 1.0, 0.0); // 绿色
        #else
            const vec3 color = vec3(0.0, 0.0, 1.0); // 蓝色
        #endif
            void main() {
                gl_FragColor = vec4(color, 1.0);
            }
        `,
        defines: {
            // 这里可以动态选择 COLOR_RED 或 COLOR_GREEN 来控制颜色
            COLOR_RED: true // 可以切换为 COLOR_GREEN
        }
    });
    // 创建几何体和网格
    const geometry = new THREE.BoxGeometry(10, 10, 10);
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    // 创建 OrbitControls
    const controls = new OrbitControls(camera, renderer.domElement);
    setTimeout(() => {
        // 切换为绿色
        material.defines = { COLOR_GREEN: true };
        material.needsUpdate = true; // 通知 Three.js 重新编译着色器
    }, 3000)
    setTimeout(() => {
        // 切换为绿色
        material.defines = { COLOR_GREEN: false };
        material.needsUpdate = true; // 通知 Three.js 重新编译着色器
    }, 8000)
  • extensions 一个有如下属性的对象:
    extensions = {
        clipCullDistance: false,// 设置为使用顶点着色器裁剪
        multiDraw: false // 设置为使用顶点着色器 multi_draw / 启用 gl_DrawID 
    };
  • fog 定义材质颜色是否受全局雾设置的影响; 如果将fog uniforms传递给shader,则为true。默认值为false。
  • fragmentShader 片元着色器的GLSL代码。这是shader程序的实际代码。在上面的例子中, vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。
  • glslVersion 定义自定义着色器代码的 GLSL 版本。有效值为 THREE.GLSL1 或 THREE.GLSL3。默认为空。
  • index0AttributeName 如果设置,则调用gl.bindAttribLocation 将通用顶点索引绑定到属性变量。默认值未定义
  • isShaderMaterial 用于检查给定对象是否属于 ShaderMaterial 类型的只读标志。
  • lights 材质是否受到光照的影响。默认值为 false。如果传递与光照相关的uniform数据到这个材质,则为true。默认是false。
  • linewidth 控制线框宽度。默认值为1。
  • flatShading 定义材质是否使用平面着色进行渲染。默认值为false。
  • uniforms 如下形式的对象:{ "uniform1": { value: 1.0 }, "uniform2": { value: 2 } }指定要传递给shader代码的uniforms;键为uniform的名称,值(value)是如下形式:
  • uniformsNeedUpdate 可用于在 Object3D.onBeforeRender() 中更改uniform时强制进行uniforms更新。默认为 false。
  • vertexColors 定义是否使用顶点着色。默认为 false。
  • vertexShader 顶点着色器的GLSL代码。这是shader程序的实际代码。 在上面的例子中,vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。
  • wireframe 将几何体渲染为线框(通过GL_LINES而不是GL_TRIANGLES)。默认值为false(即渲染为平面多边形)。
  • wireframeLinewidth 控制线框宽度。默认值为1。由于OpenGL Core Profile与大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。
  • clone 方法 创建该材质的一个浅拷贝。需要注意的是,vertexShader和fragmentShader使用引用拷贝; attributes 的定义也是如此; 这意味着,克隆的材质将共享相同的编译WebGLProgram; 但是,uniforms 是 值拷贝,这样对不同的材质我们可以有不同的uniforms变量。