如何在Three.js+React-Three-Fiber中向着色器传递浮点数组uniform?
问题解决方法
一、传递大长度数组到着色器
你之前把uDistance定义成vec3是核心错误——vec3仅能存储3个值,完全无法容纳1000元素的数组。正确做法是直接在GLSL中定义浮点数组:
1. 修改片段着色器
// 直接定义长度为1000的浮点数组 uniform float uDistance[1000]; varying float vDistance; void main() { // 直接通过下标访问数组元素,注意下标范围是0-999 float x = uDistance[52]; vec3 color = vec3(0.5, 0.5, x); gl_FragColor = vec4(color, 1.0); }
2. JS端uniform代码调整(补全依赖)
你的JS代码逻辑没问题,但要补全useMemo的依赖,确保数组更新时uniform能同步:
const uniforms = useMemo(() => ({ uTime: { value: 0.0 }, uRadius: { value: radius }, uDistance: { value: normalDistances } // normalDistances需是长度1000的数组 }), [radius, normalDistances]) // 必须添加数组和半径作为依赖
二、动态传递数组长度(用#define)
如果不想硬编码数组长度1000,可以通过JS向着色器传递宏定义:
1. 着色器中使用宏占位
// 声明宏,具体值由JS传递 #define DISTANCE_COUNT 1000 uniform float uDistance[DISTANCE_COUNT]; varying float vDistance; void main() { float x = uDistance[52]; vec3 color = vec3(0.5, 0.5, x); gl_FragColor = vec4(color, 1.0); }
2. React-Three-Fiber中传递define
在创建着色器材质时,通过defines字段传递宏值:
import { shaderMaterial } from '@react-three/drei' const CustomMaterial = shaderMaterial( { uTime: 0.0, uRadius: radius, uDistance: normalDistances }, // 你的顶点着色器代码(此处省略) `...`, // 你的片段着色器代码(此处省略) `...`, // 传递宏定义,动态获取数组长度 { defines: { DISTANCE_COUNT: normalDistances.length } } )
如果使用useShaderMaterial,同样可以在配置参数中添加defines字段。
关键注意事项
- JS端数组长度必须和着色器中定义的数组长度完全一致,否则会出现访问越界或数据截断问题。
- 务必补全useMemo的依赖数组,避免数组更新后uniform未同步的bug。
内容的提问来源于stack exchange,提问作者ewakwwg12
相关产品推荐
相关产品推荐

