R3F(React Three Fiber) - Material

H.GOO·2024년 4월 3일
0

WEB-3D-Project

목록 보기
3/9
post-thumbnail

🪴Material

three.js에 정의된 Material 클래스를 상속 받고 있는 재질 클래스들

3차원 객체의 3요소
: PointMaterial
: LineBasicMaterial
: MeshBasicMaterial




🪴Material 클래스별 특성

PBR(Physically Based Rendering)

물리 기반 렌더링으로 Drei의 Material 중에서는 meshStandardMaterialmeshPhysicalMaterial 이 있음.
두가지를 가장 많이 사용하며, 계산량이 높아 렌더링 속도는 비교적 느리지만 고품질의 렌더링 결과를 얻을 수 있음.


meshStandardMaterial

물리 기반 렌더링(PBR)을 지원하기 때문에 광원과의 상호 작용에 따라 물체의 재질이 현실적으로 보임. 하지만 계산량이 많아 성능 요구가 높음.

...

const { roughness, metalness } = useControls({
  roughness: { value: 0, min: 0, max: 1, step: 0.1 },
  metalness: { value: 0, min: 0, max: 1, step: 0.1 },
});

...

<mesh ref={mesh1} position={[0.7, 0, 0]}>
  <torusKnotGeometry args={[0.5, 0.15, 256, 128]} />
  <meshStandardMaterial
    visible={true} // 렌더링 여부
    transparent={false} // opacity 사용 여부
    opacity={1} // 재질 불투명도 0 ~ 1
    depthTest={true} // 렌더링 시에 depth buffer 사용하여 검사할 것인지 여부
    depthWrite={true} // 렌더링 되고 있는 mesh의 z값을 depth buffer 에 기록할 것인지 여부
    side={THREE.FrontSide} // mesh의 어떤면을 렌더링할 것인지 (FrontSide / BackSide / DoubleSide)
    color={0xff0000} // 재질 색상
    emissive={0x00000}
    roughness={roughness} // 거칠기 0 ~ 1
    metalness={metalness} // 금속성 0 ~ 1 (거칠기와 금속성은 절절한 값 조절이 필요함)
    flatShading={false} // 재질의 면을 평평하게 할 것인지
    wireframe={false}
  />
</mesh>

meshLambertMaterial

물리 기반 렌더링(PBR)을 지원하지 않으므로 현실적인 재질 표현에 제한이 있음. 하지만 계산량이 적어 렌더링 속도가 빠름.

<meshLambertMaterial
  visible={true} // 렌더링 여부
  transparent={false} // opacity 사용 여부
  opacity={1} // 재질 불투명도 0 ~ 1
  depthTest={true} // 렌더링 시에 depth buffer 사용하여 검사할 것인지 여부
  depthWrite={true} // 렌더링 되고 있는 mesh의 z값을 depth buffer 에 기록할 것인지 여부
  side={THREE.FrontSide} // mesh의 어떤면을 렌더링할 것인지 (FrontSide / BackSide / DoubleSide)
  color='#b25383'
  wireframe={true}
  emissive='#d5d500'
/>

meshPhongMaterial

픽셀 단위로 광원의 영향을 계산하는 재질이며, meshLambertMaterial 보다 정교한 쉐이딩 효과를 얻을 수 있음. MeshStandardMaterial 보다 덜 복잡하고 가볍지만 PBR 기술보다는 성능 및 현실적인 효과 면에서 떨어질 수 있음.

<meshPhongMaterial
  visible={true} // 렌더링 여부
  transparent={false} // opacity 사용 여부
  opacity={1} // 재질 불투명도 0 ~ 1
  depthTest={true} // 렌더링 시에 depth buffer 사용하여 검사할 것인지 여부
  depthWrite={true} // 렌더링 되고 있는 mesh의 z값을 depth buffer 에 기록할 것인지 여부
  side={THREE.FrontSide} // mesh의 어떤면을 렌더링할 것인지 (FrontSide / BackSide / DoubleSide)
  color={0xff0000} // 재질 색상
  emissive={0x000000} // 재질에서 방출하는 색상
  specular={0xffff00} // 광원에 의해 반사되는 색상
  shininess={100} // 반사의 정도
  flatShading={true} // 재질의 면을 평평하게 할 것인지
  wireframe={false}
/>

meshPhysicalMaterial

PBR 기술을 사용하여 현실적인 광택, 음영 및 광투과를 표현함. 빛이 투과하고 물체 내부를 밝혀주는 효과를 제공하여 유리같은 면을 표현할 수 있음. 거칠기와 금속도를 설정할 수 있음

