[3D] 지오메트리

jini.choi·2024년 4월 29일

3D(R3F)

목록 보기
2/10
  • Drei : R3F에서 사용할 수 있는 유용한 컴포넌트들을 모아 놓은 라이브러리

  • 지오메트리는 mesh의 모양을 정의하는거 말고도 다른용도로도 사용되지만 이번엔 모양에 대해서만 정리

  • 모든 지오메트리는 BufferGeometry 클래스를 상속받는다.

  • BufferGeometry는 Attribute라는 데이터를 가지고 있다. 그 중 형상과 관련된것은

    • position(형상을 정의하는 3차원 정점)
    • Vertex Index(삼각형 면 구성을 위한 정점 인덱스)
  • 이 외에도 mesh의 표면을 정의할 수 있는 아래와 같은 데이터가 있다. 이러한 데이터는 랜더링 시 GPU에 전달되고 매우 빠르게 나온다.

    • Normal(모델의 면에 대한 수직 벡터)
    • color(정점의 색상)
    • UV(텍스쳐 맵핑을 위한 좌표)
  • 가지고 있는 데이터 뿐만 아니라 사용자정의 데이터도 저장해서 GPU에 전달할 수 있다.

  • 기본 지오메트리 (Three.js의 Geometry 클래스)

mesh를 만드는 3가지 방법

  • 기본 mesh사용
  • three.js에 있는 Box 사용
  • 자식 컴포넌트 만들어서 사용(MyBox)
import { Box, OrbitControls } from "@react-three/drei";
import * as THREE from "three";

function MyBox(props) {
  const geom = new THREE.BoxGeometry();
  return <mesh {...props} geometry={geom}></mesh>;
}

function MYElement3D() {
  // Drei : R3F에서 사용할 수 있는 유용한 컴포넌트들을 모아 놓은 라이브러리
  return (
    <>
      <OrbitControls />
      <ambientLight intensity={0.1} />
      <directionalLight position={(2, 1, 3)} intensity={0.5} />

      <mesh>
        <boxGeometry />
        <meshStandardMaterial color="#1abc9c" />
      </mesh>

      <Box position-x={1.2}>
        <meshStandardMaterial color="#8e44ad" />
      </Box>

      <MyBox position-x={-1.2}>
        <meshStandardMaterial color="#e74c3c" />
      </MyBox>
    </>
  );
}

export default MYElement3D;
  • 두개의 mesh에서 한개의 boxGeometry를 같이 사용할 수 있게 하는 방법

  • useEffect를 사용해서 refMesh의 geometry에서 refWireMesh 사용하도록 한다.

import { OrbitControls } from "@react-three/drei";
import { useEffect, useRef } from "react";
// import * as THREE from "three";

function MYElement3D() {
  const refMesh = useRef();
  const refWireMesh = useRef();

  useEffect(() => {
    refWireMesh.current.geometry = refMesh.current.geometry;
  }, []);
  // Drei : R3F에서 사용할 수 있는 유용한 컴포넌트들을 모아 놓은 라이브러리
  return (
    <>
      <OrbitControls />
      <ambientLight intensity={0.1} />
      <directionalLight position={(2, 1, 3)} intensity={0.5} />

      <mesh ref={refMesh}>
        <boxGeometry />
        <meshStandardMaterial color="#1abc9c" />
      </mesh>

      <mesh ref={refWireMesh}>
        <meshStandardMaterial emissive="yellow" wireframe={true} />
      </mesh>
    </>
  );
}

export default MYElement3D;

args

  • args를 UI에서 변경할 수 있는 방법 : leva사용

    args
    arguments 줄임말, 각 지오메트리를 위한 클래스의 새엉자에 대한 인자값
    도형의 크기를 정의하며 3차원 vector값을 갖는다.

  • Segments 는 분할

  • Geometry별 인자 갯수

  • boxGeometry(6개) : xSize, ySize, zSize, xSegments, ySegments, zSegments

    xSize : x축 방향에 대한 크기
    xSegments: x축 방향에 대한 분할 수

  • sphereGeometry(7개) : radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength

    반지름
    너비 방향에 대한 분할 수 (1 이상 정수)
    높이 방향에 대한 분할 수 (1 이상 정수)
    수평 방향에 대한 시작 각도 (0 이상 360 미만 유리수)
    수평 방향에 대한 연장 각도 (0 이상 360 미만 유리수)
    높이 방향에 대한 시작 각도 (0 이상 360 미만 유리수)
    높이 방향에 대한 연장 각도 (0 이상 360 미만 유리수)
    (phiStart, phiLength)는 radian 단위로 해야됨 Math.PI/180

  • CylinderGeometry(8개) : topRadius, bottomRadius, height, radialSegments, heightSegments, bopen, thetaStart, thetaLength

    윗면 반지름
    아랫면 반지름
    높이
    방사 방향에 대한 분할 수 (1 이상 정수)
    높이 방향에 대한 분할 수 (1 이상 정수)
    윗면과 아랫면에 대한 개방 여부 (true/false)
    시작 각도 (0 이상 360 미만 유리수)
    연장 각도 (0 이상 360 미만 유리수)

  • 그 외 GeoMetry인자 확인은 공식문서 확인
    https://threejs.org/docs/index.html?q=geoMetry#api/en/geometries/BoxGeometry

import { OrbitControls } from "@react-three/drei";
import { useControls } from "leva";
import { useEffect, useRef } from "react";
// import * as THREE from "three";

function MYElement3D() {
  const refMesh = useRef();
  const refWireMesh = useRef();
  const { xSize, ySize, zSize, xSegments, ySegments, zSegments } = useControls({
    xSize: {
      value: 1,
      min: 0.1,
      max: 5,
      step: 0.01,
    },
    ySize: {
      value: 1,
      min: 0.1,
      max: 5,
      step: 0.01,
    },
    zSize: {
      value: 1,
      min: 0.1,
      max: 5,
      step: 0.01,
    },
    xSegments: {
      // xSegments는 정수값이여야됨
      value: 1,
      min: 1,
      max: 10,
      step: 1,
    },
    ySegments: {
      value: 1,
      min: 1,
      max: 10,
      step: 1,
    },
    zSegments: {
      value: 1,
      min: 1,
      max: 10,
      step: 1,
    },
  });

  useEffect(() => {
    refWireMesh.current.geometry = refMesh.current.geometry;
  }, [xSize, ySize, zSize, xSegments, ySegments, zSegments]);
  
  
  return (
    <>
      <OrbitControls />
      <ambientLight intensity={0.1} />
      <directionalLight position={(2, 1, 3)} intensity={0.5} />

      <mesh ref={refMesh}>
        <boxGeometry
          args={[xSize, ySize, zSize, xSegments, ySegments, zSegments]}
        />
        <meshStandardMaterial color="#1abc9c" />
      </mesh>

      <mesh ref={refWireMesh}>
        <meshStandardMaterial emissive="yellow" wireframe={true} />
      </mesh>
    </>
  );
}

export default MYElement3D;

이 글은 아래 유투브 강의를 듣고 작성한 글 입니다.
https://www.youtube.com/watch?v=0jnGlLb_z7w&list=PLe6NQuuFBu7HUeJkowKRkLWwkdOlhwrje&index=4

profile
개발짜🏃‍♀️

0개의 댓글