带有 3js 着色器的 React 组件:在多张卡片上显示相同的图像并为所有图像触发悬停效果

问题描述 投票:0回答:0

我根据我在网上找到的代码,使用 3js 着色器在 React 中创建了一个具有悬停效果的图像组件。我正在映射我的数据以创建多张卡片,其中每张卡片只是一张图像,使用此组件显示具有悬停效果的图像。但是,我遇到了两个问题:

  1. 所有的卡片都显示相同的图像,即使数据包含不同的图像。
  2. 当我将鼠标悬停在一张图片上时,所有图片都会触发悬停效果。

我尝试根据索引更改道具或添加唯一标识符和其他一些东西,但都没有用。我认为问题在于我如何创建图像组件本身。

有人可以帮我解决这些问题吗?

组件代码:

import { 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,
  playAnim = false,
  width = '100%',
  height = '100%',
  textureWidth = 10.8,
  textureHeight = 10.8,
}) => {
  const imgTexture = useMemo(() => {
    const loader = new TextureLoader();
    return loader.load(src);
  }, [src, width, height]);

  const { hoverValue } = useSpring({
    hoverValue: playAnim ? 1 : 0,
    config: config.molasses,
  });

  return (
    <Canvas
      pixelratio={window.devicePixelRatio || 1}
      style={{ width, height }}
      camera={{ fov: 75, position: [0, 0, 7] }}
    >
      <animated.mesh>
        <planeBufferGeometry
          attach='geometry'
          args={[textureWidth, textureHeight]}
        />
        <animated.shaderMaterial
          attach='material'
          transparent
          args={[HoverImageShader]}
          uniforms-tDiffuse-value={imgTexture}
          uniforms-hover-value={hoverValue}
        />
      </animated.mesh>
    </Canvas>
  );
};

export default AnimatedImage;

        <div ref={trackRef} className={styles.cardsTrack}>
          {cardsData?.map((card, index) => (
            <div
              id='cardContainer'
              key={index}
              className={styles.cardContainer}
            >
              <Link to={`/cards/${card.id}`} className={styles.link}>
                <div
                  id='cardImageContainer'
                  className={styles.cardImageContainer}
                  onMouseEnter={() => setHover(true)}
                  onMouseLeave={() => setHover(false)}
                >
                  <AnimatedImage src={card.image} playAnim={hover} />
                </div>
              </Link>
            </div>
          ))}
        </div>

着色器代码:

var HoverImageShader = {
  vertexShader: `
      varying vec2 vUv; 
  
      void main() {
        vUv = uv;
  
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
  fragmentShader: `
  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);
  }
    `,
  uniforms: {
    tDiffuse: {
      type: 't',
      value: '',
    },
    imageAspectRatio: {
      type: 'f',
      value: 1.0,
    },
    aspectRatio: {
      type: 'f',
      value: 1.0,
    },
    opacity: {
      type: 'f',
      value: 1.0,
    },
    hover: {
      type: 'f',
      value: 0.0,
    },
  },
};

export { HoverImageShader };

javascript reactjs three.js shader react-three-fiber
© www.soinside.com 2019 - 2024. All rights reserved.