React + Three.js에서 waving flag

24348 단어 React.jsthreejsidea
Three.js에서 바람에 흔들리는 깃발을 제작하여 비교적 고전적인 느낌을 준다
사용한 샘플을 찾지 못했기 때문에@react-three/fiber나는 각종 조사 결과를 쓰고 싶다.

깃발을 흔드는 생각/방법


PlaneGeometry의 vertices (정점) 속성만 업데이트하면 된다는 것을 알고 있습니다.
그러나three-fiber를 사용할 때vertices에는 속성을 찾을 수 없습니다.

정점 좌표를 획득하고 업데이트하는 방법


https://github.com/pmndrs/react-three-fiber/discussions/968#discussioncomment-317165
정점의 좌표 정보가 position 속성에 들어간 것 같습니다.Three.js의 샘플 코드는 Vector3입니다. 여기는 모두 배열되어 있습니다.

써본 코드


github에 예시된 코드에서 다음 좌표를 얻을 수 있습니다:.
//x
position.array[index * 3]
//y
position.array[index * 3 + 1]
//z
position.array[index * 3 + 2]
아래 코드는 필요 없어요@react-three/cannon. 하지만 usePlane 연결이 편리해서 썼어요.

모든 코드


import { TextureLoader } from "three/src/loaders/TextureLoader";
import { Canvas, useFrame, useLoader, useThree } from "@react-three/fiber";
import { Physics, usePlane, Debug } from "@react-three/cannon";
import CameraControls from "camera-controls";
import * as THREE from "three";
import { useMemo } from "react";
CameraControls.install({ THREE });

const TeamFlag = ({img_url}) => {
  const Flag = () => {
    const map = useLoader(TextureLoader, 
      img_url
    );
    const [mesh] = usePlane(() => ({
      rotation: [-0.1, 0, 0],
      position: [0, 0, 0],
      type: "Static",
      mass: 100,
      args: [3, 3, 15, 9],
    }));
    useFrame((state) => {
      const t = state.clock.getElapsedTime();
      function* enumerate(count) {
        let i = 0;
        while (i < count) yield i++;
      }
      const { geometry } = mesh.current;
      const { position, normal, uv } = geometry.attributes;
      for (const index of enumerate(position.count)) {
        const waveX1 = 0.5 * Math.sin(position.array[index * 3] * 2 + t*4);
        const waveX2 = 0.25 * Math.sin(position.array[index * 3] * 3 + t *2);
        const waveY1 =
          0.25 * Math.sin(position.array[index * 3 + 1] * 3 + t / 5);
        const multi = (position.array[index * 3] + 2) / 5;

        //z
        position.array[index * 3 + 2] = (waveX1 + waveX2 + waveY1) * multi;
      }
      position.needsUpdate = true;
      geometry.computeVertexNormals();
    });
    return (
      <mesh ref={mesh}>
        <planeGeometry args={[3, 3, 15, 9]}/>
        <meshBasicMaterial map={map} opacity={1} />
      </mesh>
    );
  };

  function Controls({
    zoom,
    focus,
    pos = new THREE.Vector3(),
    look = new THREE.Vector3(),
  }) {
    const camera = useThree((state) => state.camera);
    const gl = useThree((state) => state.gl);
    const controls = useMemo(
      () => new CameraControls(camera, gl.domElement),
      []
    );
    return useFrame((state, delta) => {
      state.camera.position.lerp(pos, 0.5);
      state.camera.updateProjectionMatrix();
      controls.setLookAt(
        state.camera.position.x,
        state.camera.position.y,
        state.camera.position.z,
        look.x,
        look.y,
        look.z,
        true
      );
      return controls.update(delta);
    });
  }

  return (
    <div>
      <Canvas
        style={{
            width:80,
            height:80
        }}
      >
        <Physics>
          <Flag />
        </Physics>
        <Controls
          zoom={false}
          focus={{}}
          pos={new THREE.Vector3(0, 0, 2.2)}
          look={new THREE.Vector3(0, 0, 0)}
        />
      </Canvas>
    </div>
  );
};

export default TeamFlag;

참조 링크


https://github.com/nikpundik/react-three-fiber-cloth-example

좋은 웹페이지 즐겨찾기