我很难找到向下滚动时组件重新渲染的原因。我尝试过使用着色器和FBO技术构建粒子场景。我使用useRef和useMemo来防止重新渲染,而不是使用useState。我尝试过使用useGLTF在组件中加载3d模型,但没有成功。向下滚动时会重新渲染。问题是什么?以下是我的代码。
let opacity;
const size = 80;
const FboParticles = ({ models }) => {
const { viewport } = useThree();
const scroll = useScroll();
/**
* Particles options
*/
// This reference gives us direct access to our points
const points = useRef();
const simulationMaterialRef = useRef();
// Create a camera and a scene for our FBO
// Create a simple square geometry with custom uv and positions attributes
const [scene, camera, positions, uvs] = useMemo(() => {
return [
new Scene(),
new OrthographicCamera(-1, 1, 1, -1, 1 / Math.pow(2, 53), 1),
new Float32Array([
-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, 1, 0,
]),
new Float32Array([0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0]),
];
}, []);
// Create our FBO render target
const renderTarget = useFBO(size, size, {
minFilter: NearestFilter,
magFilter: NearestFilter,
format: RGBAFormat,
stencilBuffer: false,
type: FloatType,
});
// Generate a "buffer" of vertex of size "size" with normalized coordinates
const particlesPosition = useMemo(() => {
const length = size * size;
const particles = new Float32Array(length * 3);
for (let i = 0; i < length; i++) {
let i3 = i * 3;
particles[i3 + 0] = (i % size) / size;
particles[i3 + 1] = i / size / size;
}
return particles;
}, []);
const uniforms = useMemo(
() => ({
uPositions: {
value: null,
},
uMobile: {
value: 1,
},
uPixelRatio: {
value: Math.min(window.devicePixelRatio, 2),
},
vColor: {
value: 0,
},
defaultTime: {
value: 0,
},
uOpacity: {
value: 0,
},
uColorTrigger: {
value: 0,
},
}),
[]
);
useLayoutEffect(() => {
if (viewport.width < 4.8) {
points.current.material.uniforms.uMobile.value = 0.1;
}
}, []);
// FBO useFrame
useFrame(({ gl, clock }) => {
gl.setRenderTarget(renderTarget);
gl.clear();
gl.render(scene, camera);
gl.setRenderTarget(null);
points.current.material.uniforms.uPositions.value = renderTarget.texture;
points.current.material.uniforms.defaultTime.value = clock.elapsedTime;
simulationMaterialRef.current.uniforms.uTime.value = clock.elapsedTime;
});
const [scales, colors] = useMemo(() => {
const length = size * size * 3;
const color = new Color();
const sca = [];
const cols = [];
let q = ["white", "white", 0x2675ad, 0x0b5394, 0x0b9490];
const range = viewport.width < 4.8 ? 20 : 40;
for (let i = 0; i < length; i++) {
const i3 = i * 3;
// color
color.set(q[randInt(0, 4)]);
cols[i3 + 0] = color.r;
cols[i3 + 1] = color.g;
cols[i3 + 2] = color.b;
// particles scale
sca[i] = Math.random() * range;
}
return [new Float32Array(sca), new Float32Array(cols)];
}, []);
/**
* mouse event
*/
const hoveredRef = useRef();
const planeGeo = useMemo(() => {
return new PlaneGeometry(viewport.width, viewport.height, 1, 1);
}, []);
/**
* scroll
*/
// scroll animation
useFrame(({ mouse }) => {
const x = (mouse.x * viewport.width) / 2;
const y = (mouse.y * viewport.height) / 2;
if (viewport.width > 6.7) {
if (hoveredRef.current) {
simulationMaterialRef.current.uniforms.uMouse.value = new Vector2(x, y);
simulationMaterialRef.current.uniforms.uMouseTrigger.value = 1;
} else simulationMaterialRef.current.uniforms.uMouseTrigger.value = 0;
}
const aRange = scroll.range(0.0, 1 / 12);
const bRange = scroll.range(0.7 / 12, 1 / 12);
simulationMaterialRef.current.uniforms.scrollTriggerA.value = aRange;
const cRange = scroll.range(1.7 / 12, 1 / 12);
const dRange = scroll.range(3.6 / 12, 1 / 12);
const c = scroll.visible(1.7 / 12, 1 / 12);
const d = scroll.visible(2.7 / 12, 1.9 / 12);
simulationMaterialRef.current.uniforms.scrollTriggerB.value = cRange;
const e = scroll.visible(4.8 / 12, 2 / 12);
const eRange = scroll.range(4.8 / 12, 1 / 12);
simulationMaterialRef.current.uniforms.scrollTriggerC.value = eRange;
const f = scroll.visible(6.8 / 12, 1 / 12);
const g = scroll.visible(7.6 / 12, 1 / 12);
const fRange = scroll.range(6.8 / 12, 1 / 12);
const gRange = scroll.range(7.6 / 12, 1 / 12);
simulationMaterialRef.current.uniforms.scrollTriggerD.value = fRange;
simulationMaterialRef.current.uniforms.scrollTriggerE.value = gRange;
const h = scroll.visible(9.6 / 12, 2.4 / 12);
const hRange = scroll.range(9.6 / 12, 1 / 12);
simulationMaterialRef.current.uniforms.scrollTriggerF.value = hRange;
points.current.material.uniforms.uColorTrigger.value = hRange;
const iRange = scroll.range(10.6 / 12, 1.4 / 12);
simulationMaterialRef.current.uniforms.scrollTriggerG.value = iRange;
// opacity
opacity = 1 - bRange;
c && (opacity = cRange);
d && (opacity = 1 - dRange);
e && (opacity = eRange);
f && (opacity = 1 - fRange);
g && (opacity = fRange);
h && (opacity = hRange);
points.current.material.uniforms.uOpacity.value = opacity;
});
return (
<>
<mesh
position={[0, 0, 0]}
onPointerOver={(e) => (
e.stopPropagation(), (hoveredRef.current = true)
)}
onPointerOut={(e) => (hoveredRef.current = false)}
visible={false}
geometry={planeGeo}
/>
{/* Render off-screen our simulation material and square geometry */}
{createPortal(
<mesh>
<simulationMaterial
ref={simulationMaterialRef}
args={[size, viewport, models]}
/>
<bufferGeometry>
<bufferAttribute
attach="attributes-position"
count={positions.length / 3}
array={positions}
itemSize={3}
/>
<bufferAttribute
attach="attributes-uv"
count={uvs.length / 2}
array={uvs}
itemSize={2}
/>
</bufferGeometry>
</mesh>,
scene
)}
<points ref={points}>
<bufferGeometry>
<bufferAttribute
attach="attributes-position"
count={particlesPosition.length / 3}
array={particlesPosition}
itemSize={3}
/>
<bufferAttribute
attach="attributes-color"
count={colors.length / 3}
array={colors}
itemSize={3}
/>
<bufferAttribute
attach="attributes-aScale"
count={scales.length}
array={scales}
itemSize={1}
/>
</bufferGeometry>
<shaderMaterial
blending={AdditiveBlending}
depthWrite={false}
// transparent={true}
fragmentShader={fragmentShader}
vertexShader={vertexShader}
uniforms={uniforms}
/>
</points>
</>
);
};
export default FboParticles;
1条答案
按热度按时间czq61nw11#
如果你想重新呈现你的组件,你只需要使用状态,如下所示:
在任何地方使用这个forceUpdate,但是重点是它应该接受对象,如果你想在对象上写int,你应该设置不同的值,所以是的,在对象上使用随机int
第一个月