응애맘마조
230530 강의 본문
저번엔 UI를 이미지로 나타내었지만 오늘은 게임 내 객체를 이미지로 나타내는 방법에 대해 강의했습니다.
그동안 2D 이미지를 애니메이션 효과로 나타낼 때는 스프라이트 이미지를 사용해 좌표를 빠르게 바꾸는 방식으로 했었지만 이번 3D에서는 위의 방식이 불가능하기 때문에 좌표를 바꾸지 않고 애니메이션 효과를 사용해야 됩니다.
#pragma once
class Mesh
{
friend class GameObject;
private:
ID3D11Buffer* vertexBuffer;
ID3D11Buffer* indexBuffer;
D3D_PRIMITIVE_TOPOLOGY primitiveTopology;
VertexType vertexType;
UINT byteWidth;
public:
UINT* indices;
UINT indexCount;
void* vertices;
UINT vertexCount;
string file;
public:
Mesh();
~Mesh();
void Set();
void LoadFile(string file);
void SaveFile(string file);
void Reset();
};
#include "framework.h"
Mesh::Mesh()
{
vertexType = VertexType::PT;
primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
byteWidth = sizeof(VertexPT);
vertexCount = 4 * 6;
indexCount = 6 * 6;
VertexPT* Vertex = new VertexPT[vertexCount];
indices = new UINT[indexCount];
Vertex[0].position = Vector3(-1, -1, -1);
Vertex[1].position = Vector3(-1, 1, -1);
Vertex[2].position = Vector3(1, -1, -1);
Vertex[3].position = Vector3(1, 1, -1);
for (int i = 1; i < 4; i++)
{
Matrix R = Matrix::CreateRotationY(PI * 0.5f * i);
Vertex[0 + i * 4].position = Vector3::Transform(Vertex[0].position, R);
Vertex[1 + i * 4].position = Vector3::Transform(Vertex[1].position, R);
Vertex[2 + i * 4].position = Vector3::Transform(Vertex[2].position, R);
Vertex[3 + i * 4].position = Vector3::Transform(Vertex[3].position, R);
}
for (int i = 4; i < 6; i++)
{
Matrix R = Matrix::CreateRotationX(PI * 0.5f + (PI * (i-4)));
Vertex[0 + i * 4].position = Vector3::Transform(Vertex[0].position, R);
Vertex[1 + i * 4].position = Vector3::Transform(Vertex[1].position, R);
Vertex[2 + i * 4].position = Vector3::Transform(Vertex[2].position, R);
Vertex[3 + i * 4].position = Vector3::Transform(Vertex[3].position, R);
}
indices = new UINT[indexCount];
//앞면
for (int i = 0; i < 6; i++)
{
indices[i * 6 + 0] = i * 4 + 0;
indices[i * 6 + 1] = i * 4 + 1;
indices[i * 6 + 2] = i * 4 + 2;
indices[i * 6 + 3] = i * 4 + 1;
indices[i * 6 + 4] = i * 4 + 3;
indices[i * 6 + 5] = i * 4 + 2;
}
vertices = Vertex;
//CreateVertexBuffer
{
D3D11_BUFFER_DESC desc;
desc = { 0 };
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ByteWidth = byteWidth * vertexCount;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = vertices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &vertexBuffer);
assert(SUCCEEDED(hr));
}
//Create Index Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(UINT) * indexCount;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = indices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &indexBuffer);
assert(SUCCEEDED(hr));
}
}
Mesh::~Mesh()
{
}
void Mesh::Set()
{
UINT offset = 0;
D3D->GetDC()->IASetVertexBuffers(0,
1,
&vertexBuffer,
&byteWidth,
&offset);
D3D->GetDC()->IASetPrimitiveTopology
(primitiveTopology);
D3D->GetDC()->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0);
}
void Mesh::LoadFile(string file)
{
this->file = file;
BinaryReader in;
wstring path = L"../Contents/Mesh/" + Util::ToWString(file);
in.Open(path);
//읽기전
switch (vertexType)
{
case VertexType::P:
if (vertices)delete[](VertexP*)vertices;
break;
case VertexType::PC:
if (vertices)delete[](VertexPC*)vertices;
break;
case VertexType::PCN:
if (vertices)delete[](VertexPCN*)vertices;
break;
case VertexType::PTN:
if (vertices)delete[](VertexPTN*)vertices;
break;
case VertexType::MODEL:
if (vertices)delete[](VertexModel*)vertices;
break;
case VertexType::TERRAIN:
if (vertices)delete[](VertexTerrain*)vertices;
break;
case VertexType::PT:
if (vertices)delete[](VertexPT*)vertices;
break;
case VertexType::PS:
if (vertices)delete[](VertexPS*)vertices;
break;
case VertexType::PSV:
if (vertices)delete[](VertexPSV*)vertices;
break;
}
vertexType = (VertexType)in.UInt();
primitiveTopology = (D3D_PRIMITIVE_TOPOLOGY)in.UInt();
byteWidth = in.UInt();
vertexCount = in.UInt();
indexCount = in.UInt();
SafeDeleteArray(indices);
indices = new UINT[indexCount];
//읽고난후
switch (vertexType)
{
case VertexType::P:
{
vertices = new VertexP[vertexCount];
VertexP* vertex = (VertexP*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
}
break;
}
case VertexType::PC:
{
vertices = new VertexPC[vertexCount];
VertexPC* vertex = (VertexPC*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].color = in.color3f();
}
break;
}
case VertexType::PCN:
{
vertices = new VertexPCN[vertexCount];
VertexPCN* vertex = (VertexPCN*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].color = in.color3f();
vertex[i].normal = in.vector3();
}
break;
}
case VertexType::PTN:
{
vertices = new VertexPTN[vertexCount];
VertexPTN* vertex = (VertexPTN*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].uv = in.vector2();
vertex[i].normal = in.vector3();
}
break;
}
case VertexType::MODEL:
{
vertices = new VertexModel[vertexCount];
VertexModel* vertex = (VertexModel*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].uv = in.vector2();
vertex[i].normal = in.vector3();
vertex[i].tangent = in.vector3();
vertex[i].indices = in.vector4();
vertex[i].weights = in.vector4();
}
break;
}
case VertexType::TERRAIN:
{
vertices = new VertexTerrain[vertexCount];
VertexTerrain* vertex = (VertexTerrain*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].uv = in.vector2();
vertex[i].normal = in.vector3();
vertex[i].weights = in.Float();
}
break;
}
case VertexType::PT:
{
vertices = new VertexPT[vertexCount];
VertexPT* vertex = (VertexPT*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].uv = in.vector2();
}
break;
}
case VertexType::PS:
{
vertices = new VertexPS[vertexCount];
VertexPS* vertex = (VertexPS*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].size = in.vector2();
}
break;
}
case VertexType::PSV:
{
vertices = new VertexPSV[vertexCount];
VertexPSV* vertex = (VertexPSV*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
vertex[i].position = in.vector3();
vertex[i].size = in.vector2();
vertex[i].velocity = in.vector3();
}
break;
}
}
for (UINT i = 0; i < indexCount; i++)
{
indices[i] = in.UInt();
}
in.Close();
SafeRelease(vertexBuffer);
SafeRelease(indexBuffer);
//CreateVertexBuffer
{
D3D11_BUFFER_DESC desc;
desc = { 0 };
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ByteWidth = byteWidth * vertexCount;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = vertices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &vertexBuffer);
assert(SUCCEEDED(hr));
}
//Create Index Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(UINT) * indexCount;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = indices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &indexBuffer);
assert(SUCCEEDED(hr));
}
}
void Mesh::SaveFile(string file)
{
this->file = file;
BinaryWriter out;
wstring path = L"../Contents/Mesh/" + Util::ToWString(file);
out.Open(path);
out.UInt((UINT)vertexType);
out.UInt((UINT)primitiveTopology);
out.UInt(byteWidth);
out.UInt(vertexCount);
out.UInt(indexCount);
switch (vertexType)
{
case VertexType::P:
{
VertexP* vertex = (VertexP*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
}
break;
}
case VertexType::PC:
{
VertexPC* vertex = (VertexPC*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.color3f(vertex[i].color);
}
break;
}
case VertexType::PCN:
{
VertexPCN* vertex = (VertexPCN*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.color3f(vertex[i].color);
out.vector3(vertex[i].normal);
}
break;
}
case VertexType::PTN:
{
VertexPTN* vertex = (VertexPTN*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.vector2(vertex[i].uv);
out.vector3(vertex[i].normal);
}
break;
}
case VertexType::MODEL:
{
VertexModel* vertex = (VertexModel*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.vector2(vertex[i].uv);
out.vector3(vertex[i].normal);
out.vector3(vertex[i].tangent);
out.vector4(vertex[i].indices);
out.vector4(vertex[i].weights);
}
break;
}
case VertexType::TERRAIN:
{
VertexTerrain* vertex = (VertexTerrain*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.vector2(vertex[i].uv);
out.vector3(vertex[i].normal);
out.Float(vertex[i].weights);
}
break;
}
case VertexType::PT:
{
VertexPT* vertex = (VertexPT*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.vector2(vertex[i].uv);
}
break;
}
case VertexType::PS:
{
VertexPS* vertex = (VertexPS*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.vector2(vertex[i].size);
}
break;
}
case VertexType::PSV:
{
VertexPSV* vertex = (VertexPSV*)vertices;
for (UINT i = 0; i < vertexCount; i++)
{
out.vector3(vertex[i].position);
out.vector2(vertex[i].size);
out.vector3(vertex[i].velocity);
}
break;
}
}
for (UINT i = 0; i < indexCount; i++)
{
out.UInt(indices[i]);
}
out.Close();
}
void Mesh::Reset()
{
SafeRelease(indexBuffer);
SafeRelease(vertexBuffer);
//CreateVertexBuffer
{
D3D11_BUFFER_DESC desc;
desc = { 0 };
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ByteWidth = byteWidth * vertexCount;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = vertices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &vertexBuffer);
assert(SUCCEEDED(hr));
}
//Create Index Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(UINT) * indexCount;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = indices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &indexBuffer);
assert(SUCCEEDED(hr));
}
}
먼저 mesh의 헤더와 cpp파일입니다. 정육면체의 모습으로 만들기 위해 삼각형 두 개를 가지고 사각형을 만들어서 rotation으로 돌려가면서 만드는 형식으로 만들었습니다.
#pragma once
class Scene1 : public Scene
{
private:
Camera* Cam;
Grid* grid;
Actor* Player;
public:
Scene1();
~Scene1();
virtual void Init() override;
virtual void Release() override; //해제
virtual void Update() override;
virtual void LateUpdate() override;//갱신
virtual void PreRender() override;
virtual void Render() override;
virtual void ResizeScreen() override;
};
#include "stdafx.h"
Scene1::Scene1()
{
Cam = Camera::Create();
Player = Actor::Create();
Player->mesh = make_shared<Mesh>();
Player->mesh->LoadFile("6.Edit.mesh");
Player->shader = make_shared<Shader>();
Player->shader->LoadFile("6.Cube.hlsl");
Player->texture = make_shared<Texture>();
Player->texture->LoadFile("Bold.png");
grid = Grid::Create();
}
Scene1::~Scene1()
{
Cam->Release();
Player->Release();
}
void Scene1::Init()
{
Camera::main = Cam;
}
void Scene1::Release()
{
Player->mesh->SaveFile("6.Edit.mesh");
}
void Scene1::Update()
{
grid->Update();
for (int i = 0; i < 4 * 6; i++)
{
string ver = "vertex" + to_string(i);
VertexPT* vertices = (VertexPT*)Player->mesh->vertices;
if (ImGui::InputFloat2((ver + "uv").c_str(), (float*)&vertices[i].uv))
{
Player->mesh->Reset();
break;
}
}
ImGui::Text("FPS: %d", TIMER->GetFramePerSecond());
Camera::ControlMainCam();
ImGui::Begin("Hierarchy");
Cam->RenderHierarchy();
Player->RenderHierarchy();
ImGui::End();
Cam->Update();
Player->Update();
}
void Scene1::LateUpdate()
{
}
void Scene1::PreRender()
{
}
void Scene1::Render()
{
Camera::main->Set();
grid->Render();
Player->Render();
}
void Scene1::ResizeScreen()
{
Cam->width = App.GetWidth();
Cam->height = App.GetHeight();
Cam->viewport.width = App.GetWidth();
Cam->viewport.height = App.GetHeight();
}
scene의 헤더와 cpp파일입니다. ImGui로 이미지의 좌표를 계산해서 직접 입력할 수 있도록 했습니다.
읽어주셔서 감사합니다.