从零开始学习three.js(18):一文详解three.js中的着色器Shader

在WebGL和Three.js的3D图形渲染中,着色器(Shader) 是实现复杂视觉效果的核心工具。通过编写自定义的着色器代码,开发者可以直接操作GPU,实现从基础颜色渲染到动态光照、粒子效果等高级图形技术。本文将深入解析Three.js中着色器的核心概念、实现原理及实战应用,并结合代码示例帮助读者全面掌握这一关键技术。

核心特点​​:


一、着色器基础与分类

1.1 顶点着色器(Vertex Shader)

顶点着色器负责处理几何体的每个顶点,主要功能包括:

  • 顶点位置变换 :将模型空间坐标转换为屏幕空间坐标(通过 gl_Position 输出)

  • 顶点属性计算:如法线变换、纹理坐标传递等

    void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }

说明projectionMatrix(投影矩阵)、modelViewMatrix(模型视图矩阵)由Three.js自动注入,position是顶点的原始坐标。

1.2 片元着色器(Fragment Shader)

片元着色器决定每个像素的最终颜色,通过 gl_FragColor 输出:

复制代码
void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}

特性:颜色支持动态计算,如基于光照模型、纹理采样等。

1.3 着色器材质类型

Three.js提供两种自定义着色器材质:

  • ShaderMaterial ​:简化版材质,内置常用变量(如modelViewMatrixprojectionMatrix),适合快速开发。

  • RawShaderMaterial ​:需手动声明所有变量(如attributeuniform),灵活性更高,适合深度优化。

​示例代码:创建基础着色器材质​

复制代码
const material = new THREE.ShaderMaterial({  
  vertexShader: vertexShaderCode,  
  fragmentShader: fragmentShaderCode,  
  uniforms: {  
    time: { value: 0 },  
    color: { value: new THREE.Color(0xff0000) }  
  }  
});  

二、着色器变量类型

2.1 Uniforms

  • 全局常量:所有顶点/片元共享同一值(如时间、光源位置)

  • 传递方式 :通过 ShaderMaterialuniforms 属性设置

    const material = new THREE.ShaderMaterial({
    uniforms: {
    uTime: { value: 0 },
    uTexture: { value: new THREE.TextureLoader().load("texture.png") }
    }
    });

在着色器中声明uniform float uTime;

2.2 Attributes

  • 顶点属性:每个顶点独有的数据(如位置、颜色、法线)

  • 典型应用:动态顶点动画(如波浪效果)

    geometry.setAttribute('displacement', new THREE.BufferAttribute(displacementArray, 1));

在顶点着色器中访问attribute float displacement;

2.3 Varyings

  • 插值变量:从顶点着色器向片元着色器传递数据(如UV坐标、颜色插值)

    // 顶点着色器
    varying vec2 vUv;
    void main() {
    vUv = uv;
    // ...
    }

    // 片元着色器
    varying vec2 vUv;
    void main() {
    vec4 color = texture2D(uTexture, vUv);
    }

注意:变量名需在两者中保持一致。


三、矩阵变换与坐标系统

3.1 核心矩阵解析

  • 模型矩阵(modelMatrix) :几何体的旋转、平移、缩放变换
  • 视图矩阵(viewMatrix) :相机的观察变换(等同于相机世界矩阵的逆矩阵)
  • 投影矩阵(projectionMatrix) :3D到2D的投影(如透视投影)

3.2 矩阵乘法顺序

顶点变换遵循 "右乘"顺序,确保坐标正确转换:

复制代码
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);

原理:从模型空间→世界空间→相机空间→裁剪空间逐步变换。


四、实战案例:动态波纹效果

4.1 着色器代码实现

顶点着色器(传递UV坐标):

复制代码
varying vec2 vUv;
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

片元着色器(动态波纹计算):

复制代码
uniform float uTime;
varying vec2 vUv;

void main() {
    float ripple = sin(length(vUv - 0.5) * 10.0 - uTime * 2.0);
    float opacity = smoothstep(0.0, 0.2, abs(ripple));
    gl_FragColor = vec4(0.2, 0.5, 1.0, opacity);
}

4.2 JavaScript端配置

复制代码
const material = new THREE.ShaderMaterial({
    uniforms: {
        uTime: { value: 0 }
    },
    vertexShader: vertexShaderCode,
    fragmentShader: fragmentShaderCode,
    transparent: true
});

// 动画循环中更新Uniform
function animate() {
    material.uniforms.uTime.value += 0.01;
    requestAnimationFrame(animate);
}

效果:实现以中心向外扩散的蓝色波纹。


五、高级技巧与优化

5.1 性能优化策略

  1. 减少分支语句 :GPU不擅长动态分支,可用 mix()step() 替代 if-else
  2. 向量化运算 :优先使用 vec3/vec4 代替多个 float 计算
  3. 纹理压缩:使用Mipmap和纹理图集减少采样开销

5.2 常见问题排查

  • 变量未声明 :检查Three.js版本是否支持特定语法(如 #version 300 es
  • 精度问题 :在移动端明确指定精度(precision mediump float;
  • 矩阵顺序错误:确保模型→视图→投影的乘法顺序正确

六、扩展应用:后期处理通道

通过 EffectComposerShaderPass 实现屏幕后处理:

复制代码
import { EffectComposer, ShaderPass } from 'three/examples/jsm/postprocessing';

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));

const customPass = new ShaderPass(customShaderMaterial);
composer.addPass(customPass);

典型效果:模糊、Bloom光效、颜色校正等。


结语

Three.js着色器为开发者打开了高性能图形编程的大门。通过深入理解GLSL语法、矩阵变换和变量传递机制,可以创造出从基础颜色变化到复杂物理模拟的全方位视觉效果。建议通过Shadertoy平台进行实时演练,结合Three.js文档探索更多可能性。

相关推荐
p***h6431 小时前
JavaScript在Node.js中的异步编程
开发语言·javascript·node.js
N***73851 小时前
Vue网络编程详解
前端·javascript·vue.js
e***71671 小时前
Spring Boot项目接收前端参数的11种方式
前端·spring boot·后端
程序猿小蒜1 小时前
基于springboot的的学生干部管理系统开发与设计
java·前端·spring boot·后端·spring
银空飞羽1 小时前
让Trae CN SOLO自主发挥,看看能做出一个什么样的项目
前端·人工智能·trae
ndjnddjxn2 小时前
Rust学习
开发语言·学习·rust
菜鸟‍2 小时前
【后端学习】MySQL数据库
数据库·后端·学习·mysql
Eshine、2 小时前
解决前端项目中,浏览器无法正常加载带.gz名称的文件
前端·vue3·.gz·.gz名称的js文件无法被加载
陈天伟教授2 小时前
基于学习的人工智能(1)机器学习
人工智能·学习
im_AMBER2 小时前
Leetcode 59 二分搜索
数据结构·笔记·学习·算法·leetcode