DOTY
DirectX11. 7) 3D Model Rendering 본문
이전의 코드에서는 3D 공간에서 평면인 모델만 렌더링 했지만 이번에는 입체를 렌더링 한다.
따라서 이전의 코드와 큰 차이가 없지만 3D 모델을 처리하기 위한 Vertex(x, y, z), Texture(tu, tv), Normal(nx, ny, nz)가 포함된 텍스쳐 파일을 읽어와 이를 처리하여 렌더링 하는 것을 익힐 수 있었다.
추가로 Rotate, Translate, Scale 관련 코드도 추가되었다.
> Cube.txt <
Vertex Count: 36
Data:
-1.0 1.0 -1.0 0.0 0.0 0.0 0.0 -1.0
1.0 1.0 -1.0 1.0 0.0 0.0 0.0 -1.0
-1.0 -1.0 -1.0 0.0 1.0 0.0 0.0 -1.0
-1.0 -1.0 -1.0 0.0 1.0 0.0 0.0 -1.0
1.0 1.0 -1.0 1.0 0.0 0.0 0.0 -1.0
1.0 -1.0 -1.0 1.0 1.0 0.0 0.0 -1.0
1.0 1.0 -1.0 0.0 0.0 1.0 0.0 0.0
1.0 1.0 1.0 1.0 0.0 1.0 0.0 0.0
1.0 -1.0 -1.0 0.0 1.0 1.0 0.0 0.0
1.0 -1.0 -1.0 0.0 1.0 1.0 0.0 0.0
1.0 1.0 1.0 1.0 0.0 1.0 0.0 0.0
1.0 -1.0 1.0 1.0 1.0 1.0 0.0 0.0
1.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0
-1.0 1.0 1.0 1.0 0.0 0.0 0.0 1.0
1.0 -1.0 1.0 0.0 1.0 0.0 0.0 1.0
1.0 -1.0 1.0 0.0 1.0 0.0 0.0 1.0
-1.0 1.0 1.0 1.0 0.0 0.0 0.0 1.0
-1.0 -1.0 1.0 1.0 1.0 0.0 0.0 1.0
-1.0 1.0 1.0 0.0 0.0 -1.0 0.0 0.0
-1.0 1.0 -1.0 1.0 0.0 -1.0 0.0 0.0
-1.0 -1.0 1.0 0.0 1.0 -1.0 0.0 0.0
-1.0 -1.0 1.0 0.0 1.0 -1.0 0.0 0.0
-1.0 1.0 -1.0 1.0 0.0 -1.0 0.0 0.0
-1.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 0.0
-1.0 1.0 1.0 0.0 0.0 0.0 1.0 0.0
1.0 1.0 1.0 1.0 0.0 0.0 1.0 0.0
-1.0 1.0 -1.0 0.0 1.0 0.0 1.0 0.0
-1.0 1.0 -1.0 0.0 1.0 0.0 1.0 0.0
1.0 1.0 1.0 1.0 0.0 0.0 1.0 0.0
1.0 1.0 -1.0 1.0 1.0 0.0 1.0 0.0
-1.0 -1.0 -1.0 0.0 0.0 0.0 -1.0 0.0
1.0 -1.0 -1.0 1.0 0.0 0.0 -1.0 0.0
-1.0 -1.0 1.0 0.0 1.0 0.0 -1.0 0.0
-1.0 -1.0 1.0 0.0 1.0 0.0 -1.0 0.0
1.0 -1.0 -1.0 1.0 0.0 0.0 -1.0 0.0
1.0 -1.0 1.0 1.0 1.0 0.0 -1.0 0.0
1. ModelClass.h
#pragma once
#ifndef _MODELCLASS_H_
#define _MODELCLASS_H_
#include "TextureClass.h"
#include <d3d11.h>
#include <directxmath.h>
#include <fstream>
using namespace DirectX;
using namespace std;
class ModelClass
{
private:
struct VertexType
{
XMFLOAT3 position;
XMFLOAT2 texture;
XMFLOAT3 normal;
};
struct ModelType
{
float x, y, z;
float tu, tv;
float nx, ny, nz;
};
public:
ModelClass();
ModelClass(const ModelClass&);
~ModelClass();
bool Initialize(ID3D11Device*, ID3D11DeviceContext*, char*, char*, HWND);
void Shutdown();
void Render(ID3D11DeviceContext*);
int GetIndexCount();
ID3D11ShaderResourceView* GetTexture();
private:
bool InitializeBuffers(ID3D11Device*);
void ShutdownBuffers();
void RenderBuffers(ID3D11DeviceContext*);
bool LoadTexture(ID3D11Device*, ID3D11DeviceContext*, char*);
void ReleaseTexture();
bool LoadModel(char*);
void ReleaseModel();
private:
ID3D11Buffer* m_vertexBuffer, * m_indexBuffer;
int m_vertexCount, m_indexCount;
TextureClass* m_Texture;
ModelType* m_model;
};
#endif
※Initialize의 매개변수 HWND는 어디서 오류가 났는지 확인하기 위함이다. 필요하면 지워도 무방하다.
1-1. ModelType
3D모델을 처리하기 위한 세 타입의 변수 총 8가지를 선언. Vertex(x, y, z), Texture(tu, tv), Normal(nx, ny, nz)
정점을 처리하기 위한 Vertex, 텍스쳐를 적용하기 위한 Texture, 정점으로 만들어진 면이 어느 방향을 보고 있는지에 대한 Normal 세 타입의 변수를 선언한다.
1-2. Initialize
filename을 얻기 위한 char* 형식의 매개변수가 추가되었다. 이를 이용해 텍스트 파일을 읽어온다.
for(i=0; i<m_vertexCount; i++)
{
vertices[i].position = XMFLOAT3(m_model[i].x, m_model[i].y, m_model[i].z);
vertices[i].texture = XMFLOAT2(m_model[i].tu, m_model[i].tv);
vertices[i].normal = XMFLOAT3(m_model[i].nx, m_model[i].ny, m_model[i].nz);
indices[i] = i;
}
이전의 Vertex와 Index들을 일일이 썼다면 이번에는 가공을 한 후에 m_model에 저장했기 때문에 그 데이터들을 직접 불러오면 된다.
1-3. LoadModel
bool ModelClass::LoadModel(char* filename)
{
ifstream fin;
char input;
int i;
// Open the model file.
fin.open(filename);
// If it could not open the file then exit.
if (fin.fail())
{
return false;
}
// Read up to the value of vertex count.
fin.get(input);
while (input != ':')
{
fin.get(input);
}
// Read in the vertex count.
fin >> m_vertexCount;
// Set the number of indices to be the same as the vertex count.
m_indexCount = m_vertexCount;
// Create the model using the vertex count that was read in.
m_model = new ModelType[m_vertexCount];
// Read up to the beginning of the data.
fin.get(input);
while (input != ':')
{
fin.get(input);
}
fin.get(input);
fin.get(input);
// Read in the vertex data.
for (i = 0; i < m_vertexCount; i++)
{
fin >> m_model[i].x >> m_model[i].y >> m_model[i].z;
fin >> m_model[i].tu >> m_model[i].tv;
fin >> m_model[i].nx >> m_model[i].ny >> m_model[i].nz;
}
// Close the model file.
fin.close();
return true;
}
텍스트 파일의 데이터들을 그대로 쓰기는 어려워 가공해야 한다. txt파일의 첫 줄을 m_vertexCount를 얻을 수 있다.
따라서 InitializeBuffers에서 Vertex
그다음줄부터는 큐브를 그리기 위한 12개의 삼각형 즉, 36개의 점들이 적혀있다.
(x, y, z, tu, tv, nx, ny, nz) 순으로 적혀있고 이를 m_model 구조체 배열에 하나씩 저장해 준다.
2. ApplicationClass - Render
bool ApplicationClass::Render(float rotation)
{
XMMATRIX worldMatrix, viewMatrix, projectionMatrix;
// new Matrix for Rotate, Translate, Scale
XMMATRIX rotateMatrix, translateMatrix, scaleMatrix, srMatrix;
bool result;
// Clear the buffers to begin the scene.
m_Direct3D->BeginScene(1.0f, 1.0f, 1.0f, 1.0f);
// Generate the view matrix based on the camera's position.
m_Camera->Render();
// Get the world, view, and projection matrices from the camera and d3d objects.
m_Direct3D->GetWorldMatrix(worldMatrix);
m_Camera->GetViewMatrix(viewMatrix);
m_Direct3D->GetProjectionMatrix(projectionMatrix);
rotateMatrix = XMMatrixRotationY(rotation); // Build the rotation matrix.
translateMatrix = XMMatrixTranslation(-2.0f, 0.0f, 0.0f); // Build the translation matrix.
// Multiply them together to create the final world transformation matrix.
worldMatrix = XMMatrixMultiply(rotateMatrix, translateMatrix);
// Put the model vertex and index buffers on the graphics pipeline to prepare them for drawing.
m_Model->Render(m_Direct3D->GetDeviceContext());
// Render the model using the light shader.
result = m_LightShader->Render(m_Direct3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, m_Model->GetTexture(),
m_Light->GetDirection(), m_Light->GetDiffuseColor());
if (!result)
{
return false;
}
scaleMatrix = XMMatrixScaling(0.5f, 0.5f, 0.5f); // Build the scaling matrix.
rotateMatrix = XMMatrixRotationY(-rotation); // Build the rotation matrix.
translateMatrix = XMMatrixTranslation(2.0f, 0.0f, 0.0f); // Build the translation matrix.
// Multiply the scale, rotation, and translation matrices together to create the final world transformation matrix.
srMatrix = XMMatrixMultiply(scaleMatrix, rotateMatrix);
worldMatrix = XMMatrixMultiply(srMatrix, translateMatrix);
// Put the model vertex and index buffers on the graphics pipeline to prepare them for drawing.
m_Model->Render(m_Direct3D->GetDeviceContext());
// Render the model using the light shader.
result = m_LightShader->Render(m_Direct3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, m_Model->GetTexture(),
m_Light->GetDirection(), m_Light->GetDiffuseColor());
if (!result)
{
return false;
}
m_Direct3D->EndScene();
return true;
}
Rotate, Translate, Scale의 Matrix를 추가해서 이들을 곱한 최종 Matrix를 적용하여 렌더링 한다.
translateMatrix = XMMatrixTranslation(2.0f + sin(rotation * 2), 0.0f + cos(rotation), 0.0f);
이런식으로 삼각함수를 섞어서 쓴다면 한 점을 중심으로 원의 둘레를 따라 원운동하는 오브젝트도 만들 수 있다.
※ rastertek Tutorial chapter 7과 8의 내용이 포함되어있다.
'DirectX' 카테고리의 다른 글
DirectX11. 8) Ambient Light, Specular Lighting (0) | 2023.06.19 |
---|---|
DirectX11. check 1) Back-Face culling (0) | 2023.06.14 |
DirectX11. 6) Light (0) | 2023.06.14 |
DirectX11. 5) Texture (0) | 2023.06.13 |
DirectX11. 4) Buffer, Shader II (0) | 2023.06.12 |