Three.js journey 11 - Materials

크롱·2024년 12월 3일
0

Three.js

목록 보기
8/12

textures 로드

/**
 * Objects
 */
const material = new THREE.MeshBasicMaterial();

const sphere = new THREE.Mesh(new THREE.SphereGeometry(0.5, 16, 16), material);
//SphereGeometry(radius, widthSegments, heightSegments)

sphere.position.x = -1.5;

const plane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material);

const torus = new THREE.Mesh(
  new THREE.TorusGeometry(0.3, 0.2, 16, 32),
  material
);

torus.position.x = 1.5;

scene.add(sphere, plane, torus);

우선 mesh들을 생성하고, texture들을 로드한뒤 material에 대해 알아보자



/**
 * Textures - material 이전에 선언!
 */

const textureLoader = new THREE.TextureLoader();

const doorColorTexture = textureLoader.load("./textures/door/color.jpg");
const doorAlphaTexture = textureLoader.load("./textures/door/alpha.jpg");
const doorAmbientOcclusionTexture = textureLoader.load(
  "./textures/door/ambientOcclusion.jpg"
);
...

//textures used as map and matcap are supposed to be encoded in sRGB and we need to inform Three.js of this by setting their colorSpace to THREE.SRGBColorSpace:
doorColorTexture.colorSpace = THREE.SRGBColorSpace; // 안하면 색깔 이상해짐
matcapTexture.colorSpace = THREE.SRGBColorSpace;

ColorTexture 처럼 map 으로 사용되거나 matcapTexture을 사용할 시 colorSpace를 SRGBColorSpace로 적용해야 색상이 잘 먹힌다



MeshBasicMaterial

💘MeshBasicMaterial💘

const material = new THREE.MeshBasicMaterial({ map: doorColorTexture });
위의 코드는 밑 2줄로 표현할 수 있다

const material = new THREE.MeshBasicMaterial();
material.map = doorColorTexture;

material.color = new THREE.Color("red");

material.wireframe = true;

material.transparent = true; // alpha 값 또는 opacity조정시 transparent true 필수
material.opacity = 0.4;
material.alphaMap = doorAlphaTexture; // 흰색 - 보임 /  검정 - 안보임

material.side = THREE.DoubleSide // DoubleSide - 프로세싱은 더 오래걸림, 예를들어 plane 뒷면도 보이고, sphere 내부로 들어갈수도있음 // default - FrontSide
👉 블렌더에서 import 하면 디폴트값이 DoubleSide이다

MeshNormalMaterial

Normals are information encoded in each vertex that contains the direction of the outside of the face. If you displayed those normals as arrows, you would get straight lines coming out of each vertex that compose your geometry.

특정 face를 비추거나 빛이 제오메트리의 표면을 어떻게 reflect / refract 하는지를 결정할때 Normal을 사용한다.

When using the MeshNormalMaterial, the color will just display the normal orientation relative to the camera. If you rotate around the sphere, you'll see that the color is always the same, regardless of which part of the sphere you're looking at.

const material = new THREE.MeshNormalMaterial();
material.wireframe = true  MeshBasicMaterial처럼 이런거 다 가능 !

🌟new🌟
material.flatShading = true

MeshMatcapMaterial

MeshMatcapMaterial은 성능을 유지하면서도 매우 멋진 외관을 제공하기 때문에 환상적인 material이다. 이 material가 작동하기 위해서는 위 사진처럼 구 모양처럼 보이는 참조 텍스처가 필요하다.
material는 카메라에 대한 normal 방향에 따라 텍스처에서 색상을 선택하게 된다. 즉 카메라를 돌려도 항상 같은 한 방향에 따라 텍스쳐의 색상이 결정됨
(ex. 위 텍스처를 적용한다고 한다면 제오메트리는 카메라를 돌려도 항상 왼-위는 붉은색, 오-위는 노란색)

카메라의 방향에 무관하게 착시가 동일하다는 단점!

const material = new THREE.MeshMatcapMaterial()
material.matcap = matcapTexture

MeshLambertMaterial

✨퍼포먼스가 좋은, 빛을 필요로 하는 material✨
MeshBasicMaterial와 같이 프로퍼티들에 접근 가능하지만 빛에 관한 프로퍼티도 존재한다.
light을 사용할 때 가장 이상적인 material 이지만 구와 같이 둥근형상을 확대해서 보면 이상한 라인들이 생성된 것을 볼 수 있다

const material = new THREE.MeshLambertMaterial();

MeshPhongMaterial

