[DirectX11] Tutorial 34 - 빌보드
Tutorial 34 - 빌보드
원문 : http://www.rastertek.com/dx11tut34.html
DirectX 11에서 빌보드는 먼 거리에 있는 3D 지형을 표시하기 위하여 텍스쳐를 입힌 사각형을 사용하는 과정입니다. 그다지 중요하지는 않지만 많은 폴리곤이 필요하기 때문에 그리지 않는 복잡한 씬도 이 방법을 사용하여 성능의 향상을 꾀할 수 있습니다.
빌보드가 어떻게 사용되는지에 상상해 보기 위하여 수천개의 나무들이 있는 숲 씬이 있다고 생각해 보겠습니다. 폴리곤의 개수가 많은 나무들로 구성된 복잡한 숲을 실시간 렌더링으로 그려낸다는 것은 현존하는 대부분의 그래픽 카드의 가용성을 넘어서는 일입니다. 따라서 50개 정도의 가장 가까운 나무들만 제대로 그리고 나머지 나무들은 빌보드로 그리게 하는 방법을 쓰게 됩니다. 이렇게 함으로 전체 숲을 실시간으로 렌더링하면서 전체 폴리곤 개수는 낮게 유지할 수 있습니다. 유저가 가까운 50개의 나무를 지나치면 그 다음 50개의 나무가 점차적으로 빌보드에서 풀 폴리곤 모델로 바뀌게 될 것입니다. 이런 식으로 가장 가까운 나무들은 항상 디테일한 폴리곤으로 보여주고 멀리 있는 나무들은 항상 적은 폴리곤을 사용하는 빌보드가 되게 할 수 있습니다. 이 방법은 건물이나 구름, 산, 구조물, 식물, 파티클 등등 다른 많은 물체에도 사용할 수 있습니다.
빌보드를 구현하는 방법간의 차이점이 있다면 사각형이 어떻게 회전하는지가 다릅니다. 어떤 경우 사각형이 유저가 보는 방향에 따라 돌아가는데, 대부분의 파티클 시스템이 이렇게 동작합니다. 다른 경우 3D 텍스트처럼 2D같이 항상 스크린을 바라보게끔 하는 경우도 있습니다. 하지만 이번 예제에서는 유저의 위치에 따라 유저를 항상 마주보게 하는 세번째 방법을 다룰 것입니다. 방금 나무 예제에서 여러분이라면 이 방법을 사용할 것입니다.
프레임워크
Graphicsclass.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #pragma once ///////////// // GLOBALS // ///////////// const bool FULL_SCREEN = false; const bool VSYNC_ENABLED = true; const float SCREEN_DEPTH = 1000.0f; const float SCREEN_NEAR = 0.1f; class D3DClass; class CameraClass; class ModelClass; class TextureShaderClass; class GraphicsClass { public: GraphicsClass(); GraphicsClass(const GraphicsClass&); ~GraphicsClass(); bool Initialize(int, int, HWND); void Shutdown(); bool Frame(XMFLOAT3&); private: bool Render(); private: D3DClass* m_Direct3D = nullptr; CameraClass* m_Camera = nullptr; ModelClass* m_FloorModel = nullptr; ModelClass* m_BillboardModel = nullptr; TextureShaderClass* m_TextureShader = nullptr; }; | cs |
Graphicsclass.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | #include "stdafx.h" #include "d3dclass.h" #include "cameraclass.h" #include "modelclass.h" #include "textureshaderclass.h" #include "graphicsclass.h" GraphicsClass::GraphicsClass() { } GraphicsClass::GraphicsClass(const GraphicsClass& other) { } GraphicsClass::~GraphicsClass() { } bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hwnd) { // Direct3D 객체 생성 m_Direct3D = new D3DClass; if (!m_Direct3D) { return false; } // Direct3D 객체 초기화 if (!m_Direct3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR)) { MessageBox(hwnd, L"Could not initialize Direct3D.", L"Error", MB_OK); return false; } // m_Camera 객체 생성 m_Camera = new CameraClass; if (!m_Camera) { return false; } // 카메라 포지션을 설정한다 m_Camera->SetPosition(XMFLOAT3(0.0f, 0.0f, -10.0f)); // 텍스처 쉐이더 객체를 생성한다. m_TextureShader = new TextureShaderClass; if(!m_TextureShader) { return false; } // 텍스처 쉐이더 객체를 초기화한다. if(!m_TextureShader->Initialize(m_Direct3D->GetDevice(), hwnd)) { MessageBox(hwnd, L"Could not initialize the texture shader object.", L"Error", MB_OK); return false; } // 바닥 모델 객체를 만듭니다. m_FloorModel = new ModelClass; if(!m_FloorModel) { return false; } // 바닥 모델 객체를 초기화합니다. if(!m_FloorModel->Initialize(m_Direct3D->GetDevice(), "../Dx11Demo_34/data/floor.txt", L"../Dx11Demo_34/data/grid01.dds")) { MessageBox(hwnd, L"Could not initialize the floor model object.", L"Error", MB_OK); return false; } // 빌보드 모델 객체를 만듭니다. m_BillboardModel = new ModelClass; if(!m_BillboardModel) { return false; } // 빌보드 모델 객체를 초기화합니다. if(!m_BillboardModel->Initialize(m_Direct3D->GetDevice(), "../Dx11Demo_34/data/square.txt", L"../Dx11Demo_34/data/seafloor.dds")) { MessageBox(hwnd, L"Could not initialize the billboard model object.", L"Error", MB_OK); return false; } return true; } void GraphicsClass::Shutdown() { // 빌보드 모델 객체를 해제합니다. if(m_BillboardModel) { m_BillboardModel->Shutdown(); delete m_BillboardModel; m_BillboardModel = 0; } // 바닥 모델 객체를 해제합니다. if(m_FloorModel) { m_FloorModel->Shutdown(); delete m_FloorModel; m_FloorModel = 0; } // 텍스처 쉐이더 객체를 해제합니다. if(m_TextureShader) { m_TextureShader->Shutdown(); delete m_TextureShader; m_TextureShader = 0; } // 카메라 객체를 해제합니다. if(m_Camera) { delete m_Camera; m_Camera = 0; } // Direct3D 객체를 해제합니다. if (m_Direct3D) { m_Direct3D->Shutdown(); delete m_Direct3D; m_Direct3D = 0; } } bool GraphicsClass::Frame(XMFLOAT3& position) { // 카메라 위치를 업데이트합니다. m_Camera->SetPosition(position); // 그래픽 장면을 렌더링합니다. return Render(); } bool GraphicsClass::Render() { XMMATRIX worldMatrix, viewMatrix, projectionMatrix, translateMatrix; XMFLOAT3 cameraPosition, modelPosition; // 장면을 시작할 버퍼를 지운다. m_Direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f); // 카메라의 위치에 따라 뷰 행렬을 생성합니다. m_Camera->Render(); // 카메라 및 d3d 객체에서 월드, 뷰 및 오쏘 (ortho) 행렬을 가져옵니다. m_Direct3D->GetWorldMatrix(worldMatrix); m_Camera->GetViewMatrix(viewMatrix); m_Direct3D->GetProjectionMatrix(projectionMatrix); // 드로잉을 준비하기 위해 바닥 파이프 모델 버텍스와 인덱스 버퍼를 그래픽 파이프 라인에 배치합니다. m_FloorModel->Render(m_Direct3D->GetDeviceContext()); // 텍스처 쉐이더를 사용하여 바닥 모델을 렌더링합니다. if(!m_TextureShader->Render(m_Direct3D->GetDeviceContext(), m_FloorModel->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, m_FloorModel->GetTexture())) { return false; } // 카메라 위치를 얻는다. cameraPosition = m_Camera->GetPosition(); // 빌보드 모델의 위치를 설정합니다. modelPosition.x = 0.0f; modelPosition.y = 1.5f; modelPosition.z = 0.0f; // 아크 탄젠트 함수를 사용하여 현재 카메라 위치를 향하도록 빌보드 모델에 적용해야하는 회전을 계산합니다. double angle = atan2(modelPosition.x - cameraPosition.x, modelPosition.z - cameraPosition.z) * (180.0 / XM_PI); // 회전을 라디안으로 변환합니다. float rotation = (float)angle * 0.0174532925f; // 세계 행렬을 사용하여 원점에서 빌보드 회전을 설정합니다. worldMatrix = XMMatrixRotationY(rotation); // 빌보드 모델에서 번역 행렬을 설정합니다. translateMatrix = XMMatrixTranslation(modelPosition.x, modelPosition.y, modelPosition.z); // 마지막으로 회전 및 변환 행렬을 결합하여 빌보드 모델의 최종 행렬을 만듭니다. worldMatrix = XMMatrixMultiply(worldMatrix, translateMatrix); // 모델 버텍스와 인덱스 버퍼를 그래픽 파이프 라인에 배치하여 드로잉을 준비합니다. m_BillboardModel->Render(m_Direct3D->GetDeviceContext()); // 텍스처 셰이더를 사용하여 모델을 렌더링합니다. if(!m_TextureShader->Render(m_Direct3D->GetDeviceContext(), m_BillboardModel->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, m_BillboardModel->GetTexture())) { return false; } // 렌더링 된 장면을 화면에 표시합니다. m_Direct3D->EndScene(); return true; } | cs |
출력 화면
마치면서
여러분이 빌보드 모델 왼쪽 오른쪽으로 옴직여도 모델이 항상 여러분의 위치를 바라볼 것입니다. 이 방법 외에도 다른 빌보딩 기법을 사용하여 또다른 효과를 줄 수 있다는 점을 알아 두시기 바랍니다.
연습문제
1. 프로그램을 다시 컴파일하여 실행해 보십시오. 왼쪽과 오른쪽 화살표 키를 사용하여 양쪽으로 움직여 보고 빌보드가 알맞게 회전하는지 확인해 보십시오.
2. 빌보드의 텍스쳐를 알파블렌딩을 사용한 나무 그림으로 바꾸어 보십시오.
3. 평평한 지형에 빌보드를 이용하여 작은 숲을 만들어 보십시오.
4. 각각의 나무와의 거리를 이용하여 적당한 지점에서 빌보드와 실제 나무 모델이 서로 변환되게끔 블렌드 효과를 만들어 보십시오.
5. 뷰 기반의 빌보드를 공부해 보십시오.
소스코드
소스코드 : Dx11Demo_34.zip
'DirectX 11 > Basic' 카테고리의 다른 글
[DirectX11] Tutorial 36 - 흐림 효과 (0) | 2018.01.07 |
---|---|
[DirectX11] Tutorial 35 - 깊이 버퍼 (0) | 2018.01.01 |
[DirectX11] Tutorial 33 - 불효과 (1) | 2017.12.31 |
[DirectX11] Tutorial 32 - 유리, 얼음 (0) | 2017.12.30 |
[DirectX11] Tutorial 31 - 3D 사운드 (0) | 2017.12.28 |