Three.js 着色器使用教程:进阶指南

在 Three.js 的三维场景构建中,着色器(Shader)是极为强大的工具,能显著提升场景渲染效果,创造独特视觉体验。本文假定你已掌握 Three.js 基础,将深入探讨着色器在 Three.js 中的运用。

理解着色器

着色器是运行在 GPU 上的小程序,分为顶点着色器(Vertex Shader)和片段着色器(Fragment Shader)。顶点着色器处理几何体顶点,常用于控制物体形状、位置和方向;片段着色器处理每个像素颜色,决定物体表面最终呈现颜色。在 Three.js 中,通过自定义着色器可实现复杂光影效果、材质模拟等。

在 Three.js 中使用自定义着色器

1. 创建着色器材质

使用ShaderMaterial类创建自定义着色器材质。需提供顶点着色器和片段着色器代码字符串。

js 复制代码
const vertexShader = `
    void main() {
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
`;
const fragmentShader = `
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
`;
const shaderMaterial = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader
});

上述代码中,顶点着色器仅进行常规坐标变换,将顶点位置转换到屏幕空间。片段着色器将所有像素设置为红色。

2. 应用材质到几何体

将创建的ShaderMaterial应用到几何体上,与使用普通材质类似。

js 复制代码
const geometry = new THREE.BoxGeometry(1, 1, 1);
const mesh = new THREE.Mesh(geometry, shaderMaterial);
scene.add(mesh);

此时,场景中立方体将呈现红色。

示例:实现简单的渐变效果

修改片段着色器实现从顶部蓝色到底部绿色的渐变效果。

js 复制代码
const vertexShader = `
    void main() {
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
`;
const fragmentShader = `
    varying vec2 vUv;
    void main() {
        vec4 topColor = vec4(0.0, 0.0, 1.0, 1.0);
        vec4 bottomColor = vec4(0.0, 1.0, 0.0, 1.0);
        float interpolate = vUv.y;
        gl_FragColor = mix(topColor, bottomColor, interpolate);
    }
`;
const shaderMaterial = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader
});
// 在顶点着色器中传递纹理坐标
const geometry = new THREE.BoxGeometry(1, 1, 1);
geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array([
    0, 0,  1, 0,  1, 1,  0, 1
]), 2));
const mesh = new THREE.Mesh(geometry, shaderMaterial);
scene.add(mesh);

这里,在顶点着色器中未做太多修改。片段着色器引入vUv变量(用于存储纹理坐标),通过vUv.y值(范围 0 - 1)对顶部蓝色和底部绿色进行线性插值,实现渐变效果。需注意,要为几何体设置uv属性传递纹理坐标信息。

传递 Uniform 变量

Uniform 变量是在着色器中可在每一帧更新的全局变量。如传递时间变量实现动画效果。

js 复制代码
const vertexShader = `
    uniform float time;
    void main() {
        vec3 newPosition = position;
        newPosition.y += sin(time + position.x) * 0.2;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
    }
`;
const fragmentShader = `
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
`;
const shaderMaterial = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader,
    uniforms: {
        time: { value: 0 }
    }
});
function animate() {
    requestAnimationFrame(animate);
    shaderMaterial.uniforms.time.value += 0.05;
    renderer.render(scene, camera);
}
animate();

在上述代码中,顶点着色器引入time uniform 变量,根据时间和顶点x坐标修改顶点y坐标,实现波浪状动画效果。在animate函数中每一帧更新time uniform 变量值。

总结

通过上述示例,你了解了在 Three.js 中创建和使用自定义着色器、实现渐变效果及传递 uniform 变量。着色器功能强大,可实现复杂材质、光影和动画效果。深入研究着色器语言(GLSL)语法和特性,能为 Three.js 场景开发带来更多创意和可能。

相关推荐
JieE21211 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
runnerdancer11 小时前
LLM是怎么处理messages数组的,提示词缓存又是什么
前端·agent
陈随易12 小时前
VSCode的Copilot扩展支持接入DeepSeek,Kimi了!
前端·后端·程序员
我不是外星人14 小时前
有了 Harness Engineering ,真的还需要研发工程师吗?
前端·后端·ai编程
candyTong14 小时前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
IT_陈寒16 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
Jackson__17 小时前
分享一个横向滚动案例,带悬停暂停,通用性很强
前端
MariaH18 小时前
git rebase的使用
前端
_柳青杨18 小时前
深入理解 JavaScript 事件循环
前端·javascript
阡陌Jony18 小时前
关于前端性能优化的一些问题:
前端