MeshLambertMaterial과 비슷하지만, 이상한 라인이 덜 보이고 빛의 반사를 볼 수 있다. 하지만 성능은 조금 떨어진다고한다.
shininess 프로퍼티로 빛의 반사를 제어할 수 있고 값이 높을 수록 표면이 더 반짝거린다. specular는 반사될때 반짝거리는 빛의 색상이다

const material = new THREE.MeshPhongMaterial();
material.shininess = 100;
material.specular = new THREE.Color("red");

MeshToonMaterial

MeshLambertMaterial와 비슷한 프로퍼티를 가지고있지만 cartoon 스타일이다

const material = new THREE.MeshToonMaterial()
material.gradientMap = gradientTexture

엥ㅇ? 근데 카툰스타일이 아닌데요?

그 이유는 gradientTexture의 사이즈가 너무 작아 mipmapping 때문에 텍스쳐의 픽셀들이 stretch 되어서 mipmapping 되어버렸기 때문이다

첫번째 3개의 띠로 이루어진게 원래 텍스처인데 너무 작아서 2번째처럼 그라디언 된거임
하지만 나는 마인크래프트같은 첫번째 효과를 원하기때문에 mipmapping을 해제해야한다.

const material = new THREE.MeshToonMaterial()
gradientTexture.minFilter = THREE.NearestFilter
gradientTexture.magFilter = THREE.NearestFilter
gradientTexture.generateMipmaps = false // gpu 에게 좋다
material.gradientMap = gradientTexture


MeshStandardMaterial💞

자주쓰이는 MeshStandardMaterial

MeshStandardMaterial은 물리 기반 렌더링 원칙을 사용하고, 이는 PBR이 적용된다는것!
MeshLambertMaterial와 MeshPhongMaterial처럼 light을 지원하지만, 더 현실적인 알고리즘과 거칠기(roughness), 금속성(metalness) 같은 더 나은 매개변수를 가지고 있다.

"표준"이라고 불리는 이유는 PBR이 많은 소프트웨어, 엔진, 라이브러리에서 표준이 되었기 때문이다. 이는 현실적인 매개변수를 사용하여 현실적인 결과를 얻는 것이며, blender, 언리얼엔진에서 사용되는 사실적인 표현을 three.js 에서도 가능하게함

import GUI from 'lil-gui'

/**
 * Debug
 */
const gui = new GUI()



// MeshStandardMaterial
const material = new THREE.MeshStandardMaterial()
material.metalness = 0.7
material.roughness = 0.2 // 작을수록 매끄럽다

gui.add(material, 'metalness').min(0).max(1).step(0.0001)
//material의 metalness 에 접근하므로
gui.add(material, 'roughness').min(0).max(1).step(0.0001)

Environment Map

Environment Map을 추가해보자

import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'


// 텍스처 로더와 비슷하다. 인스턴스를 생성해주자
const rgbeLoader = new RGBELoader()

rgbeLoader.load('./textures/environmentMap/2k.hdr', (environmentMap) => {
  environmentMap.mapping = THREE.EquirectangularReflectionMapping

  scene.background = environmentMap; // 2k.hdr 배경 적용
  scene.environment = environmentMap; // 2k.hdr 배경 빛이 objects에 적용
})

더 많은 프로퍼티들

// MeshStandardMaterial
const material = new THREE.MeshStandardMaterial()
material.metalness = 0.7
material.roughness = 0.2 


material.map = doorColorTexture;
material.aoMap = doorAmbientOcclusionTexture;
material.aoMapIntensity = 1;
  • map
    👉 The map property allows you to apply a simple texture
  • aoMap (ambient occlusion map)
    👉 텍스처 어두운 부분에 그림자를 추가하여 깊이감을 더해줌. aoMapIntensity를 통해 어두움의 정도를 정할수있다
    👉 aoMap은 참고로 AmbientLight, environment map, 그리고 HemisphereLight 에서 만들어진 light에만 효과가있다.






new THREE.PlaneGeometry(1, 1, 100, 100)...

material.displacementMap = doorHeightTexture
material.displacementScale = 0.1
  • displacementMap 프로퍼티는 relief 입체감을 만들기위해 버텍스들을 움직인다. 그래서 object의 subdivision을 많이 만들어야한다는 단점



const material = new THREE.MeshStandardMaterial();

material.metalness = 1;
material.roughness = 1;
material.metalnessMap = doorMetalnessTexture
material.roughnessMap = doorRoughnessTexture


//normal map
material.normalMap = doorNormalTexture;
material.normalScale.set(0.5, 0.5); //노말맵 강도 설정


