DirectX

38. DirectX11 3D 입문_Sampling

devRiripong 2024. 2. 7.
반응형

Sampling과 관련된 부분을 실습해 본다.

 

1. 06. SamplerDemo 클래스 생성하기

탐색기에서 05. TextureDemo를 복제해서 이름을 06. SamplerDemo로 수정한다.

솔루션 탐색기에서 Client/Game 필터에 넣어준다.

코드 내용도 SamplerDemo에 맞게 수정한다.

void SamplerDemo::Init()
{
	_shader = make_shared<Shader>(L"05. Sampler.fx");

이 부분도 05. Sampler.fx로 수정한다.

 

2. 05. Sampler.fx 셰이더 생성하기 

탐색기에서 Shaders 폴더의 04. Texture.fx를 복제하여 이름을 05. Sampler.fx로 바꿔준다.

그리고 Main/Shaders로 넣어준다.

SamplerState Sampler0;

샘플링을 했을 때 SamplerState로 여러 옵션을 정해줄 수 있는데, 그 부분을 테스트해본다.

 

wireframe은 사용 안 할 것이니

RasterizerState FillModeWireFrame
{
    FillMode = Wireframe;
};

이 부분은 제거한다.

 

설정할 수 있는 게 2가지가 있다고 보면 된다.

Filter 관련 부분

Address 관련 부분을 설정할 수 있다.

 

SamplerState에서 Sampler란 UV좌표에 따라 UV매핑이라는 게 꼭짓점, 정점마다 UV 좌표를 지정해 주면 그거에 맞게끔 텍스쳐를 발라주는 개념이다.

 

Filter 같은 경우는 만약에 정확하게 이미지 사이즈에 해당하는 메시가 있어서 그 크기에 딱 오려 붙일 수 있으면 좋겠지만 보통은 그렇지 않기 때문에 확대/축소를 할 때 중간값을 처리하는데 필요하다.

 

Filter = 확대/축소 일어났을 때 중간 값을 처리하는 방식

 

Address = UV가 1보다 컸을 때, 나머지 부분을 어떻게 처리?

 

전 시간에 Grid로 테스트한 게 Address와 관련이 있다고 할 수 있다.

사실상 이 Address가 중요하다.

 

05. Sampler.fx에

uint Address;

이 변수를 만들어서 여기에 값을 세팅한 다음에 이 값을 통해서 뭔가 할 수 있게 만들어 준다.

 

값을 세팅해서 여러 개 중에서 골라줄 것이다.

 

1) SamplerState 4개 만들어 주기

SamplerState를 만들어 줄 건데 Sampler0 같은 기본값 아니라 AddressU와 AddressV를 세팅할 수 있게 한다.

SamplerState SamplerAddressWrap
{
// U가 넘어 갔을 때, V가 넘어갔을 때 무엇을 할 것이냐
// 대부분은 둘 다 똑같은 경우로 두는 경우가 많다. 
    AddressU = Wrap;
    AddressV = Wrap;
};

SamplerState SamplerAddressMirror
{
    AddressU = Mirror;
    AddressV = Mirror;
};

SamplerState SamplerAddressClamp
{
// Clamp는 뭔가 자르는 느낌
    AddressU = Clamp;
    AddressV = Clamp;
};

SamplerState SamplerAddressBorder
{
// 2D 때 실습해 본 적이 있다.
    AddressU = Border;
    AddressV = Border;
    BorderColor = float4(1, 0, 0, 1); 
};

이렇게 SamplerState를 4개 만들어 주고,

 

2) uint Address값에 따라 SameplerState 선택하게 PS 만들어주기

기존에 있던 PS는 삭제하고 PS를 새롭게 만들어준다.

float4 PS(VertexOutput input) : SV_TARGET
{
    if (Address == 0)
        return Texture0.Sample(SamplerAddressWrap, input.uv); 
    
    if (Address == 1)
        return Texture0.Sample(SamplerAddressMirror, input.uv);
    
    if (Address == 2)
        return Texture0.Sample(SamplerAddressClamp, input.uv);
    
    if (Address == 3)
        return Texture0.Sample(SamplerAddressBorder, input.uv);
    
        return Texture0.Sample(Sampler0, input.uv);
}

추가적인 옵션도 넣을 수 있다.

 

예를 들어 filter를 테스트하고 싶었다고 하면,

SamplerState SamplerAddressMirror
{
    Filter = MIN_MAG_MIP_LINEAR; 
    AddressU = Mirror;
    AddressV = Mirror;
};

이렇게 추가적인 Filtert 옵션도 정해줄 수 있는데 중간값 보정은 티가 잘 안 나니까 그냥 눈에 띄는 Address 부분만 해본다.

 

이렇게 4가지 방식 중 하나를 골라주는 것이다.

Technique을 골라 줄 때는 FillModeWireFrame을 삭제했으니 P1는 삭제하고 기본 P0 만 남긴다.

