如何解决react-three-fiber中自定义着色器hover状态的着色器错误
问题:React-Three-Fiber自定义着色器编译错误排查与修复
我尝试用react-three-fiber结合自定义着色器实现带hover状态的图片组件,着色器改编自TheFrost的Codepen项目。但出现着色器编译错误,片段着色器未编译,涉及texture函数调用、维度不匹配等问题。已确认图片props传递正常,但画布仅显示粉色背景,图片未渲染。相关错误日志与组件代码如下,求解决方法。
错误日志
REE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false RAGMENT Program Info Log: Fragment shader is not compiled. ERROR: 0:106: 'texture' : function name expected ERROR: 0:106: '=' : dimension mismatch ERROR: 0:106: '=' : cannot convert from 'const mediump float' to 'highp 4-component vector of float' ERROR: 0:111: 'texture' : function name expected ERROR: 0:111: '=' : dimension mismatch ERROR: 0:111: 'assign' : cannot convert from 'const mediump float' to 'highp 4-component vector of float' ERROR: 0:113: 'texture' : function name expected ERROR: 0:113: 'r' : field selection requires structure, vector, or interface block on left hand side ERROR: 0:114: 'texture' : function name expected ERROR: 0:114: 'g' : field selection requires structure, vector, or interface block on left hand side 101: float zoomLevel = .2; 102: float hoverLevel = exponentialInOut(min(1., (distance(vec2(.5), uv) * hover) + hover)); 103: uv *= 1. - zoomLevel * hoverLevel; 104: uv += zoomLevel / 2. * hoverLevel; 105: uv = clamp(uv, 0., 1.); > 106: vec4 color = texture2D(texture, uv); 107: if(hoverLevel > 0.) { 108: hoverLevel = 1.-abs(hoverLevel-.5)*2.; 109: //Pixel displace 110: uv.y += color.r * hoverLevel * .05; 111: color = texture2D(texture, uv); 112: // RGBshift
组件代码
import { useState, useMemo } from 'react'; import { TextureLoader } from 'three'; import { Canvas } from '@react-three/fiber'; import { useSpring, animated, config } from '@react-spring/three'; import { HoverImageShader } from 'shader/HoverImageShader'; const AnimatedImage = ({ src, width = '100%', height = '100%' }) => { const [hovered, setHover] = useState(false); const imgTexture = useMemo(() => { const loader = new TextureLoader(); return loader.load(src); }, [src]); const { hoverValue } = useSpring({ hoverValue: hovered ? 1 : 0, config: config.molasses, }); return ( <Canvas pixelratio={window.devicePixelRatio || 1} style={{ background: 'pink', width, height }} camera={{ fov: 75, position: [0, 0, 7] }} > <animated.mesh onPointerOver={() => setHover(true)} onPointerOut={() => setHover(false)} > <planeBufferGeometry attach='geometry' args={[10.7, 10.7]} /> <animated.shaderMaterial attach='material' transparent args={[HoverImageShader]} uniforms-texture-value={imgTexture} uniforms-hover-value={hoverValue} /> </animated.mesh> </Canvas> ); }; export default AnimatedImage;
解决方案
1. 修复着色器变量命名冲突
错误核心原因是纹理uniform的命名texture与GLSL内置函数texture()重名,导致编译器无法识别函数调用。
- 修改着色器中的uniform定义:将
uniform sampler2D texture;改为uniform sampler2D uTexture; - 替换片段着色器中所有纹理采样代码:把
texture2D(texture, uv)改成texture(uTexture, uv)(WebGL2中推荐使用texture()替代texture2D())
2. 确保自定义缓动函数存在
原着色器中的exponentialInOut是自定义函数,需要确保你的HoverImageShader中包含该函数的定义:
float exponentialInOut(float t) { return t == 0.0 || t == 1.0 ? t : t < 0.5 ? +0.5 * pow(2.0, (20.0 * t) - 10.0) : -0.5 * pow(2.0, 10.0 - (t * 20.0)) + 1.0; }
3. 修正React-Three-Fiber的ShaderMaterial参数传递
animated.shaderMaterial的参数传递方式有误,需要用shader属性传入着色器对象,并通过uniforms对象传递参数,而不是旧的uniforms-xxx-value语法:
<animated.shaderMaterial attach='material' transparent shader={HoverImageShader} uniforms={{ uTexture: { value: imgTexture }, hover: { value: hoverValue } }} />
4. 纹理加载的额外处理(可选)
为避免纹理翻转问题,可以在加载纹理时设置:
const imgTexture = useMemo(() => { const loader = new TextureLoader(); const texture = loader.load(src); texture.flipY = false; // 适配three.js的纹理坐标系 return texture; }, [src]);
完成以上修改后,着色器应该能正常编译,hover交互效果也能正确渲染。
内容的提问来源于stack exchange,提问作者Oliver
相关产品推荐
相关产品推荐

