You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使Fiber/Drei中HTML文本与3D对象滚动速度同步?

问题描述

我有一个包含大量随页面滚动的3D元素的场景,想要在这些元素前方添加文本,但还没找到让文本与3D对象滚动速度匹配的方法。

在示例场景中,“hello”文本初始位置正确,但滚动时很快与粉色盒子错位。如何让文本与Scroll组件内的任意3D对象的运动保持同步?

“hello”应位于粉色盒子内部

示例代码

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钩子获取滚动进度,手动计算并更新位置:

  1. 先导入useScroll:
import { useScroll } from '@react-three/drei'
  1. 在组件中获取滚动数据并同步到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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 22:45:40