...

const { roughness, metalness } = useControls({
  roughness: { value: 0, min: 0, max: 1, step: 0.1 },
  metalness: { value: 0, min: 0, max: 1, step: 0.1 },
  clearcoat: { value: 0, min: 0, max: 1, step: 0.01 },
  clearcoatRoughness: { value: 0, min: 0, max: 1, step: 0.01 },
});

...

<mesh ref={mesh1} position={[0.7, 0, 0]}>
  <boxGeometry />
  <meshPhysicalMaterial
    visible={true} // 렌더링 여부
    transparent={false} // opacity 사용 여부
    opacity={1} // 재질 불투명도 0 ~ 1
    depthTest={true} // 렌더링 시에 depth buffer 사용하여 검사할 것인지 여부
    depthWrite={true} // 렌더링 되고 있는 mesh의 z값을 depth buffer 에 기록할 것인지 여부
    side={THREE.FrontSide} // mesh의 어떤면을 렌더링할 것인지 (FrontSide / BackSide / DoubleSide)
    color={0xff0000} // 재질 색상
    emissive={0x00000}
    roughness={roughness} // 거칠기 0 ~ 1
    metalness={metalness} // 금속성 0 ~ 1 (거칠기와 금속성은 절절한 값 조절이 필요함)
    flatShading={false} // 재질의 면을 평평하게 할 것인지
    wireframe={false}
    clearcoat={clearcoat} // 코팅 0 ~ 1
    clearcoatRoughness={clearcoatRoughness} // 코팅 거칠기 0 ~ 1
  />
</mesh>

meshDepthMaterial

물체의 깊이(depth) 정보에 기반하여 렌더링함. 즉, 카메라로부터 얼마나 떨어져 있는지를 나타내는 값에 따라 그림자 및 표면 디테일을 표현함. 주로 그림자 생성 및 거리에 따른 시각적 효과를 조절하는 데 사용함.

{/* camera 로부터 2.5 떨어진 지점은 0을 할당하고, 6인 지점은 1을 할당하여 렌더링한 재질의 표현 */}
<Canvas camera={{ near: 3.5, far: 6 }}>
  ...
  <mesh ref={mesh1} position={[0.7, 0, 0]}>
    <torusKnotGeometry args={[0.5, 0.15, 256, 128]} />
    <meshDepthMaterial />
  </mesh>
  ...
</Canvas>

meshMatcapMaterial

Matcap(Material Capture) 텍스처 기반 렌더링.
Matcap은 실제 광원의 반사를 이미지로 캡처한 텍스처로, 이 텍스처를 사용하여 물체의 표면이 실제 광원을 반사하는 것처럼 렌더링함. 아래의 코드를 보면 조명 코드를 지워도 해당 결과물이 나옴.

matCaps 재질을 위한 이미지 다운로드 링크

import { useRef, useEffect } from 'react';
import { OrbitControls, useTexture } from '@react-three/drei';

const Matcap = () => {
  const mesh1 = useRef();
  const mesh2 = useRef();

  // useTexture를 사용하여 이미지를 로드하고, 로드된 텍스처 객체를 반환
  const matcap = useTexture('./images/matcap/gold.jpg');

  useEffect(() => {
    mesh2.current.material = mesh1.current.material;
  }, []);

  return (
    <>
      {/* 컨트롤러 */}
      <OrbitControls />

      <mesh ref={mesh1} position={[0.7, 0, 0]}>
        <torusKnotGeometry args={[0.5, 0.15, 256, 128]} />
        <meshMatcapMaterial matcap={matcap} flatShading={true} />
      </mesh>

      <mesh ref={mesh2} position={[-0.7, 0, 0]}>
        <torusGeometry args={[0.5, 0.2]} />
      </mesh>
    </>
  );
};

export default Matcap;

meshNormalMaterial

매쉬 표면에 대한 법선 벡터의 x, y, z 값을 색상 요소값인 RGB 값으로 사용하여 표현함.

import { useRef, useEffect } from 'react';
import { OrbitControls, useTexture } from '@react-three/drei';

const Normal = () => {
  const mesh1 = useRef();
  const mesh2 = useRef();

  useEffect(() => {
    mesh2.current.material = mesh1.current.material;
  }, []);

  return (
    <>
      {/* 컨트롤러 */}
      <OrbitControls />

      <mesh ref={mesh1} position={[0.7, 0, 0]}>
        <torusKnotGeometry args={[0.5, 0.15, 256, 128]} />
        <meshNormalMaterial />
      </mesh>

      <mesh ref={mesh2} position={[-0.7, 0, 0]}>
        <torusGeometry args={[0.5, 0.2]} />
      </mesh>
    </>
  );
};

