首页 > 解决方案 > 通过动态更新 TubeBufferGeometry 的曲线创建光迹效果

问题描述

我有一个使用 react-three-fiber 的第三人称游戏,我想在玩家移动的任何地方添加一种尾灯效果。光迹会在一段时间后消失,所以我想为这些点设置一个固定大小的数组。这是我最初尝试的解决方案:

const point = new THREE.Vector3();
const points = new Array(50).fill(null).map(p => new THREE.Vector3());
let index = 0;


const Trail = () => {
    const ref = useRef();
    const playerBody = useStore(state => state.player); // contains player position

    const [path, setPath] = useState(new THREE.CatmullRomCurve3(points));
    useFrame(() => { // equivalent to raf
        const { x, y, z } = playerBody.position;
        point.set(x, y, z);

        points[index].copy(point);
        index = (index + 1) % 50;

        setPath(new THREE.CatmullRomCurve3(points));

        if (ref && ref.current) {
            ref.current.attributes.position.needsUpdate = true;
            ref.current.computeBoundingSphere();
        }
    });

    return (
        <mesh>
            <tubeBufferGeometry ref={ref} attach="geometry" args={[path, 20, .5, 8, false]} />
            <meshBasicMaterial attach="material" color={0xffffff} />
        </mesh>
    )
}

基本上,我的思考过程是更新每一帧(或每 x 帧以提高性能)上的曲线,并使用索引来跟踪要更新的点数组中的哪个位置。

但是我遇到了两个问题:

  1. TubeBufferGeometry 不更新。不确定是否可以在实例化后更新几何。
  2. 我预见到使用这种固定数组/索引方法的缺陷是,一旦我到达数组的末尾,我将不得不绕回索引 0。所以曲线插值会搞砸,因为我假设它需要点依次。数组中的最后一个点现在应该连接到第一个点,但不会那样。

为了解决#2,我尝试了类似

points.unshift();
points.push(point.clone);

而不是,points[index].copy(point);但我仍然无法让 Tube 首先更新。

我想看看是否有更好的解决方案,或者这是否是解决此类问题的正确方法。

标签: three.jsreact-three-fiber

解决方案


如果要更新 TubeBufferGeometry 的路径,还需要更新所有的顶点和法线,就像重新构建几何体一样。

看看这里了解它是如何工作的:https ://github.com/mrdoob/three.js/blob/r118/src/geometries/TubeGeometry.js#L135

重要的部分是generateSegment()功能,之前不要忘记这部分:

    const frames = path.computeFrenetFrames( tubularSegments, closed );

我去年做了一个例子,随意使用我的代码:https ://codepen.io/soju22/pen/JzzvbR


推荐阅读