큐브 매핑

왼쪽 아래 이미지는 검은색 점으로 표시된 시점을 가진 장면을 보여준다. 위쪽 이미지는 해당 시점에서 본 큐브 매핑의 전개도를 보여주며, 오른쪽 아래 이미지는 원본 장면에 겹쳐진 큐브를 보여준다. textcontrols=1 컴퓨터 그래픽스에서 **큐브 매핑**(Cube mapping)은 맵 형태로 정육면체의 여섯 면을 사용하는 환경 매핑의 한 방법이다. 환경은 정육면체의 측면에 투영되어 여섯 개의 정사각형 텍스처로 저장되거나, 단일 텍스처의 여섯 영역으로 펼쳐진다. 큐브 맵은 먼저 시점에서 장면을 여섯 번 렌더링하여 생성되는데, 각 뷰는 각 큐브 면을 나타내는 90도 시야 절두체로 정의된다.Fernando, R. & Kilgard M. J. (2003). The CG Tutorial: The Definitive Guide to Programmable Real-Time Graphics. (1st ed.). Addison-Wesley Longman Publishing Co., Inc. Boston, MA, USA. Chapter 7: Environment Mapping Techniques 또는 환경이 먼저 구에 투영된다고 간주되면, 큐브의 각 면은 해당 심사도법이다. 대부분의 경우 큐브 매핑은 이미지 왜곡, 시점 의존성, 계산 비효율성 등 구 매핑에 내재된 많은 문제들을 제거하기 때문에 오래된 구 매핑 방식보다 선호된다. 또한, 큐브 매핑은 구 매핑에 비해 반사의 실시간 렌더링을 지원하는 훨씬 더 큰 용량을 제공하는데, 이는 비효율성과 시점 의존성의 조합이 시점이 지속적으로 변경될 때 구 매핑을 적용할 수 있는 능력을 심각하게 제한하기 때문이다. 큐브 매핑의 변형은 360도 비디오 프로젝션에도 일반적으로 사용된다.language=en-us
# 역사
큐브 매핑은 짐 블린과 마틴 뉴웰이 환경 매핑을 처음 제안한 지 10년 후인 1986년에 네드 그린이 그의 논문 "환경 매핑 및 기타 세계 투영의 응용"에서 처음 제안했다.s2cid = 11301955 그러나 동시에 6개의 텍스처 이미지에 접근하는 하드웨어 제약으로 인해 추가적인 기술 개발 없이는 큐브 매핑을 구현하는 것이 불가능했다. 이 문제는 1999년 엔비디아 지포스 256이 출시되면서 해결되었다. 엔비디아는 하드웨어 큐브 매핑을 "지포스 256의 획기적인 이미지 품질 기능으로 ... 개발자들이 정확한 실시간 반사를 생성할 수 있도록 할 것이다. 하드웨어 가속 큐브 환경 매핑은 개발자들의 창의력을 발휘하여 반사 및 스페큘러 조명 효과를 사용하여 흥미롭고 몰입감 있는 환경을 만들 수 있도록 할 것이다."라고 홍보했다.Nvidia, Jan 2000. Technical Brief: Perfect Reflections and Specular Lighting Effects With Cube Environment Mapping date=2008-10-04 오늘날 큐브 매핑은 환경 매핑의 선호되는 방법으로 다양한 그래픽 응용 프로그램에서 여전히 사용된다.
# 장점
큐브 매핑은 상대적으로 단순하기 때문에 다른 환경 매핑 방법보다 선호된다. 또한 큐브 매핑은 광선 추적을 통해 얻은 결과와 유사한 결과를 생성하지만, 훨씬 더 계산적으로 효율적이다. 품질의 중간 정도 감소는 효율성에서 큰 이득으로 보상된다. 큐브 매핑 이전에 존재했던 구 매핑은 대부분의 응용 프로그램에 비실용적인 많은 내재된 결함을 가지고 있었다. 구 매핑은 시점 의존적이며, 이는 각 시점에 대해 다른 텍스처가 필요하다는 것을 의미한다. 따라서 시점이 움직이는 응용 프로그램에서는 각 새로운 시점에 대해 새로운 구 매핑을 동적으로 생성하거나, 모든 시점에 대한 매핑을 미리 생성해야 한다. 또한 구의 표면에 매핑된 텍스처는 늘리거나 압축해야 하므로 뒤틀림과 왜곡(특히 구의 가장자리를 따라)이 직접적인 결과로 발생한다. 이러한 이미지 결함은 "미리 늘리기"와 같은 특정 트릭과 기술을 사용하여 줄일 수 있지만, 이는 구 매핑에 또 다른 복잡성을 더할 뿐이다. 포물면 매핑은 구 매핑의 한계에 대한 일부 개선을 제공하지만, 특수한 이미지 왜곡 작업과 더 복잡한 계산 외에 두 번의 렌더링 패스가 필요하다. 반대로 큐브 매핑은 단일 렌더링 패스만 필요하며, 단순한 특성으로 인해 개발자가 이해하고 생성하기 매우 쉽다. 또한 큐브 매핑은 텍스처 이미지의 전체 해상도를 사용하며, 구 및 포물면 매핑과 비교하여 더 낮은 해상도의 이미지를 사용하여 동일한 품질을 얻을 수 있다. 큐브 맵의 이음새를 처리하는 것이 문제이지만, 이음새 동작을 처리하고 매끄러운 반사를 생성하는 알고리즘이 개발되었다.
# 단점
장면에 새로운 객체나 새로운 조명이 도입되거나, 반사되는 객체가 움직이거나 어떤 식으로든 변하면 반사가 변하고 큐브 맵을 다시 렌더링해야 한다. 큐브 맵이 장면을 통해 움직이는 객체에 부착되어 있으면 각 새로운 위치에서 큐브 맵을 다시 렌더링해야 한다.
# 응용