doorMetalnessTexture 인데, material에 metalnessMap 프로퍼티를 통해 metalness를 더 표현해보자 ( Roughness 도 가능)

👇그리고 normalMap을 통해 진짜 현실 문같이 디테일이 가득한 문이 완성됨




material.transparent = true //꼭!
material.alphaMap = doorAlphaTexture
  • alpha 로 겉에 부분이 투명해져서 최종적으로 문만 남음

MeshPhysicalMaterial

MeshStandardMaterial와 99퍼센트 똑같지만 더 사실적으로 표현가능하게하는 프로퍼티들을 4개 더 사용할 수 잇다

  • learcoat
  • sheen
  • iridescence
  • transmission

근데 퍼포먼스가 너무(제일) 안좋음..ㅠㅠ


const material = new THREE.MeshPhysicalMaterial()

// Clearcoat
material.clearcoat = 1
material.clearcoatRoughness = 0

gui.add(material, 'clearcoat').min(0).max(1).step(0.0001)
gui.add(material, 'clearcoatRoughness').min(0).max(1).step(0.0001)


//Sheen
material.sheen = 1
material.sheenRoughness = 0.25
material.sheenColor.set(1, 1, 1)

gui.add(material, 'sheen').min(0).max(1).step(0.0001)
gui.add(material, 'sheenRoughness').min(0).max(1).step(0.0001)
gui.addColor(material, 'sheenColor')


// iridescense
material.iridescence = 1
material.iridescenceIOR = 1
material.iridescenceThicknessRange = [ 100, 800 ]

gui.add(material, 'iridescence').min(0).max(1).step(0.0001)
gui.add(material, 'iridescenceIOR').min(1).max(2.333).step(0.0001)
gui.add(material.iridescenceThicknessRange, '0').min(1).max(1000).step(1)
gui.add(material.iridescenceThicknessRange, '1').min(1).max(1000).step(1)

// Transmission
material.transmission = 1
material.ior = 1.5
material.thickness = 0.5

gui.add(material, 'transmission').min(0).max(1).step(0.0001)
gui.add(material, 'ior').min(1).max(10).step(0.0001)
gui.add(material, 'thickness').min(0).max(1).step(0.0001)

  • clearcoat
    기존 마테리얼 위에 매니큐어 바른것처럼 덧대는것.

    The clearcoat will simulate a thin layer of varnish on top of the actual material. This layer has its own reflective properties while we can still see the default material behind it.

  • Sheen
    패브릭같은 머테리얼에 사실감을 줍니다

  • iridescense

    이런 빛(?) 머테리얼 표면에 생성함

  • Transmission

☑ 오브젝트가 반투명한것처럼 보인다

☑ 빛이 머테리얼을 통과시키도록 한다 => 오브젝트 뒷면이 더 사실적으로 표현됨

ior 은 뭔진 잘 모르겠지만 만약 내가 diamond를 구현하고싶으면 2.417, 물은 1.333 공기는 1.000293

모든 프로퍼티 지우고 metalness와 roughness만 0으로 만들어보자

const material = new THREE.MeshPhysicalMaterial()
material.metalness = 0
material.roughness = 0
// material.map = doorColorTexture
// material.aoMap = doorAmbientOcclusionTexture
// material.aoMapIntensity = 1
// material.displacementMap = doorHeightTexture
// material.displacementScale = 0.1
// material.metalnessMap = doorMetalnessTexture
// material.roughnessMap = doorRoughnessTexture
// material.normalMap = doorNormalTexture
// material.normalScale.set(0.5, 0.5)
// material.transparent = true
// material.alphaMap = doorAlphaTexture

// Transmission
material.transmission = 1
material.ior = 1.5
material.thickness = 0.5

gui.add(material, 'transmission').min(0).max(1).step(0.0001)
gui.add(material, 'ior').min(1).max(10).step(0.0001)
gui.add(material, 'thickness').min(0).max(1).step(0.0001)

이런식으로 됩니다요

roughness를 추가하면 glossy 해짐

결론

좋은 퍼포먼스를 내는 마테리얼 선정이 중요. 퍼포먼스가 좋은 MeshLambertMaterial로 좋은결과를 낼 수 있다면 이걸 사용하자
카메라를 obj 주변으로 움직일수없거나 빛 또한 움직일 수 없을때는 Matcap을 사용하셈.


참고: https://velog.io/@9rganizedchaos/Three.js-journey-%EA%B0%95%EC%9D%98%EB%85%B8%ED%8A%B8-12#meshbasicmaterial

profile
👩‍💻안녕하세요🌞

0개의 댓글