使用react-三纤维和react-spring对bufferAttribute进行动画处理

mtx*_*mtx 6 three.js reactjs react-spring react-three-fiber

我有带有自定义着色器和缓冲区几何形状的简单点网格。

几何图形具有位置、大小和颜色属性。指针悬停时,悬停的顶点会变成红色。

到目前为止,一切都很好。

现在我想为悬停顶点的颜色变化设置动画。

以下是点网格的代码片段:

const Points = (
  props = { hoveredIndex: null, initialCameraZ: 0, array: [], sizes: [] }
) => {
  const [_, setHover] = useState(false);

  const vertices = new Float32Array(props.array);
  const sizes = new Float32Array(props.sizes);
  const _colors = genColors(props.sizes.length); // returns [] of numbers.

  const uniforms = useMemo(() => {
    return {
      time: { type: "f", value: 0.0 },
      cameraZ: { type: "f", value: props.initialCameraZ }
    };
  }, [props.initialCameraZ]);

  // trying to use react-spring here
  const [animProps, setAnimProps] = useSpring(() => ({
    colors: _colors
  }));

  const geometry = useUpdate(
    (geo) => {
      if (props.hoveredIndex !== null) {
        const i = props.hoveredIndex * 3;
        const cols = [..._colors];
        cols[i] = 1.0;
        cols[i + 1] = 0.0;
        cols[i + 2] = 0.0;

        geo.setAttribute(
          "color",
          new THREE.BufferAttribute(new Float32Array(cols), 3)
        );

        setAnimProps({ colors: cols });
      } else {
        geo.setAttribute(
          "color",
          new THREE.BufferAttribute(new Float32Array(_colors), 3)
        );

        setAnimProps({ colors: _colors });
      }
    },
    [props.hoveredIndex]
  );

  return (
    <a.points
      onPointerOver={(e) => setHover(true)}
      onPointerOut={(e) => setHover(false)}
    >
      <a.bufferGeometry attach="geometry" ref={geometry}>
        <bufferAttribute
          attachObject={["attributes", "position"]}
          count={vertices.length / 3}
          array={vertices}
          itemSize={3}
        />
        <bufferAttribute
          attachObject={["attributes", "size"]}
          count={sizes.length}
          array={sizes}
          itemSize={1}
        />
        <a.bufferAttribute
          attachObject={["attributes", "color"]}
          count={_colors.length}
          array={new Float32Array(_colors)}
          // array={animProps.colors} // this does not work
          itemSize={3}
        />
      </a.bufferGeometry>
      <shaderMaterial
        attach="material"
        uniforms={uniforms}
        vertexShader={PointsShader.vertexShader}
        fragmentShader={PointsShader.fragmentShader}
        vertexColors={true}
      />
    </a.points>
  );
};

Run Code Online (Sandbox Code Playgroud)

完整的代码和示例可在codesandbox上找到

当我尝试animProps.colors在 bufferAttribute 中使用颜色时,它无法更改颜色。

我究竟做错了什么?怎样做才对呢?

我知道我可以创建开始和目标颜色属性,将它们传递给着色器并在那里进行插值,但这会超出使用反应三纤维的目的。

有没有办法在反应三纤维中动画缓冲区属性?

Pet*_*man 1

这可能无法按预期工作,因为需要显式标记对缓冲区属性所做的更改才能发送到 GPU。我想这react-spring并不是开箱即用的。

这是一个普通示例,请注意 的用法needsUpdate

import { useFrame } from '@react-three/fiber'
import React, { useRef } from 'react'
import { BufferAttribute, DoubleSide } from 'three'

const positions = new Float32Array([
    1, 0, 0,
    0, 1, 0,
    -1, 0, 0,
    0, -1, 0
])

const indices = new Uint16Array([
    0, 1, 3,
    2, 3, 1,
])

const Comp = () => {
    
    const positionsRef = useRef<BufferAttribute>(null)

    useFrame(() => {
        const x = 1 + Math.sin(performance.now() * 0.01) * 0.5
        positionsRef.current.array[0] = x
        positionsRef.current.needsUpdate = true
    })

    return <mesh>
        <bufferGeometry>
            <bufferAttribute
                ref={positionsRef}
                attach='attributes-position'
                array={positions}
                count={positions.length / 3}
                itemSize={3}
            />
            <bufferAttribute
                attach="index"
                array={indices}
                count={indices.length}
                itemSize={1}
            />
        </bufferGeometry>
        <meshBasicMaterial 
            color={[0, 1, 1]} 
            side={DoubleSide}
        />
    </mesh>
}

Run Code Online (Sandbox Code Playgroud)

如需进一步阅读,请查看本教程