如何在React Three Fiber中实现可动画的GLSL扭曲着色器?
入门级GLSL扭曲效果实现指引(React Three Fiber环境)
一、顶点着色器 vs 片元着色器:选哪个?
- 你要做的是3D物体的形态扭曲,优先用顶点着色器。直接修改顶点位置能让物体的物理轮廓(比如阴影、碰撞逻辑)和视觉效果保持一致;片元着色器仅能实现像素级的视觉扭曲,会导致物体形态和视觉脱节,更适合2D纹理类扭曲效果。
二、噪声选择:数学噪声还是图像噪声?
- 入门阶段推荐数学生成噪声(比如Perlin/Simplex噪声):
- 无需额外加载纹理资源,代码内即可生成,调试效率高。
- 容易通过参数控制噪声的缩放、强度,适配动画需求。
- 和TouchDesigner里的噪声节点逻辑相通,你熟悉的生成艺术概念可以直接迁移过来。
- 图像噪声适合特定纹理风格的扭曲,但需要额外加载噪声图,入门阶段先从数学噪声入手更高效。
三、React Three Fiber里的实现步骤
1. 基础着色器材质结构
用ShaderMaterial定义着色器逻辑和控制参数:
import { ShaderMaterial, useRef } from '@react-three/fiber'; const DistortMaterial = () => { const matRef = useRef(null); return ( <ShaderMaterial ref={matRef} uniforms={{ time: { value: 0 }, // 动画时间参数 distortStrength: { value: 0.2 }, // 扭曲强度 noiseScale: { value: 4.0 } // 噪声缩放(控制扭曲细节) }} vertexShader={` uniform float time; uniform float distortStrength; uniform float noiseScale; // 入门级伪随机噪声函数(可替换为Perlin/Simplex噪声) float noise(vec2 st) { return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453); } void main() { // 结合顶点位置与时间生成动态噪声UV vec2 noiseUV = vec2(position.x + time, position.z) * noiseScale; float distortVal = noise(noiseUV) * distortStrength; // 修改顶点Y轴位置(可按需改为X/Z轴或多轴) vec3 distortedPos = position + vec3(0.0, distortVal, 0.0); // 完成顶点着色器标准流程 gl_Position = projectionMatrix * modelViewMatrix * vec4(distortedPos, 1.0); } `} fragmentShader={` void main() { // 基础白色输出,后续可替换为纹理或自定义颜色逻辑 gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); } `} /> ); };
2. 添加动画逻辑
用useFrame钩子更新时间参数,实现动态扭曲:
import { useFrame } from '@react-three/fiber'; // 在DistortMaterial组件内添加 useFrame((state) => { matRef.current.uniforms.time.value = state.clock.elapsedTime; });
3. 应用到3D物体
将材质绑定到mesh上即可看到效果:
const MyScene = () => { return ( <mesh> <boxGeometry args={[2, 2, 2]} /> <DistortMaterial /> </mesh> ); };
四、进阶提示
- 替换平滑噪声:上面的伪随机噪声效果较生硬,可找现成的GLSL Perlin/Simplex噪声代码替换,扭曲效果会更自然。
- 多轴扭曲控制:可新增uniform参数控制扭曲的轴向,或让噪声同时影响多个坐标轴。
- 颜色联动:若需要颜色随扭曲变化,可在顶点着色器中将噪声值传递给片元着色器,用于修改像素颜色。
内容的提问来源于stack exchange,提问作者Laiqa Mohid
相关产品推荐
相关产品推荐

