[Three.js] 2. 물체(Object)의 변형 position scale rotation group
Scene 의 물체를 변경하는 요소는 크게 3가지가 있습니다.
- 물체의 이동 : Position
- 물체의 사이즈 변형 : Scale
- 물체의 회전 : Rotation, Quaternion ( 사원수 )
Object3D 클래스를 상속하는 모든 클래스에는 PerspectiveCamera 또는 Mesh와 같은 속성과 기타 클래스가 있습니다. 각 클래스가 어떤 클래스를 상속하는지는 Three.js 문서에서 확인할 수 있습니다. 이러한 속성은 매트릭스(matrices : 행렬)라는 이름으로 컴파일됩니다. 매트릭스는 내부적으로 Three.js, WebGL, GPU에서 사물을 변환하는 데 사용됩니다. 매트릭스를 직접 처리할 필요는 없으며 앞서 언급한 속성을 수정하면 됩니다.
0. Axes helper( 축 도우미 )
공간에서 사물의 위치를 정하는 것은 정말 어려울 수 있습니다. 특히 카메라를 움직이기 시작할 때 각 축의 방향을 파악하는 것은 복잡합니다. 한 가지 좋은 해결책은 Three.js 축 도우미를 사용하는 것입니다. 축 도우미는 장면의 중앙에서 시작하여 해당 방향으로 가는 x, y 및 z 축에 해당하는 3개의 선을 표시합니다. 축 도우미를 생성하려면 해당 scene을 인스턴스화한 직후에 인스턴스화하고 scene에 추가합니다. 선의 길이를 유일한 파라미터로 지정할 수 있습니다. 2를 사용하겠습니다:
/**
* Axes Helper
*/
const axesHelper = new THREE.AxesHelper(2) // 2는 축의 길이입니다
scene.add(axesHelper)
처음에는 녹색과 빨간색 선이 보일 것입니다. 녹색 선은 y축에 해당합니다. 빨간색 선은 x축에 해당하고 파란색 선은 z축에 해당하지만 카메라와 완벽하게 정렬되어 있기 때문에 보이지 않습니다.
아래 처럼 카메라의 위치를 조정해줘야 파란색 선이 보일겁니다.
camera.position.set(1,1,4)
1. 이동
position은 3D 공간에서 무언가를 배치하는 데 필요한 세 가지 필수 속성인 x, y, z를 가지고 있습니다.
각 축의 방향은 순전히 임의적이며 환경에 따라 달라질 수 있습니다.
Three.js에서는 일반적으로 y축은 위쪽, z축은 뒤쪽, x축은 오른쪽으로 이동하는 것으로 간주합니다.
render(...) 메서드를 호출하기 전에 이 작업을 수행해야 메시를 이동하기 전에 렌더링할 수 있습니다.
mesh.position.x = 0.7
mesh.position.y = - 0.6
mesh.position.z = 1
//혹은 아래처럼 사용도 가능하다
mesh.position.set(0.7, - 0.6, 1)
position 속성은 어떤 객체가 아니며 Vector3 클래스의 인스턴스입니다.
이 클래스에는 x, y, z 프로퍼티가 있지만 유용한 메서드도 많이 있습니다.
벡터는 크기와 방향을 모두 가진 수학적 개념입니다.
일상생활에서 볼 수 있는 예로는 바람이나 움직이는 물체를 들 수 있습니다.
1. 크기: 벡터의 길이를 나타냅니다. 예를 들어, 바람의 세기나 물체가 이동한 거리를 의미합니다.
2. 방향: 벡터가 향하는 곳을 나타냅니다. 예를 들어, 바람이 불어가는 방향이나 물체가 움직이는 방향을 의미합니다.
벡터는 보통 화살표로 표현됩니다:
- 화살표의 길이는 벡터의 크기를 나타냅니다.
화살표가 가리키는 방향은 벡터의 방향을 나타냅니다.
1 - 1. position 메서드들
1. length( ) : Float
벡터의 길이를 구할 수 있습니다: (0, 0, 0)에서 (x, y, z)까지의 직선 길이
console.log(mesh.position.length())
2. distanceTo ( v : Vector3 ) : Float
이 벡터에서 v까지의 거리를 계산합니다.
3. normalize ( ) : this
벡터의 값을 정규화할 수 있습니다(벡터의 길이를 1 단위로 줄이되 방향은 유지한다는 의미)
console.log(mesh.position.normalize())
4. set ( x : Float, y : Float, z : Float ) : this
타겟 벡터의 x, y, z 구성 요소를 설정합니다.
2. 사이즈 변형
scale도 Vector3입니다. 기본적으로 x, y 및 z는 1과 같으며, 이는 개체에 배율이 적용되지 않음을 의미합니다. 0.5를 값으로 입력하면 이 축에서 개체는 원래 크기의 절반이 되고, 2를 값으로 입력하면 이 축에서 원래 크기의 두 배가 됩니다. 이러한 값을 변경하면 개체의 크기가 그에 따라 조정되기 시작합니다.
mesh.scale.set(2, 0.25, 0.5) // x, y, z 축
3. 물체의 회전 ( Rotation 과 Quaternion )
회전은 position나 scale 보다 조금 더 까다로운 문제입니다. 회전을 처리하는 방법에는 두 가지가 있습니다.
자명한( self-evident ) rotation 속성을 사용할 수도 있지만 덜 자명한( less obvious ) quaternion 속성을 사용할 수도 있습니다. Three.js는 두 가지를 모두 지원하며, 하나를 업데이트하면 다른 하나가 자동으로 업데이트됩니다. 어느 쪽을 선호하느냐의 문제일 뿐입니다.
3 - 1. Rotation (오일러 각도)
회전 속성에도 x, y, z 속성이 있지만, 벡터3 대신 오일러 속성이 있습니다.
오일러의 x, y, z 속성을 변경할 때는 물체의 중심을 축 방향으로 막대기를 통과시킨 다음 그 막대기로 물체를 회전시킨다고 상상할 수 있습니다.
- y축으로 회전하면 회전목마처럼,
- x축으로 회전하면 자동차 바퀴가 회전하는 것처럼,
- z축으로 회전하면 비행기 앞의 프로펠러가 회전하는 것처럼 상상하면 됩니다.
이 축의 값은 라디안으로 표현됩니다.
반 회전을 달성하려면 3.14159...와 같이 써야 합니다.
자바스크립트의 Math.PI를 사용하여 파이 의 근사값을 얻을 수 있습니다.
mesh.rotation.x = Math.PI * 0.25
mesh.rotation.y = Math.PI * 0.25
이러한 로테이션을 결합하면 이상한 결과가 나올 수 있습니다.
X축을 회전하는 동안 다른 축의 방향도 변경되기 때문입니다.
오일러 각도에서의 회전은 X, Y, Z 순서로 적용되므로 한 축이 더 이상 효과가 없을 때 짐벌 잠금과 같은 이상한 동작이 발생할 수 있습니다.
짐벌 락은 아래 링크를 확인
https://youtu.be/_nJLDmue0h4?t=174&si=JAP_01UrFbAdiusP
이 순서를 변경하려면 reorder(...) 메서드 object.rotation.reorder('YXZ')를 사용하여 이 순서를 변경할 수 있습니다.
오일러는 이해하기 쉽지만 이 순서 문제로 인해 문제가 발생할 수 있습니다.
이것이 대부분의 엔진과 3D 소프트웨어가 쿼터니언이라는 다른 솔루션을 사용하는 이유입니다
3 - 2. Quaternion(쿼터니언 , 사원수)
쿼터니언 속성 역시 회전을 표현하지만 좀 더 수학적인 방식으로 순서 문제를 해결합니다.
여기서는 설명한 하고 사용방식에 대해서는 다루지 않겠습니다.
회전을 변경하면 쿼터니언이 업데이트된다는 점을 기억하세요.
즉, 두 가지 중 하나를 원하는 대로 사용할 수 있습니다.
카메라의 lookAt( ) 메서드
Object3D 인스턴스에는 객체에 무언가를 보도록 요청할 수 있는 lookAt(...)이라는 메서드가 있습니다.
오브젝트는 자동으로 -z 축을 사용자가 지정한 대상을 향해 회전합니다.
복잡한 수학이 필요하지 않습니다.
카메라를 오브젝트 방향으로 회전하거나
대포의 방향을 적을 향하게 하거나
캐릭터의 눈을 오브젝트로 이동하는 데 사용할 수 있습니다.
파라미터는 타겟이며 반드시 Vector3이어야 합니다.
camera.lookAt(new Vector3(0, - 1, 0))
큐브가 더 높은 것처럼 보이지만 실제로는 카메라가 큐브 아래를 보고 있습니다.
메시의 위치와 같은 기존 Vector3를 사용할 수도 있지만 메시가 씬의 중앙에 있기 때문에 기본 카메라 위치가 됩니다.
4. 사물의 그룹화
어느 시점에서 사물을 그룹화하고 싶을 수도 있습니다.
벽, 문, 창문, 지붕, 덤불 등으로 집을 짓고 있다고 가정해 보겠습니다.
다 지었다고 생각했을 때 집이 너무 작다는 것을 알게 되고 각 객체의 크기를 다시 조정하고 위치를 업데이트해야 합니다. 좋은 대안은 모든 객체를 컨테이너로 그룹화하고 해당 컨테이너의 크기를 조정하는 방법입니다.
Group 클래스로 이를 수행할 수 있습니다.
그룹을 인스턴스화하여 장면에 추가합니다. 이제 새 오브젝트를 만들려면 씬에 직접 추가하는 대신 add(...) 메서드를 사용하여 방금 만든 그룹에 추가할 수 있습니다.
Group 클래스는 Object3D 클래스에서 상속되므로 위치, 크기, 회전, 쿼터니언 및 lookAt과 같은 앞서 언급한 속성 및 메서드에 액세스할 수 있습니다. lookAt(...) 호출에 주석을 달고 이전에 만든 큐브 대신 3개의 큐브를 만들어 그룹에 추가합니다. 그런 다음 그룹에 변형을 적용합니다:
const group = new Group()
group.scale.y = 2
group.rotation.y = 0.2
scene.add(group)
const createCube = (x) => {
const cube = new Mesh(
new BoxGeometry(1, 1, 1),
new MeshBasicMaterial({ color: 0xff0000 })
)
cube.position.x = x
return cube
}
const cubePositions = [-1.5, 0, 1.5]
cubePositions.forEach(x => {
group.add(createCube(x))
})
도움되는 링크들 :