technique11 T0
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_5_0, VS())); // 버전은 5.0, main 함수는 VS다는 뜻
        SetPixelShader(CompileShader(ps_5_0, PS())); 
    }
};

이렇게 세팅이 끝났다.

 

3. SamplerDemo::Render에서 05. Sampler.fx의 uint Address 값 세팅하기

SamplerDemo::Render에서 추가적으로 Address가 세팅이 되어야 한다.

enum ADDRESS_VALUE
	{
		ADDRESS_WRAP = 0, 
		ADDRESS_MIRROR = 1, 
		ADDRESS_CLAMP = 2, 
		ADDRESS_BORDER = 3, 
	};

이걸 이용해서 Shader에다가 세팅해 주면 된다.

_shader->GetScalar("Address")->SetInt(ADDRESS_WRAP);

이렇게 세팅을 해준다.

 

Main.cpp에서

#include "06. SamplerDemo.h"

를 추가하고

WinMain에서

desc.app = make_shared<SamplerDemo>(); // 실행 단위

이렇게 세팅한다.

 

4. 테스트하기

1) _shader->GetScalar("Address")->SetInt(ADDRESS_WRAP); 로 세팅한 경우

이게 ADDRESS_WRAP모드이다.

 

2) _shader->GetScalar("Address")->SetInt(ADDRESS_MIRROR); 로 세팅한 경우

_shader->GetScalar("Address")->SetInt(ADDRESS_MIRROR);

이렇게 세팅을 하면

묘하게 달라졌다.

대칭적으로 바라보는 반사되는 식으로 이루어진다.

 

3) _shader->GetScalar("Address")->SetInt(ADDRESS_CLAMP); 로 세팅한 경우

ADDRESS_CLAMP로 세팅을 하면

기본값이 ADDRESS_CLAMP인 듯하다.

 

4) _shader->GetScalar("Address")->SetInt(ADDRESS_BORDER); 로 세팅한 경우

마지막으로 ADDRESS_BORDER로 테스트를 하면

벗어나면 지정한 색으로 밀어줄 것이다.

 

5) BorderColor를 float4(0, 1, 0, 1); 로 세팅한 경우

만약에 05. Sampler.fx에서

SamplerState SamplerAddressBorder
{
// 2D 때 실습해 본 적이 있다.
    AddressU = Border;
    AddressV = Border;
    BorderColor = float4(0, 1, 0, 1); 
};

이렇게 Green으로 설정하고 하면

이렇게 세팅이 되는 걸 볼 수 있다.

 

void SamplerDemo::Render()
{
	// ? 
	_shader->GetMatrix("World")->SetMatrix((float*)&_world);
	_shader->GetMatrix("View")->SetMatrix((float*)&Camera::S_MatView);
	_shader->GetMatrix("Projection")->SetMatrix((float*)&Camera::S_MatProjection);
	_shader->GetSRV("Texture0")->SetResource(_texture->GetComPtr().Get()); 

	enum ADDRESS_VALUE
	{
		ADDRESS_WRAP = 0, 
		ADDRESS_MIRROR = 1, 
		ADDRESS_CLAMP = 2, 
		ADDRESS_BORDER = 3, 
	};

	_shader->GetScalar("Address")->SetInt(ADDRESS_BORDER);

	uint32 stride = _vertexBuffer->GetStride(); 
	uint32 offset = _vertexBuffer->GetOffset(); 

	// DeviceContext에서 IA단계에서 사용할 VertextBuffer를 묶어주는 함수였다.
	DC->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
	DC->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);

	_shader->DrawIndexed(0,0, _indexBuffer->GetCount(), 0, 0); 
}

이렇게 SamplerDemo::Render에서 테스트를 해보았다.

 

정확히 어떤 값이 뭐였는지 기억을 못 해도 되지만 내가 어떤 게 필요한지 기억해서 적당히 세팅하는 걸 고려할 수 있다.

 

ADDRESS_WRAP으로 되돌린다.

 

5. 맺음말

샘플링이란 게 이런 용도였다. UV 좌표랑 관련이 있고, UV비율에 따라서 정점에 맞도록 발라주는 게 Sampler인데

그중에서 Fillter와 Address는 UV가 1보다 컸을 때 나머지 부분을 어떻게 채울 것인가와 관련이 있는 옵션이라는 걸 실습을 통해 알 수 있었다.

 

만약 2D 때처럼 옵션을 통해서 하면 힘들게 바꿔야 하지만 지금은 편리하게 세팅하면 알아듣고 나머지 부분들이 연동이 되어서 자동으로 고쳐지니 실습할 때도 편리하게 작업할 수 있다.

반응형

'DirectX' 카테고리의 다른 글

40. DirectX11 3D 입문_Normal  (0) 2024.02.09
39. DirectX11 3D 입문_HeightMap  (0) 2024.02.08
37. DirectX11 3D 입문_Geometry  (0) 2024.02.06
36. DirectX11 3D 입문_텍스처  (0) 2024.02.06
35. DirectX11 3D 입문_카메라  (0) 2024.02.05

댓글