我根据我在网上找到的代码,使用 3js 着色器在 React 中创建了一个具有悬停效果的图像组件。我正在映射我的数据以创建多张卡片,其中每张卡片只是一张图像,使用此组件显示具有悬停效果的图像。但是,我遇到了两个问题:
我尝试根据索引更改道具或添加唯一标识符和其他一些东西,但都没有用。我认为问题在于我如何创建图像组件本身。
有人可以帮我解决这些问题吗?
组件代码:
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 };