출처 : 유튜브 GIS DEVELOPER https://youtu.be/F4aTwdpFkfw
geometry에 UV좌표 개념으로 맵핑된다.
UV좌표는 three.js에서 제공하는 geometry에 기본적으로 지정되어있다.
const textureLoader = new THREE.TextureLoader();
const map = textureLoader.load("/images/texture.jpg", (texture) => {
// 이미지 반복 맵핑
texture.repeat.x = 2;
texture.repeat.y = 2;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// RepeatWrapping: 이미지를 반복해서 맵핑
// ClampToEdgeWrapping: 처음에만 이미지가 한 번 맵핑되고, 이후 반복부터는 이미지의 끝단 픽셀로 나머지 영역을 채움
// MirroredRepeatWrapping: 이미지를 x와 y 방향으로 반복하되, 짝수번째 반복에서는 이미지가 거울에 반사되어 뒤집힌 모양으로 맵핑됨
texture.offset.x = 0; // UV 좌표의 시작 위치 조정
texture.offset.y = 0;
texture.rotation = THREE.MathUtils.degToRad(45); // 이미지를 회전해서 맵핑
texture.center.x = 0.5; // 회전 기준 좌표
texture.center.y = 0.5;
texture.magFilter = THREE.LinearFilter; // 이미지의 원래 크기보다 화면에 더 크게 확대되어 랜더링
texture.minFilter = THREE.NearestMipMapLinearFilter; // 이미지의 원래 크기보다 화면에 더 작게 확대되어 랜더링
});
const material = new THREE.MeshStandardMaterial({
map: map,
});
출처 : 유튜브 GIS DEVELOPER https://youtu.be/F4aTwdpFkfw
-> mipMap을 사용한 경우가 랜더링 품질이 좋다.
하지만 항상 mipMap을 사용하는 것은 아님. mipMap 생성을 위한 메모리 사용량이 상당하고, 랜더링 시 하나의 픽셀값을 지정하기위한 계산에 필요한 연산량이 각 속성에 따라 모두 다르므로, 사용하는 텍스쳐 맵핑의 크기 등에 따라서 적절한 minFilter의 속성값을 지정해서 사용해야한다.
-> 대부분의 경우 기본값을 사용해도 무리가 없다.
지정되지 않은 특정 지점에 대한 노말 벡터는 이 박스의 구성 좌표의 노말 벡터들을 이용해 보간되어 계산된다.
normalMap을 사용하면 박스 표면의 노말 벡터를 normalMap 이미지의 RGB값을 이용해 계산한다.
이렇게 되면 인위적으로 mesh 표면의 각 픽셀에 대해 법선 벡터를 지정할 수 있게 되고 각 픽셀 단위로 광원 효과가 달라져 입체감을 표현할 수 있게 된다.
mesh의 geometry 형상이 바뀌는 것이 아니기 때문에 입체감은 착시현상이지만, 매우 적은 geometry의 좌표 구성만으로도 입체감을 매우 효과적으로 표현할 수 있는 방법이다.
import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper";
const textureLoader = new THREE.TextureLoader();
const map = textureLoader.load(
"/images/glass/Glass_Window_002_basecolor.jpg"
);
const mapNormal = textureLoader.load(
"/images/glass/Glass_Window_002_normal.jpg"
);
const material = new THREE.MeshStandardMaterial({
map: map,
normalMap: mapNormal,
});
const box = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material);
box.position.set(-1, 0, 0);
this._scene.add(box);
const boxHelper = new VertexNormalsHelper(box, 0.1, 0xffff00);
this._scene.add(boxHelper);
실제로 mesh의 geometry의 좌표를 변형시켜 입체감을 표현한다.
맵 이미지의 픽셀값이 밝을 수록 좌표의 변위가 커지게 된다.
박스의 경우, displacementMap이 실제 geometry의 구성 좌표를 변경시키기 때문에 이 박스의 표면에 대한 구성 좌표가 제공되어야 한다.
-> segment(분할 수)를 나눠준다.
displacementMap 효과를 위해 좌표를 더 많이 추가하는 것은 랜더링 속도면에서 비효율적이다.
-> 적절한 normalMap과 함께 displacementMap 효과를 위한 적절한 면 분할이 필요하다.
const textureLoader = new THREE.TextureLoader();
const mapHeight = textureLoader.load(
"/images/glass/Glass_Window_002_height.png"
);
const mapNormal = textureLoader.load(
"/images/glass/Glass_Window_002_normal.jpg"
);
const material = new THREE.MeshStandardMaterial({
normalMap: mapNormal,
displacementMap: mapHeight,
displacementScale: 0.2,
displacementBias: -0.15,
});
const box = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1, 256, 256, 256),
material
);
box.position.set(-1, 0, 0);
this._scene.add(box);
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(0.7, 512, 512),
material
);
sphere.position.set(1, 0, 0);
this._scene.add(sphere);
텍스쳐 이미지에 미리 음영 효과를 그려 넣은 것
미리 만들어진 세밀한 그림자와 같은 느낌의 효과를 줄 수 있다.
const material = new THREE.MeshStandardMaterial({
aoMap: mapAO,
aoMapIntensity: 2, // aoMap의 강도 지정. default: 1
});
const box = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1, 256, 256, 256),
material
);
box.position.set(-1, 0, 0);
box.geometry.attributes.uv2 = box.geometry.attributes.uv;
this._scene.add(box);
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(0.7, 512, 512),
material
);
sphere.position.set(1, 0, 0);
sphere.geometry.attributes.uv2 = sphere.geometry.attributes.uv;
this._scene.add(sphere);
이 속성에 대한 맵 이미지의 픽셀값이 밝을수록 거칠기가 강해진다.
const material = new THREE.MeshStandardMaterial({
roughnessMap: mapRoughness,
roughness: 0.5,
});
금속 재질에 대한 느낌을 부여한다.
const material = new THREE.MeshStandardMaterial({
metalnessMap: mapMetalic,
metalness: 0.5,
});
투명도. 이 속성에 대한 이미지의 픽셀값이 밝을수록 불투명해진다.
픽셀값이 완전한 검정색일 때 완전히 투명해진다.
const material = new THREE.MeshStandardMaterial({
alphaMap: mapAlpha,
transparent: true,
side: THREE.DoubleSide, // 물체의 뒷면이 보이도록 양면 랜더링
});
지정된 이미지의 색상으로 발광하는 느낌을 표현.
const material = new THREE.MeshStandardMaterial({
lightMap: mapLight,
lightMapIntensity: 0.5
});
box.geometry.attributes.uv2 = box.geometry.attributes.uv;