드디어 인풋 클래스에서 모든 처리를 할 수 있게 되었다! 이제 웬만하면 인풋클래스를 수정하지 않아도 될 것이다. 현재 필요한 기능을 모두 제공하니까. 키보드 키를 얻어낼 때 map을 만들어야 하지만... 일단 오늘은 Texture를 가져오도록 해보자.
일단 필요한 용어 정리.
'SamplerState란 대체 무엇인가?'
일단 Sample이라는 건 검색해보니 랜덤한 입력에 대해서 regular한 출력을 하는 과정이 Sample이라고 한다. 대충 감이 오긴 하지만 구체적으로 좀 더 파보자.
다음 링크를 참조하자.
http://keithditch.powweb.com/Games/html/sampler_states.html
Direct3D Sampler States
Sampler States Sampling is the process of taking values from an input at regular intervals. The more values we take the more accurate the resultant representation. It is important to remember that we are rendering our graphics onto a finite sized grid of p
keithditch.powweb.com
요는 유한 크기의 픽셀 배열인 텍스쳐에서 컬러를 추출하여 0.0~1.0 범위를 가지는 uv 좌표에 대응 시키기 위한 작업이다. 링크에도 나와있지만 16X16 크기의 매우 화질구지 텍스쳐를 가지고 float으로 되어있는 uv 좌표에 대응 시킬 때 이 물체가 카메라로부터 멀리있어서 텍스쳐의 화질이 구려도 상관없으면 문제 없겠지만 카메라 가까이 줌인 되어있는 상황이라면 그림판에서 이미지 확대했을 때 처럼 계단 현상이 지글지글 생길 것이다. 16X16이니까 16개의 컬러를 uv좌표 1/16 마다 대응 시켜야 하니까 박스 모양이 되는 것이다. 그러니까 SamplerState에서는 유한한 픽셀 크기를 가질 수 밖에 없는 텍스쳐의 각 픽셀 사이를 어떻게 처리할 것인지 결정하는 State인 것이다.
Texture는 Directx에서 Texture가 텍스쳐라고 불리질 못하고 ShaderResourceView라고 불린다. 내가 알던 View가 아닌데? 싶어서 검색해보니 전망, 경치 이런 뜻 말고도 보이는 상태, 풍경화 이런 뜻도 있다. 오히려 Texture는 질감, 색조묘사 이런 뜻을 담고 있다. 그러니 이미지를 3d 오브젝트의 표면에 질감으로 쓰는게 아니라 UI등등 Sprite등으로 사용한다면 엄밀히 말해 이 녀석은 Texutre가 아니고 걍 View인 것이다. View가 Texutre를 포괄하는 의미인 것 같다. 내 뇌피셜이니 진지하게 받아들이지 말도록.
그러면 이제 파일로부터 ID3D11ShaderResourceView를 생성해야 내가 Directx에게 이놈을 그리라고 명령할 수 있게 되는데, 어떻게 파일에서 불러오기를 할 수 있을까?
대략 2가지 방법이 있는데, D3DX11CreateShaderResourceViewFromFile 을 호출하는 방법은 2010 june 버전의 directx11을 써야한다. 현재 Windows SDK에는 이 녀석이 없다....
두번 째는 DirectXTK(툴킷)을 임포트하고 CreateWICTextureFromFile을 호출하는 것이다. 근데 DIrectXTK 보면 솔루션이 여러개 있고 막...어휴.... 뭐가 뭔지 모르겠다.
다행히 MS에서 걍 쓰라고 헤더랑 소스를 올려둔 것 같다. 이걸로 한번 해보자.
How to Initialize a Texture From a File - Win32 apps
This topic shows how to use Windows Imaging Component (WIC) to create the texture and the view separately.
docs.microsoft.com
아, 가져온 후 실행해봤더니 다음과 같은 링크 에러가 뜬다.
error LNK2001: unresolved external symbol WKPDID_D3DDebugObjectName
근데 이 변수가 선언된 d3dcommon.h를 include 해도 문제가 해결되지 않는다. 이유는 라이브러리를 가져오라는 강제 명령이 있지 않아서 생긴 문제였다.
#pragma comment( lib, "dxguid.lib")
이 문구를 써주니 해결되었다.
class Texture : public Bindable
{
public:
Texture(Graphics& gfx, std::string filePath);
void Bind() override;
private:
wrl::ComPtr<ID3D11ShaderResourceView> pTextureView;
};
Texture::Texture(Graphics& gfx, std::string filePath)
:
Bindable(gfx)
{
HRESULT hr;
GFX_THROW_HR(CreateWICTextureFromFile(&gfx.device, &gfx.context, WSTR(filePath).c_str(), nullptr, pTexture.GetAddressOf()));
}
void Texture::Bind()
{
gfx.context.PSSetShaderResources(0u, 1u, pTextureView.GetAddressOf());
}
뭐 일단 이런 식으로 했다. 추후 여러 장의 텍스쳐를 넣는 걸 감안하면 이렇게 하면 안되겠지만 일단 테스트용이니 0번 슬롯에 넣는 걸로 두자.
다음은 SamplerState를 등록하는 것이다.
Texture와 유사한 구성이라서 특별히 어려운 점은 없었다.
//Sampler State Wrapper 클래스
class Sampler : public Bindable
{
public:
Sampler(Graphics& gfx);
void Bind() override;
private:
D3D11_SAMPLER_DESC desc;
wrl::ComPtr<ID3D11SamplerState> pSampler;
};
여기서 desc를 지역변수로 두지 않은 이유는 추후 설정을 다르게 할 일이 있을 것 같아 아예 desc정보를 가지고 있도록 만들었다.
소스파일은 이런 식이다.
Sampler::Sampler(Graphics& gfx)
:
Bindable(gfx),
desc({})
{
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
HRESULT hr;
GFX_THROW_HR(gfx.device.CreateSamplerState(&desc, pSampler.GetAddressOf()));
}
void Sampler::Bind()
{
gfx.context.PSSetSamplers(0, 1, pSampler.GetAddressOf());
}
자, 이제 이에 대응하는 Shader를 만들 차례다.
cbuffer CBuf
{
matrix transform;
};
struct VSOut
{
float2 uv : TexCoord;
float4 pos : SV_Position;
};
VSOut main(float3 pos : Position, float2 uv : TexCoord)
{
VSOut vso;
vso.pos = mul(float4(pos, 1.0f), transform);
vso.uv = uv;
return vso;
}
Texture2D tex;
SamplerState splr;
float4 main(float2 uv : Texcoord) : SV_Target
{
return tex.Sample(splr, uv);
}
VertexShader와 PixelShader이다. Vertex는 단순히 Color 대신 Texcoord를 받도록 했고, PS에서는 그냥 Sampler 함수를 돌려서 텍스처와 uv좌표를 대응시켰다.
자, 이제 마지막으로 해야할 것은? Vertex에 Texture 정보를 추가해주는 것이다.
저번에 만든 VertexLayout 헤더에 enum과 Map 구조체, case 레이블 문에 Texture2D를 추가해줌으로써 작업 완료.
이제 렌더링 파이프라인에서 해당 Texture와 Sampler를 바인딩해주면 문제없이 렌더링 된다. 물론 InputLayout 등등도 처리해주는 건 당연히 하고.
'진행과정 기록 > GameEngine' 카테고리의 다른 글
20200202 Assimp(Open Asset Importer) (2) | 2020.02.02 |
---|---|
20200201 앞으로 할일 (0) | 2020.02.01 |
20200130 Input class - Wheel, Mouse Raw Input (0) | 2020.01.30 |
20200129 Input 클래스 수정 (0) | 2020.01.29 |
20200128 Camera, imgui (0) | 2020.01.28 |