export default Normal;

meshToonMaterial

매쉬 표면에 대한 법선 벡터의 x, y, z 값을 색상 요소값인 RGB 값으로 사용하여 표현함.

tone.jpg 다운로드 링크


(좌: threeTone.jpg 중: fourTone.jpg 우: fiveTone.jpg)

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

const Toon = () => {
  const mesh1 = useRef();
  const mesh2 = useRef();

  const texture = useTexture('./images/tone/fiveTone.jpg');
  // 텍스처의 픽셀화된 모습을 유지하도록 함.
  texture.minFilter = THREE.NearestFilter; // 텍스처가 축소될 때 => 가장 가까운 픽셀의 값을 사용하여 텍스처를 축소하는 필터링 방법
  texture.magFilter = THREE.NearestFilter; // 텍스처가 확대될 때 => 가장 가까운 픽셀의 값을 사용하여 텍스처를 확대하는 필터링 방법

  useEffect(() => {
    mesh2.current.material = mesh1.current.material;
  }, []);

  return (
    <>
      {/* 컨트롤러 */}
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <mesh ref={mesh1} position={[0.7, 0, 0]}>
        <torusKnotGeometry args={[0.5, 0.15, 256, 128]} />
        <meshToonMaterial gradientMap={texture} color='cyan' />
      </mesh>

      <mesh ref={mesh2} position={[-0.7, 0, 0]}>
        <torusGeometry args={[0.5, 0.2]} />
      </mesh>
    </>
  );
};

export default Toon;



🪴Drei Material 클래스별 특성

공식문서에서 Material 클래스 검색


MeshReflectorMaterial

주로 어떤 물체의 표면을 반사하는데 사용함. 거울이나 유리와 같은 반사적인 표면을 표현할 수 있음.

import { MeshReflectorMaterial, OrbitControls } from '@react-three/drei';

const Reflector = () => {
  return (
    <>
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <mesh position={[0, -0.6, 0]} rotation={[-Math.PI / 2, 0, 0]}>
        <planeGeometry args={[10, 10]} />
        <MeshReflectorMaterial
          blur={[300, 100]}
          resolution={2048}
          mixBlur={1}
          mixStrength={30}
          roughness={1}
          depthScale={0.7}
          minDepthThreshold={0.4}
          maxDepthThreshold={1.4}
          color='#777777'
          metalness={0.5}
        />
      </mesh>

      <mesh position={[0, 0, 0]}>
        <boxGeometry />
        <meshStandardMaterial color='cyan' />
      </mesh>
    </>
  );
};

export default Reflector;

MeshRefractionMaterial

3D 배경을 위한 HDR 이미지

import { useLoader } from '@react-three/fiber';
import { CubeCamera, MeshRefractionMaterial, OrbitControls } from '@react-three/drei';
import { RGBELoader } from 'three-stdlib';

const Refraction = () => {
  const texture = useLoader(RGBELoader, './images/hdr/shanghai_bund_1k.hdr');

  return (
    <>
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <CubeCamera resolution={1024} frames={1} envMap={texture}>
        {(texture) => (
          <mesh position={[0, -0.6, 0]} rotation={[-Math.PI / 2, 0, 0]}>
            <dodecahedronGeometry />
            <MeshRefractionMaterial
              envMap={texture}
              toneMapped={false}
              bounces={2}
              aberrationsStrength={0.03}
              ior={2.75}
              fresnel={1}
              color='white'
              fastChroma={true}
            />
          </mesh>
        )}
      </CubeCamera>
    </>
  );
};

export default Refraction;

MeshTransmissionMaterial

주로 투명한 물체를 렌더링하는 데 사용함. 유리, 투명한 플라스틱, 물 등의 재질을 표현할 때 사용함.

import * as THREE from 'three';
import { MeshTransmissionMaterial, OrbitControls } from '@react-three/drei';
import { useControls } from 'leva';

