ImGui 활용한 DirectX 11 3D를 이용한 2D를 만드는 내용입니다.
본 내용은 똑같이 사용할 수 없음을 알립니다. (참고 및 공부자료로 만들어진 내용임을 밝힙니다.)
전 과정에 대해 이해를 해야 다음 이 부분에 대한 이해를 할 수 있음을 밝힙니다
이전 자료) https://ppatabox.tistory.com/63
21.12.07~
Rect.hlsl 복사후 Line.hlsl 만들기 (빌드에서 제외 시키기 (속성-> 빌드에서 제외(예))
Line.은 NDC공간 사용했음
이미지 _Textures / MetalSlug / Player.png 로 저장
사용될 이미지 파일
현재 코드와 함께 텍스쳐 2D이미지의 관리 및 객체를 받는 과정에 대해 이해하기 바란다.
코드를 분석해보고 지금까지 건너 왔던 것들을 확인해보자
월드를 지정하여 캐릭터 애니메이션을 띄워 보았다.
아래 메탈슬러그 캐릭터가 움직이는 모습을 볼 수 있다.
각 프레임당 움직일 값을 주었고
png파일을 Player.cpp에서 각각 위치한 것을 포토샵으로 정점위치와 값을 입력해서 떼어준 값이다. Uv 부분이 잘못되면 값이 튀틀리니 주의 하자
Texture.h
#pragma once
class Texture
{
public:
struct Vertex
{
Vector3 Position;
Vector2 Uv;
Color4 Color;
};
public:
static Texture* Make
(
wstring fileName,
Vector2 cutStart = Vector2(0, 0),
Vector2 cutSize = Vector2(0, 0),
Color4 color = Color4(1, 1, 1, 1)
);
private:
static map<wstring, ID3D11ShaderResourceView*> textureMap;
static vector<Texture *> textures;
public:
Texture(ID3D11ShaderResourceView* srv, Vector2 cutStart, Vector2 cutEnd, Color4 color);
~Texture();
ID3D11ShaderResourceView* GetSrv() { return srv; }
void Render();
private:
void CreateBuffer();
private:
ID3D11ShaderResourceView* srv;
VertexBuffer* vertexBuffer;
Shader* shader;
Vector2 textureSize;
Vector2 cutStart;
Vector2 cutEnd;
Vector2 uvStart;
Vector2 uvEnd;
Color4 color;
};
Texture.cpp
#include "stdafx.h"
#include "Texture.h"
map<wstring, ID3D11ShaderResourceView*> Texture::textureMap;
vector<Texture *> Texture::textures;
Texture * Texture::Make(wstring fileName, Vector2 cutStart, Vector2 cutSize, Color4 color)
{
HRESULT hr;
ID3D11ShaderResourceView* srv;
if (textureMap.count(fileName) < 1)
{
wstring fullPath = L"../_Textures/" + fileName;
D3DX11CreateShaderResourceViewFromFile
(
Device,
fullPath.c_str(),
NULL,
NULL,
&srv,
&hr
);
assert(SUCCEEDED(hr));
textureMap.insert(pair<wstring, ID3D11ShaderResourceView*>(fileName, srv));
}
srv = textureMap[fileName];
Vector2 cutEnd;
cutEnd.x = cutStart.x + cutSize.x;
cutEnd.y = cutStart.y + cutSize.y;
Texture* texture = new Texture(srv, cutStart, cutEnd, color);
textures.push_back(texture);
return texture;
}
Texture::Texture(ID3D11ShaderResourceView * srv, Vector2 cutStart, Vector2 cutEnd, Color4 color)
: srv(srv), color(color)
{
shader = new Shader(L"Texture.hlsl");
D3D11_INPUT_ELEMENT_DESC layoutDesc[] =
{
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0,
"UV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0,
"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0,
};
shader->CreateInputLayout(layoutDesc, ARRAYSIZE(layoutDesc));
ID3D11Texture2D* texture;
srv->GetResource((ID3D11Resource **)&texture);
D3D11_TEXTURE2D_DESC textureDesc;
texture->GetDesc(&textureDesc);
textureSize = Vector2((float)textureDesc.Width, (float)textureDesc.Height);
uvStart.x = (cutStart.x > 0) ? cutStart.x / textureSize.x : 0;
uvStart.y = (cutStart.y > 0) ? cutStart.y / textureSize.y : 0;
uvEnd.x = (cutEnd.x > 0) ? cutEnd.x / textureSize.x : 1;
uvEnd.y = (cutEnd.y > 0) ? cutEnd.y / textureSize.y : 1;
this->cutStart = cutStart;
this->cutEnd.x = (cutEnd.x < 1) ? textureSize.x : cutEnd.x;
this->cutEnd.y = (cutEnd.y < 1) ? textureSize.y : cutEnd.y;
CreateBuffer();
}
void Texture::CreateBuffer()
{
Vertex* vertices = new Vertex[6];
Vector2 start = uvStart;
Vector2 end = uvEnd;
vertices[0].Position = Vector3(-0.5f, -0.5f, 0.0f);
vertices[1].Position = Vector3(-0.5f, +0.5f, 0.0f);
vertices[2].Position = Vector3(+0.5f, -0.5f, 0.0f);
vertices[3].Position = Vector3(+0.5f, -0.5f, 0.0f);
vertices[4].Position = Vector3(-0.5f, +0.5f, 0.0f);
vertices[5].Position = Vector3(+0.5f, +0.5f, 0.0f);
vertices[0].Uv = Vector2(start.x, end.y); //Uv쪽 설정 필기참조
vertices[1].Uv = Vector2(start.x, start.y);
vertices[2].Uv = Vector2(end.x, end.y);
vertices[3].Uv = Vector2(end.x, end.y);
vertices[4].Uv = Vector2(start.x, start.y);
vertices[5].Uv = Vector2(end.x, start.y);
vertices[0].Color = color;
vertices[1].Color = color;
vertices[2].Color = color;
vertices[3].Color = color;
vertices[4].Color = color;
vertices[5].Color = color;
vertexBuffer = new VertexBuffer(vertices, 6, sizeof(Vertex));
SAFE_DELETE_ARRAY(vertices);
}
Texture::~Texture()
{
SAFE_RELEASE(srv);
}
void Texture::Render()
{
shader->Render();
vertexBuffer->Render();
DeviceContext->PSSetShaderResources(0, 1, &srv);
DeviceContext->Draw(6, 0);
}
Animation.h
#pragma once
struct FAnimation
{
Texture* texture;
float time;
FAnimation()
{
texture = NULL;
time = 0.25f;
}
FAnimation(Texture* texture, float time = 0.25f)
{
this->texture = texture;
this->time = time;
}
};
class Animation
{
public:
Animation();
~Animation();
UINT GetPlayFromIndex() { return playFrameIndex; }
ID3D11ShaderResourceView* GetCurrentSrv() { return frames[playFrameIndex].texture->GetSrv(); }
void Initialize(vector<FAnimation> animations);
void Play(UINT frame = 0);
void Pause();
void Stop();
void Update();
void Render();
private:
vector<FAnimation> frames;
private:
bool bPlaying = false;
UINT playFrameIndex = 0;
float playTime = 0.0f;
};
Animation.cpp
#include "stdafx.h"
#include "Animation.h"
Animation::Animation()
{
}
Animation::~Animation()
{
for (FAnimation& frame : frames)
SAFE_DELETE(frame.texture);
}
void Animation::Initialize(vector<FAnimation> animations)
{
frames = animations;
}
void Animation::Play(UINT frame)
{
bPlaying = true;
playFrameIndex = frame;
playTime = Time->Running();
}
void Animation::Pause()
{
bPlaying = false;
}
void Animation::Stop()
{
bPlaying = false;
playFrameIndex = 0;
}
void Animation::Update()
{
FAnimation& frame = frames[playFrameIndex];
if (Time->Running() - playTime >= frame.time)
{
playFrameIndex++;
if (playFrameIndex >= frames.size())
playFrameIndex = 0;
playTime = Time->Running();
}
}
void Animation::Render()
{
frames[playFrameIndex].texture->Render();
}
쉐이더 부분
Texture.hlsl
struct VertexInput
{
float4 Position : POSITION0;
float2 Uv : UV0;
float4 Color : Color0;
};
struct PixelInput
{
float4 Position : SV_POSITION;
float2 Uv : UV0;
float4 Color : Color0;
};
cbuffer VS_Vp : register(b0)
{
matrix View;
matrix Projection;
}
cbuffer VS_World : register(b1)
{
matrix World;
}
PixelInput VS(VertexInput input)
{
PixelInput output;
output.Position = mul(input.Position, World);
output.Position = mul(output.Position, View);
output.Position = mul(output.Position, Projection);
output.Uv = input.Uv;
output.Color = input.Color;
return output;
}
SamplerState Sampler : register(s0);
Texture2D Texture : register(t0);
float4 PS(PixelInput input) : SV_TARGET
{
return Texture.Sample(Sampler, input.Uv) * input.Color;
}
Line.hlsl
struct VertexInput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
};
struct PixelInput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
};
PixelInput VS(VertexInput input)
{
PixelInput output;
output.Position = input.Position;
output.Color = input.Color;
return output;
}
float4 PS(PixelInput input) : SV_TARGET
{
return input.Color;
}
Player.h/.cpp
#pragma once
class Player
{
public:
Player();
~Player();
void Update();
void Render();
private:
World* world;
SamplerState* samplerState;
Animation* animation;
};
#include "stdafx.h"
#include "Player.h"
Player::Player()
{
world = new World();
world->Position(200, 100);
world->Scale(50, 50);
animation = new Animation();
//해당 애니메이션을 불러들임
vector<FAnimation> frames;
frames.push_back(FAnimation(Texture::Make(L"MetalSlug/Player.png", Vector2(3, 2), Vector2(30, 38))));
frames.push_back(FAnimation(Texture::Make(L"MetalSlug/Player.png", Vector2(34, 2), Vector2(30, 38))));
frames.push_back(FAnimation(Texture::Make(L"MetalSlug/Player.png", Vector2(64, 2), Vector2(30, 38))));
animation->Initialize(frames);
samplerState = new SamplerState();
}
Player::~Player()
{
SAFE_DELETE(world);
SAFE_DELETE(animation);
SAFE_DELETE(samplerState);
}
void Player::Update()
{
animation->Update();
}
void Player::Render()
{
samplerState->Render();
world->Render();
animation->Render();
}
Device.cpp/Running 부분
WPARAM Running()
{
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
srand((UINT)time(NULL));
Key = new Keyboard();
Time = new Timer();
InitImGui();
InitScene();
struct VpDesc
{
Matrix View;
Matrix Projection;
} vpDesc;
D3DXVECTOR3 eye(0, 0, -1);
D3DXVECTOR3 lookAt(0, 0, 0);
D3DXVECTOR3 up(0, 1, 0);
D3DXMatrixLookAtLH(&vpDesc.View, &eye, &lookAt, &up);
D3DXMatrixTranspose(&vpDesc.View, &vpDesc.View);
D3DXMatrixOrthoOffCenterLH(&vpDesc.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
D3DXMatrixTranspose(&vpDesc.Projection, &vpDesc.Projection);
VpBuffer = new ConstantBuffer(&vpDesc, sizeof(VpDesc), 0);
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Time->Update();
UpdateImGui();
Update();
DeviceContext->ClearRenderTargetView(RTV, BgColor);
VpBuffer->Render();
Render();
RenderImGui();
SwapChain->Present(0, 0);
}
}
DestroyScene();
SAFE_DELETE(VpBuffer);
SAFE_DELETE(Key);
SAFE_DELETE(Time);
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
return msg.wParam;
}
Main.cpp
#include "stdafx.h"
#include "Game/Player.h"
Line* line = NULL;
Rect* rect = NULL;
Player* player = NULL;
void InitScene()
{
line = new Line();
rect = new Rect();
rect->Position(100, 100);
rect->Scale(50, 50);
player = new Player();
}
void DestroyScene()
{
SAFE_DELETE(line);
SAFE_DELETE(rect);
SAFE_DELETE(player);
}
void Update()
{
rect->Update();
player->Update();
}
void Render()
{
line->Add(Vector2(100, 30), Vector2(Width - 100, 30), Color4(1, 0, 0, 1));
line->Render();
rect->Render();
player->Render();
}
수정사항이 있다면 적극 반영 및 수정하겠음
바로 UnrealEngine으로 넘어갈 것이다.
추후 다렉 파일연습과 수업이 있으면 올리겠음.
기존 Animation에 대해서 분석한 것이 있다면 댓글로 알려주면 좋겠습니다.