如何使Fiber/Drei中HTML文本与3D对象滚动速度同步?
问题描述
我有一个包含大量随页面滚动的3D元素的场景,想要在这些元素前方添加文本,但还没找到让文本与3D对象滚动速度匹配的方法。
在示例场景中,“hello”文本初始位置正确,但滚动时很快与粉色盒子错位。如何让文本与Scroll组件内的任意3D对象的运动保持同步?

示例代码
import { PerspectiveCamera, Scroll, ScrollControls, Box, Html } from '@react-three/drei' import { useRef } from 'react' export default function Experience() { const cam = useRef() return ( <> <PerspectiveCamera makeDefault position={[0, 13, 10]} ref={cam} /> <ambientLight intensity={0.1} /> <ScrollControls pages={1.8} damping={0.5}> <Scroll> <pointLight position={[3, 5, 3]} castShadow /> <Box position={[0, 15, 0]} /> <Html position={[0, 10, 0]}>hello</Html> <Box position={[0, 10, 0]} castShadow material-color="pink" /> <Box position={[0, 5, 0]} /> <Box position={[0, 0, 0]} /> <mesh receiveShadow position-y={-0.5} rotation-x={-Math.PI * 0.5} scale={50}> <planeGeometry /> <meshStandardMaterial color="greenyellow" /> </mesh> </Scroll> </ScrollControls> </> ) }
解决方案
问题核心是Html组件默认挂载在DOM中,不会自动跟随Three.js场景内Scroll组件的滚动变换,因此和3D对象出现错位。以下是两种修复方案:
方法一:将Html作为3D对象的子元素
把Html嵌套在目标3D对象内部,它会自动继承父元素的所有变换(包括Scroll驱动的位移),代码修改如下:
<Box position={[0, 10, 0]} castShadow material-color="pink"> <Html>hello</Html> </Box>
这种方式无需额外计算,文本会完全同步父盒子的运动,是最简洁可靠的方案。
方法二:手动同步滚动位移
如果需要Html独立存在但保持同步,可以通过useScroll钩子获取滚动进度,手动计算并更新位置:
- 先导入
useScroll:
import { useScroll } from '@react-three/drei'
- 在组件中获取滚动数据并同步到
Html:
export default function Experience() { const cam = useRef() const { scroll } = useScroll() return ( <> <PerspectiveCamera makeDefault position={[0, 13, 10]} ref={cam} /> <ambientLight intensity={0.1} /> <ScrollControls pages={1.8} damping={0.5}> <Scroll> <pointLight position={[3, 5, 3]} castShadow /> <Box position={[0, 15, 0]} /> {/* 根据滚动进度计算Y轴位置,和粉色盒子同步 */} <Html position={[0, 10 - scroll.current * 15, 0]}>hello</Html> <Box position={[0, 10, 0]} castShadow material-color="pink" /> <Box position={[0, 5, 0]} /> <Box position={[0, 0, 0]} /> <mesh receiveShadow position-y={-0.5} rotation-x={-Math.PI * 0.5} scale={50}> <planeGeometry /> <meshStandardMaterial color="greenyellow" /> </mesh> </Scroll> </ScrollControls> </> ) }
scroll.current返回0到1之间的滚动进度,乘以场景的总滚动距离(这里是15,对应盒子从y=15到y=0的位移),即可让文本和3D对象保持同步。
内容的提问来源于stack exchange,提问作者Ashbury
相关产品推荐
相关产品推荐