const Transmission = () => {
  const config = useControls({
    transmissionSampler: false,
    backside: false,
    samples: { value: 10, min: 1, max: 32, step: 1 },
    resolution: { value: 2048, min: 256, max: 2048, step: 256 },
    transmission: { value: 1, min: 0, max: 1 },
    roughness: { value: 0.0, min: 0, max: 1, step: 0.01 },
    thickness: { value: 3.5, min: 0, max: 10, step: 0.01 },
    ior: { value: 1.5, min: 1, max: 5, step: 0.01 },
    chromaticAberration: { value: 0.06, min: 0, max: 1 },
    anisotropy: { value: 0.1, min: 0, max: 1, step: 0.01 },
    distortion: { value: 0.0, min: 0, max: 1, step: 0.01 },
    distortionScale: { value: 0.3, min: 0.01, max: 1, step: 0.01 },
    temporalDistortion: { value: 0.5, min: 0, max: 1, step: 0.01 },
    clearcoat: { value: 1, min: 0, max: 1 },
    attenuationDistance: { value: 0.5, min: 0, max: 10, step: 0.01 },
    attenuationColor: '#ffffff',
    color: '#c9ffa1',
    bg: '#839681',
  });

  return (
    <>
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <mesh>
        <sphereGeometry args={[1.4, 128, 128]} />
        <MeshTransmissionMaterial {...config} background={new THREE.Color(config.bg)} />
      </mesh>

      <mesh scale={0.3}>
        <torusGeometry args={[0.5, 0.2, 32]} />
        <meshStandardMaterial />
      </mesh>
    </>
  );
};

export default Transmission;

MeshWobbleMaterial

웨이블(wobble) 효과: 물체의 표면이나 전체적인 형태가 일정한 주기로 변형되는 효과.
따라서 물체의 표면이나 전체적인 형태가 일정한 주기로 변형되도록 할
때 사용함.

import { MeshWobbleMaterial, OrbitControls } from '@react-three/drei';

const Wobble = () => {
  return (
    <>
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <mesh>
        <torusGeometry />
        <MeshWobbleMaterial
          factor={1} // 흔들림 정도
          speed={10} // 흔들림 속도
        />
      </mesh>
    </>
  );
};

export default Wobble;

MeshDistortMaterial

물체의 표면을 왜곡시키는 효과를 줄 때 사용함.

import { MeshDistortMaterial, OrbitControls } from '@react-three/drei';

const Distort = () => {
  return (
    <>
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <mesh>
        <torusGeometry />
        <MeshDistortMaterial 
          distort={0.9} // 왜곡 정도
          speed={3}   // 왜곡 속도
        />
      </mesh>
    </>
  );
};

export default Distort;

MeshDiscardMaterial

재질이 적용된 메시를 화면에 표시하지 않도록 함.

일반적인 mesh에 visible={false} 속성을 주는 것과의 차이점

MeshDiscardMaterial 은 화면에 표시하지는 않지만 그림자는 표현함.

import { MeshDiscardMaterial, OrbitControls } from '@react-three/drei';

const Discard = () => {
  return (
    <>
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <mesh>
        <torusGeometry />
        <MeshDiscardMaterial />
      </mesh>
    </>
  );
};

export default Discard;

shaderMaterial

사용자 정의 쉐이더(Shader)를 통해 물체의 렌더링을 제어하는 데 사용하며, 비교적 저수준의 재질이지만 내장된 재질외에 사용자가 커스텀하여 고급 렌더링으로 사용할 수 있음.

import * as THREE from 'three';
import { extend } from '@react-three/fiber';
import { OrbitControls, shaderMaterial } from '@react-three/drei';

const SimpleMaterial = new shaderMaterial(
  // [첫번째 인자] uColor라는 uniform을 정의하여 색상정보를 GPU에 전달
  {
    uColor: new THREE.Color(1, 0, 0),
  },

  // [두번째 인자] Vertex(꼭짓점) Shader: Geometry의 좌표값을 화면에 출력하기 위한 좌표로 변경하는 목적
  `
  varying vec2 vUv;

  void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`,

  // [세번째 인자] Fragment shader: mesh가 화면에 픽셀 단위로 표시될 때 각 픽셀에 생상 값을 결정하는 목적
  // 버텍스 쉐이더에서 계산된 정보를 사용하여 각 픽셀의 색상을 결정함.
  `
  uniform vec3 uColor;
  varying vec2 vUv;

  void main() {
    gl_FragColor = vec4(vUv.y * uColor, 1.0);
  }
`
);

// SimpleMaterial를 태그 형태로 사용하기 위해서 R3F의 extend 함수를 사용함.
extend({ SimpleMaterial });

const Shader = () => {
  return (
    <>
      <OrbitControls />

      <ambientLight intensity={0.2} />
      <directionalLight position={[0, 1, 0]} />
      <directionalLight position={[1, 2, 8]} intensity={0.7} />

      <mesh>
        <boxGeometry />
        <simpleMaterial uColor={'red'} /> {/* jsx 에서는 소문자로 사용 */} {/* uColor를 전달할 수 있음 */}
      </mesh>
    </>
  );
};

export default Shader;


0개의 댓글