윗/밑면 반지름, 높이, 세그먼트 개수, 끝을 닫을지 여부, 원기둥 호의 시작각도, 호의 중심각.
2.5. DodecahedronGeometry
십이면체를 그린다. 반지름과 디테일한 정도가 전부다.
2.6. ExtrudeGeometry
경로를 따라 생성된 입체를 렌더링한다. 입체는 threejs의 Shape 객체를 통해 만들어질 수 있다.
2.7. IcosahedronGeometry
이십면체를 그린다.
2.8. SphereGeometry
구를 그린다. 구면 좌표계를 통한 그림도 지원한다.
2.8. 기타 Geometry
LatheGeometry : 선을 회전시켜 만든 모양을 렌더링한다.
OctahedronGeometry : 팔면체를 그린다.
ParametricGeometry : 매개 변수를 통해서 만든 입체를 렌더링하는 듯 하다.
PlaneGeometry : 평면을 그린다.
PolyhedronGeometry : 다면체를 그린다.
RingGeometry : 중앙이 비어 있는 CD같은 모양의 디스크를 그린다.
ShapeGeometry : 2D 윤곽선을 그린다.
TetrahedronGeometry : 사면체를 그린다.
TextGeometry : 텍스트를 그린다. 폰트를 따로 로딩해 줘야 한다.
TorusGeometry : 도넛 모양을 그린다.
TorusKnotGeometry : 원환 매듭 모양을 그린다.
TubeGeometry : 경로를 따라서 원통을 그린다.
EdgesGeometry : 다른 geometry를 받아서 각 면 사이 각이 thresholdAngle 이상일 때만 모서리를 그린다.
WireframeGeometry
3. Scene graph
씬 그래프는 요소의 계층 구조를 나타낸다. 각 요소의 지역 공간과 그 소속을 다루는 것이다. 예를 들어서 지구는 태양의 지역 공간에 속해서 태양을 공전한다. 그리고 달은 지구의 지역 공간에서 공전한다.
태양의 입장에서 보면 달은 괴상한 모양을 그리겠지만 달은 그냥 지구의 지역 공간만 신경쓰면 된다. threejs에서 이런 움직임을 모방하려 한다면 달을 지구의 자식으로 만들어서 지구의 지역 공간에서 공전하게 만들면 될 뿐이다.
기본 세팅과 같은 부분을 빼고 물체 좌표계간의 계층 구조를 만드는 코드는 다음과 같다.
4. Material
Material은 물체가 scene에 어떻게 나타날지를 결정한다. 이 속성은 material 생성자를 호출 시 값을 넘겨서 정할 수도 있고 생성한 다음 바꿀 수도 있다.
MeshBasicMaterial : 광원 영향을 받지 않음
MeshLambertMaterial : 광원 영향을 받는데, 정점에서만 광원을 계산함
MeshPhongMaterial : 픽셀 하나하나에서 광원을 계산한다. 이것도 근사 모델이긴 하지만 더 정확한 광원 모델링을 위해 사용한다.
옵션에서는 shininess, emissive등을 설정 가능하다.
만화 같은 스타일의 물체를 생성하는 MeshToonMaterial, 물리 기반 렌더링을 위한 MeshStandardMaterial, 더 고급의 물리 렌더링 특성을 제공하는 MeshPhysicalMaterial 등이 있다.
특수한 경우 사용하는 재질로는 그림자를 가져오는 ShadowMaterial, 픽셀의 깊이를 렌더링하는 MeshDepthMaterial, 법선을 렌더링하는 MeshNormalMaterial 등이 있다. 재질을 커스텀할 수 있게 해주는 ShaderMaterial도 존재한다. 이들은 당장 자세히 알 필요는 없을 것 같다.
4.1. 유명한 옵션
flatShading : 물체를 각지게 표현할지 여부, 기본값은 false
side : 어떤 면을 렌더링할지 여부, 기본값은 THREE.FrontSide이고 THREE.BackSide / THREE.DoubleSide도 있다.
재질을 만드는 건 연산이 많이 필요하기에 보통 한 번 만든 재질을 바꾸지는 않지만 만약 그래야 할 일이 있다면 material.needsUpdate = true로 설정해야 한다.
5. 텍스처
텍스처는 TextureLoader를 생성한 다음 load 메서드에 이미지를 넘겨서 호출한 후 반환된 값을 Material의 map 속성에 지정하는 방식으로 사용할 수 있다.
이 loader.load는 비동기로 작동한다. 2번째 인수로는 텍스처를 전부 불러온 후에 호출될 콜백을 지정할 수 있다. 다음과 같이 하면 텍스처를 전부 불러온 다음 화면을 렌더링한다.
다수의 텍스처를 불러올 땐 LoadingManager 사용. TextureLoader를 생성할 때 LoadingManager를 인수로 넘겨준다. 그리고 load 메서드를 호출할 때 2번째 인수로 텍스처를 전부 불러온 후에 호출될 콜백을 지정할 수 있다.
LoadingManager의 onProgress에 콜백 함수 지정시 현재 진행 상태도 추적할 수 있다.
단 텍스처는 메모리를 매우 많이 사용하므로 주의해서 사용하자. 보통 텍스처는 width * height * 4 * 1.33바이트의 메모리를 사용한다. 따라서 필요한 퀄리티를 유지하는 선에서 해상도를 낮추는 게 좋다.
그런데 텍스처의 크기가 딱 원본과 맞는 경우는 잘 없다. 이 경우 GPU는 mipmap이라는, 텍스처를 반 크기로 축소해 가면서 생성한 map들을 만들어 놓고 geometry와 가장 가까운 크기의 것을 골라서 렌더링한다.
사용되는 필터는 텍스처가 원본보다 클 경우 texture.magFilter를 사용하며 THREE.nearestFilter와 THREE.LinearFilter가 있다.
텍스처가 원본보다 작을 경우 texture.minFilter를 사용하며 THREE.NearestFilter, THREE.LinearFilter, THREE.NearestMipmapNearestFilter, THREE.NearestMipmapLinearFilter, THREE.LinearMipmapNearestFilter, THREE.LinearMipmapLinearFilter가 있다.
필요할 때마다 추가하자.
6. 조명
조명은 대표적으로 AmbientLight, DirectionalLight, HemisphereLight 가 있다.
6.1. AmbientLight
Ambient Light는 말 그대로 방향 같은 게 없이 scene에 전체적으로 적용되는 빛이다. 물체에 Light color를 곱해 주는 것 뿐이고 방향이나 어떤 물체에 더 비춰 준다는 개념이 없다.
6.2. HemisphereLight
반구 형태의 광원이다. 천장과 바닥의 색을 인자로 받아서 천장을 바라보는 색은 천장 색, 바닥을 바라보는 색은 바닥 색으로 혼합한다.
6.3. DirectionalLight
직사광이다. 생성자는 빛 색상과 강도를 인자로 받으며 position과 target을 설정해야 한다.
그런데 조명이 충분히 강하지 않으면 조명이 눈에 잘 안 들어올 수도 있다. 이런 경우를 대비해서 helper를 사용할 수 있다. helper는 조명의 위치를 표시해 준다. DirectionalLightHelper를 사용하자.
이 직사광은 한 점에서 뻗어나오는 게 아니다. 어떤 방향으로 빛이 비추는 것이다. 한 점에서 뻗어나오는 광원은 다음에 볼 PointLight이다.
6.4. PointLight
점 광원을 생성한다. 생성자는 빛 색상과 강도를 인자로 받으며 position을 설정해야 한다.
6.5. SpotLight
광원에서 원뿔 모양의 빛을 비추는 스포트라이트를 생성한다. 생성자는 빛 색상과 강도를 인자로 받으며 position, target, 각도, 빛의 범위를 설정해야 한다.
6.6. RectAreaLight
사각 형태의 조명이며 MeshStandardMaterial과 MeshPhysicalMaterial에서만 사용할 수 있다. 생성자는 빛 색상과 강도를 인자로 받으며 width, height도 설정해야 한다.
renderer.physicallyCorrectLights 속성을 true로 설정해서 켜게 되면 조명을 물리적으로 보정할 수 있다. 일단 넘어가자.
7. 카메라
이런 식으로 PerspectiveCamera를 생성할 수 있다.
near, far를 설정하는 건 매우 중요하다. 만약 near를 매우 작게 그리고 far를 매우 크게 설정한다면 모든 물체가 다 보일 것이다. 하지만 이는 카메라의 정밀도에 영향을 미친다.
정밀도는 near, far 사이에 어느 정도씩 퍼져 있는데 카메라에 가까울수록 정밀도가 높고 멀수록 낮아진다. 이럴 경우 z-fighting이라고 하는 현상이 발생해서 물체가 깨져 보이게 된다. WebGLRenderer 생성시 옵션으로 logarithmicDepthBuffer를 true로 설정하면 이 현상을 완화할 수 있다. 하지만 이는 일부 기기에서만 지원된다...
따라서 near, far를 주의깊게 설정해야 한다.
7.1. OrthographicCamera
이는 정사영 카메라다. 원근 카메라의 잘린 사각뿔 모양 대신 직육면체 모양의 카메라다. 생성자는 left, right, top, bottom, near, far를 인자로 받는다.
이 카메라는 받은 6개의 인자를 토대로 육면체를 만들고, 이 육면체 내의 물체들을 정사영해서 보여준다. 따라서 개체 크기가 카메라와의 거리에 관계없이 일정하게 유지된다.
8. 그림자
threeJS는 그림자 맵을 사용해서 그림자를 만든다. 이는 그림자를 만드는 모든 물체를 빛의 시점에서 렌더링함을 말한다. 따라서 그림자를 만드는 모든 물체들의 그림자 각각을 빛 각각이 한번씩 렌더링한다.
만약 20개의 물체와 5개의 조명이 있고 20개 물체 모두가 그림자를 만든다면 한 장면을 위해서 화면은 6번 렌더링된다(물체를 만드는 1번, 그림자를 만드는 5번).
따라서 그림자를 지게 하는 조명을 여러 개 만들기보다는 보통 다른 방법을 사용한다. 하나의 조명만 그림자를 지게 하거나 가짜 그림자를 만드는 등이다. 하지만 이는 나중에 알아보고, 그림자는 어떻게 사용하는가? renderer의 shadowMap 옵션을 켜고 조명도 그림자를 드리우도록 옵션을 켠다.
이렇게 하면 그림자 일부가 잘려 보이는데 이는 그림자용 카메라 범위 안에 있는 그림자만 렌더링하게 되기 때문이다. 이 그림자용 카메라는 위의 경우 DirectionalLight의 위치에 존재하며 해당 조명의 목표를 바라본다. 그리고 일정 공간 안의 그림자만 렌더링한다. 이 공간에 들어오지 않는 그림자가 잘려 나가는 것이다.