## 안정적인 반사 하이라이트
컴퓨터 지원 설계 (CAD) 프로그램은 3D 객체를 렌더링할 때 표면 곡률을 시각적으로 전달하기 위해 스페큘러 하이라이트를 시각적 단서로 사용한다. 그러나 많은 CAD 프로그램은 스페큘러 조명 계산이 객체를 나타내는 데 사용되는 메시의 정점에서만 수행되고, 객체 표면을 가로지르는 조명을 추정하기 위해 보간법이 사용되기 때문에 스페큘러 하이라이트 샘플링에 문제를 보인다. 메시 정점이 충분히 밀집되어 있지 않아 스페큘러 조명의 샘플링이 불충분할 때 문제가 발생한다. 이는 결국 메시 정점으로부터의 거리에 비례하는 밝기를 가진 하이라이트를 생성하여 곡률을 나타내는 시각적 단서를 훼손한다. 불행히도 이 문제는 단순히 더 조밀한 메시를 생성하는 것으로 해결할 수 없는데, 이는 객체 렌더링의 효율성을 크게 떨어뜨릴 수 있기 때문이다. 큐브 맵은 안정적인 반사 하이라이트를 렌더링하는 데 상당히 간단하고 효율적인 솔루션을 제공한다. 여러 반사 하이라이트를 큐브 맵 텍스처에 인코딩할 수 있으며, 이는 표면의 반사 매핑 벡터를 보간법하여 좌표를 제공함으로써 접근할 수 있다. 개별 정점에서 조명을 계산하는 것에 비해 이 방법은 곡률을 더 정확하게 나타내는 더 깨끗한 결과를 제공한다. 이 방법의 또 다른 장점은 확장성이 좋다는 것이다. 추가 반사 하이라이트를 렌더링 비용 증가 없이 텍스처에 인코딩할 수 있기 때문이다. 그러나 이 접근 방식은 광원이 멀거나 무한한 광원이어야 한다는 제약이 있지만, 다행히도 CAD 프로그램에서는 보통 그렇다.
## 스카이박스
footer = 큐브맵을 사용한 렌더링은 야외 장면에서 더 보기 좋다. (왼쪽은 큐브맵 사용, 오른쪽은 기본 태양광 사용). 블렌더 사이클에서 렌더링됨. 입방체 스카이박스의 면에 매핑될 수 있는 텍스처의 예시와 면 라벨 아마도 큐브 매핑의 가장 진보된 응용은 미리 렌더링된 파노라마 하늘 이미지를 생성하는 것이다. 이 이미지는 그래픽 엔진에 의해 거의 무한한 거리의 정육면체 면으로 렌더링되며, 시점은 정육면체 중앙에 위치한다. 그래픽 엔진이 수행하는 큐브 면의 원근 투영은 환경을 투영하여 큐브 맵을 생성하는 효과를 되돌려서, 관찰자가 스카이박스를 생성하는 데 사용된 장면에 둘러싸인 듯한 환상을 경험하게 한다. 이 기술은 비디오 게임에서 널리 사용되는데, 이는 디자이너가 거의 성능 비용 없이 복잡한(탐색 불가능하지만) 환경을 게임에 추가할 수 있기 때문이다.
## 천창 조명
큐브 맵은 야외 조명을 정확하게 모델링하는 데 유용할 수 있다. 햇빛을 단일 무한 광원으로만 모델링하는 것은 야외 조명을 너무 단순화하여 비현실적인 조명을 초래한다. 태양으로부터 많은 빛이 나오지만, 대기 중의 광선 산란은 전체 하늘을 광원(종종 천창 조명이라고 함)으로 작용하게 한다. 그러나 큐브 맵을 사용하면 천창 조명으로부터의 확산 기여를 포착할 수 있다. 반사 벡터가 사용되는 환경 맵과 달리, 이 방법은 표면 법선 벡터를 기반으로 큐브 맵에 접근하여 천창으로부터의 확산 조명에 대한 빠른 근사치를 제공한다. 이 방법의 한 가지 단점은 천창을 제대로 나타내도록 큐브 맵을 계산하는 것이 매우 복잡하다는 것이다. 최근의 한 과정은 큐브 맵으로부터 낮은 주파수 확산 조명을 가장 잘 나타내는 구형 조화 기저를 계산하는 것이다. 그러나 천창 조명을 효과적으로 모델링하기 위한 상당한 양의 연구가 이루어졌다.
## 동적 반사
큐브 맵핑된 반사 동작 기본 환경 매핑은 정적 큐브 맵을 사용한다. 즉, 객체가 이동하거나 왜곡될 수 있지만, 반사되는 환경은 일관되게 유지된다. 그러나 큐브 맵 텍스처는 동적으로 변화하는 환경(예: 바람에 흔들리는 나무)을 나타내기 위해 지속적으로 업데이트될 수 있다. 동적 반사를 생성하는 간단하지만 비용이 많이 드는 방법은 매 프레임마다 런타임에 큐브 맵을 구축하는 것이다. 이는 추가 렌더링 단계로 인해 정적 매핑보다 효율성이 훨씬 떨어지지만, 여전히 인터랙티브한 속도로 수행할 수 있다. 불행히도 이 기술은 여러 반사 객체가 있을 때 잘 확장되지 않는다. 각 반사 객체마다 고유한 동적 환경 맵이 일반적으로 필요하다. 또한 반사 객체들이 서로를 반사할 수 있다면 추가적인 복잡성이 더해진다. 동적 큐브 맵은 일반적으로 광선 추적을 사용하여 생성되는 효과를 근사화하여 재귀적으로 생성될 수 있다.
## 글로벌 일루미네이션
큐브 맵 데이터 구조를 사용하여 인터랙티브 속도로 글로벌 일루미네이션을 계산하는 알고리즘이 2002년 ICCV에서 발표되었다.
## 투영 텍스처
비디오 게임에서 널리 사용되는 또 다른 응용은 투영 텍스처 매핑이다. 이는 큐브 맵에 의존하여 환경 이미지를 주변 장면에 투영한다. 예를 들어, 점 광원은 등롱 안에서 찍었거나 빛이 스며드는 창틀에서 찍은 파노라마 이미지인 큐브 맵에 연결된다. 이를 통해 게임 개발자는 장면 기하학을 복잡하게 만들거나 값비싼 실시간 그림자 볼륨 계산에 의존하지 않고도 사실적인 조명을 구현할 수 있다.
# 메모리 주소 지정
이 그림은 큐브 맵이 어떻게 색인화되고 주소 지정되는지 보여준다. 큐브 텍스처는 6개의 텍스처 맵을 양의 X, 음의 X, 양의 Y, 음의 Y, 양의 Z, 음의 Z 순서로 0부터 5까지 색인화한다.date=23 August 2019title = Chapter 19. Image-Based Lighting 이미지는 원점이 이미지의 왼쪽 아래에 있도록 저장된다. 양의 X 및 Y 면은 Z 좌표를 반전해야 하며, 음의 Z 면은 X 좌표를 부정해야 한다. 면과 텍스처 좌표 (u, v)가 주어지면, 정규화되지 않은 벡터 (x, y, z)는 다음 함수로 계산할 수 있다. void convert_cube_uv_to_xyz(int index, float u, float v, float *x, float *y, float *z) { // convert range 0 to 1 to -1 to 1 float uc = 2.0f * u - 1.0f; float vc = 2.0f * v - 1.0f; switch (index) { case 0: *x = 1.0f; *y = vc; *z = -uc; break; // POSITIVE X case 1: *x = -1.0f; *y = vc; *z = uc; break; // NEGATIVE X case 2: *x = uc; *y = 1.0f; *z = -vc; break; // POSITIVE Y case 3: *x = uc; *y = -1.0f; *z = vc; break; // NEGATIVE Y case 4: *x = uc; *y = vc; *z = 1.0f; break; // POSITIVE Z case 5: *x = -uc; *y = vc; *z = -1.0f; break; // NEGATIVE Z } } 마찬가지로 벡터 (x, y, z)는 다음 함수로 면 색인과 텍스처 좌표 (u, v)로 변환할 수 있다. void convert_xyz_to_cube_uv(float x, float y, float z, int *index, float *u, float *v) { float absX = fabs(x); float absY = fabs(y); float absZ = fabs(z); int isXPositive = x > 0 ? 1 : 0; int isYPositive = y > 0 ? 1 : 0; int isZPositive = z > 0 ? 1 : 0; float maxAxis, uc, vc; // POSITIVE X if (isXPositive && absX >= absY && absX >= absZ) { // u (0 to 1) goes from +z to -z // v (0 to 1) goes from -y to +y maxAxis = absX; uc = -z; vc = y; *index = 0; } // NEGATIVE X if (!isXPositive && absX >= absY && absX >= absZ) { // u (0 to 1) goes from -z to +z // v (0 to 1) goes from -y to +y maxAxis = absX; uc = z; vc = y; *index = 1; } // POSITIVE Y if (isYPositive && absY >= absX && absY >= absZ) { // u (0 to 1) goes from -x to +x // v (0 to 1) goes from +z to -z maxAxis = absY; uc = x; vc = -z; *index = 2; } // NEGATIVE Y if (!isYPositive && absY >= absX && absY >= absZ) { // u (0 to 1) goes from -x to +x // v (0 to 1) goes from -z to +z maxAxis = absY; uc = x; vc = z; *index = 3; } // POSITIVE Z if (isZPositive && absZ >= absX && absZ >= absY) { // u (0 to 1) goes from -x to +x // v (0 to 1) goes from -y to +y maxAxis = absZ; uc = x; vc = y; *index = 4; } // NEGATIVE Z if (!isZPositive && absZ >= absX && absZ >= absY) { // u (0 to 1) goes from +x to -x // v (0 to 1) goes from -y to +y maxAxis = absZ; uc = -x; vc = y; *index = 5; } // Convert range from -1 to 1 to 0 to 1 *u = 0.5f * (uc / maxAxis + 1.0f); *v = 0.5f * (vc / maxAxis + 1.0f); }