2

I am trying to create an image component with a hover state using shaders with react-three-fiber.

The shader was originally created by TheFrost and can be found at https://codepen.io/frost084/full/OKZNRm.

Unfortunately, I come across an error that I don't understand. Error:

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
o

The Image Component code:

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;

Besides the error my website works fine, only the image is not rendered. I have confirmed that the image is successfully passed through props. However, the image is not being rendered on the canvas. The canvas is rendering correctly with a pink background.

How to resolve this shader error?

2
  • The name of the texture sampler uniform can't be texture, because texture is the name of built-in function in GLSL ES 3.00. I suggest to use tDiffuse as it is common in threejs. Commented May 1, 2023 at 15:33
  • I have tried that but I get the read properties of undefined (reading 'value') error Commented May 1, 2023 at 15:38

1 Answer 1

1

The name of the texture sampler uniform can't be texture, because texture is the name of built-in function in GLSL ES 3.00. I suggest to use tDiffuse as it is common in threejs.

Change setting of the uniform variable:

uniforms-texture-value={imgTexture}

uniforms-tDiffuse-value={imgTexture}

Change the fragment shader:

precision highp float; 

uniform sampler2D tDiffuse;
uniform float imageAspectRatio;
uniform float aspectRatio;
uniform float opacity;
uniform float hover;
varying vec2 vUv;

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;
} 

void main() {
    vec2 uv = vUv;

    // fix aspectRatio
    float u = imageAspectRatio/aspectRatio;
    if(imageAspectRatio > aspectRatio) {
    u = 1. / u;
    }

    uv.y *= u;
    uv.y -= (u)/2.-.5;

    // hover effect
    float zoomLevel = .2;
    float hoverLevel = exponentialInOut(min(1., (distance(vec2(.5), uv) * hover) + hover));
    uv *= 1. - zoomLevel * hoverLevel;
    uv += zoomLevel / 2. * hoverLevel;
    uv = clamp(uv, 0., 1.);
    vec4 color = texture2D(tDiffuse, uv);
    if(hoverLevel > 0.) {
    hoverLevel = 1.-abs(hoverLevel-.5)*2.;
    //Pixel displace
    uv.y += color.r * hoverLevel * .05;
    color = texture2D(tDiffuse, uv);
    // RGBshift
    color.r = texture2D(tDiffuse, uv+(hoverLevel)*0.01).r;
    color.g = texture2D(tDiffuse, uv-(hoverLevel)*0.01).g;
    }

    gl_FragColor = mix(vec4(1.,1.,1.,opacity), color, opacity);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.