• 티스토리 홈
  • 프로필사진
    유니얼
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
유니얼
  • 프로필사진
    유니얼
    • 분류 전체보기 (295)
      • Unity (17)
        • 게임 개발 (5)
      • Unreal (24)
        • 게임 개발 (20)
      • DirectX (36)
      • 코딩테스트 (91)
        • 프로그래머스 (25)
        • 백준 (66)
      • Google Workspace (1)
      • Programing (102)
        • C# (68)
        • C++ (24)
        • JavaScript (10)
      • 게임 서버 프로그래밍 (17)
      • Web (6)
        • 슈퍼코딩 (6)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
    등록된 댓글이 없습니다.
  • 최근 공지
    등록된 공지가 없습니다.
# Home
# 공지사항
#
# 태그
# 검색결과
# 방명록
  • [DirectX11] Sampler의 이해
    2024년 03월 05일
    • 유니얼
    • 작성자
    • 2024.03.05.:21
    728x90

    DirectX 11로 게임 엔진 아키텍처 만들기

    DirectX11을 공부하면서 게임 엔진 아키텍처를 설계하는 것은 매우 흥미롭고 교육적인 경험입니다. 이번 글에서는 DirectX11 내에서 중요한 역할을 하는 Sampler에 대해 알아보겠습니다. Sampler는 텍스처 데이터를 픽셀 셰이더로 가져올 때 사용되는 방식을 정의합니다. 적절한 샘플링은 게임의 비주얼 품질을 대폭 향상시킬 수 있으므로, 이를 잘 이해하고 사용하는 것이 중요합니다.

    Result1Result2
    Result3Result4

    참고강의 링크:

    https://www.inflearn.com/course/directx11-%EA%B2%8C%EC%9E%84%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%95%BD%EB%B0%98/dashboard

     

    [게임 프로그래머 도약반] DirectX11 입문 강의 - 인프런

    게임 프로그래머 공부에 있어서 필수적인 DirectX 11 지식을 초보자들의 눈높이에 맞춰 설명하는 강의입니다., [사진][사진] [사진] 게임 개발자는 Unreal, Unity만 사용할 줄 알면 되는 거 아닌가요? 엔

    www.inflearn.com

    Sampler란?

    Sampler는 텍스처에서 색상 데이터를 어떻게 추출할지 결정하는 객체입니다. 텍스처 좌표가 정확히 텍셀(Texel, 텍스처의 픽셀)에 매핑되지 않을 때, 어떤 텍셀의 색상을 사용할지 결정하는 규칙을 제공합니다. 이는 특히 텍스처가 확대, 축소, 회전되거나, 뷰포트의 픽셀과 정확히 일치하지 않을 때 중요합니다.

    기본 구조

    먼저, VertexInput 구조체와 VertexOutput 구조체를 정의하여, 각각의 정점 데이터와 픽셀 셰이더로 넘겨줄 데이터를 명시합니다. VS(Vertex Shader)는 입력된 정점 데이터를 화면 상의 위치로 변환하고, PS(Pixel Shader)는 각 픽셀의 최종 색상을 계산합니다.

    // 변환 행렬을 정의합니다. 
    이 행렬들은 3D 오브젝트를 월드 공간, 뷰 공간, 프로젝션 공간으로 변환하는 데 사용됩니다.
    matrix World;
    matrix View;
    matrix Projection;
    
    // 텍스처 자원을 정의합니다.
    Texture2D Texture0;
    
    // 텍스처 주소 지정 모드를 결정하기 위한 변수입니다.
    uint Address;
    
    // 버텍스 쉐이더의 입력 구조체입니다. 각 버텍스에 대한 정보를 담고 있습니다.
    struct VertexInput
    {
    	float4 position : POSITION; // 버텍스의 위치
    	float2 uv : TEXCOORD;       // 텍스처 좌표
    };
    
    // 버텍스 쉐이더의 출력 구조체입니다. 처리된 버텍스 정보를 담고 있습니다.
    struct VertexOutput
    {
    	float4 position : SV_POSITION; // 스크린 공간에서의 버텍스 위치
    	float2 uv : TEXCOORD;          // 텍스처 좌표
    };

    SamplerState의 정의와 적용

    SamplerState는 텍스처 샘플링 시 텍스처 좌표가 정확한 텍셀에 매칭되지 않을 때, 색상을 어떻게 결정할지 정의합니다. 다음은 다양한 SamplerState의 예시입니다:

    • Wrap: 텍스처 좌표가 [0, 1] 범위를 벗어났을 때, 좌표값을 '감싸서' 반복 적용합니다.
    • Mirror: 좌표가 범위를 벗어날 때마다 이미지가 거울처럼 반전됩니다.
    • Clamp: 좌표가 [0, 1] 범위를 벗어나면, 가장자리의 색상을 계속 사용합니다.
    • Border: 지정된 색상으로 경계를 채웁니다.
    // 샘플러 상태를 정의합니다. 이 상태는 텍스처 샘플링 시의 주소 지정 모드를 결정합니다.
    SamplerState Sampler0;
    
    // Wrap 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 좌표를 '반복'합니다.
    SamplerState SamplerAddressWrap
    {
    	AddressU = Wrap;
    	AddressV = Wrap;
    };
    
    // Mirror 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 좌표를 '반사'하여 반복합니다.
    SamplerState SamplerAddressMirror
    {
    	AddressU = Mirror;
    	AddressV = Mirror;
    };
    
    // Clamp 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 좌표를 경계값에 '고정'합니다.
    SamplerState SamplerAddressClamp
    {
    	AddressU = Clamp;
    	AddressV = Clamp;
    };
    
    // Border 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 지정된 '경계 색상'을 사용합니다.
    SamplerState SamplerAddressBorder
    {
    	AddressU = Border;
    	AddressV = Border;
    	BorderColor = float4(1, 0, 0, 1); // 경계 색상을 빨간색으로 설정
    };

    픽셀 셰이더에서 SamplerState 사용

    PS 함수에서는 Address 변수의 값에 따라 다양한 SamplerState를 선택하여 텍스처를 샘플링합니다. 이를 통해 실행 시간에 텍스처의 샘플링 방식을 변경할 수 있습니다.

    // 픽셀 쉐이더 함수입니다.
    float4 PS(VertexOutput input) : SV_TARGET
    {
    	// Address 변수의 값에 따라 다른 샘플러를 사용하여 텍스처를 샘플링합니다.
    	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);
    }

    Shader코드

    Sampler.fx

    // 변환 행렬을 정의합니다. 이 행렬들은 3D 오브젝트를 월드 공간, 뷰 공간, 프로젝션 공간으로 변환하는 데 사용됩니다.
    matrix World;
    matrix View;
    matrix Projection;
    
    // 텍스처 자원을 정의합니다.
    Texture2D Texture0;
    
    // 텍스처 주소 지정 모드를 결정하기 위한 변수입니다.
    uint Address;
    
    // 버텍스 쉐이더의 입력 구조체입니다. 각 버텍스에 대한 정보를 담고 있습니다.
    struct VertexInput
    {
    	float4 position : POSITION; // 버텍스의 위치
    	float2 uv : TEXCOORD;       // 텍스처 좌표
    };
    
    // 버텍스 쉐이더의 출력 구조체입니다. 처리된 버텍스 정보를 담고 있습니다.
    struct VertexOutput
    {
    	float4 position : SV_POSITION; // 스크린 공간에서의 버텍스 위치
    	float2 uv : TEXCOORD;          // 텍스처 좌표
    };
    
    // 버텍스 쉐이더 함수입니다.
    VertexOutput VS(VertexInput input)
    {
    	VertexOutput output;
    	// 입력된 버텍스 위치를 월드, 뷰, 프로젝션 행렬을 사용하여 변환합니다.
    	output.position = mul(input.position, World);
    	output.position = mul(output.position, View);
    	output.position = mul(output.position, Projection);
    
    	// 텍스처 좌표를 출력 구조체로 복사합니다.
    	output.uv = input.uv;
    
    	return output;
    }
    
    // 샘플러 상태를 정의합니다. 이 상태는 텍스처 샘플링 시의 주소 지정 모드를 결정합니다.
    SamplerState Sampler0;
    
    // Wrap 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 좌표를 '반복'합니다.
    SamplerState SamplerAddressWrap
    {
    	AddressU = Wrap;
    	AddressV = Wrap;
    };
    
    // Mirror 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 좌표를 '반사'하여 반복합니다.
    SamplerState SamplerAddressMirror
    {
    	AddressU = Mirror;
    	AddressV = Mirror;
    };
    
    // Clamp 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 좌표를 경계값에 '고정'합니다.
    SamplerState SamplerAddressClamp
    {
    	AddressU = Clamp;
    	AddressV = Clamp;
    };
    
    // Border 모드: 텍스처 좌표가 [0,1] 범위를 벗어났을 때, 지정된 '경계 색상'을 사용합니다.
    SamplerState SamplerAddressBorder
    {
    	AddressU = Border;
    	AddressV = Border;
    	BorderColor = float4(1, 0, 0, 1); // 경계 색상을 빨간색으로 설정
    };
    
    // 픽셀 쉐이더 함수입니다.
    float4 PS(VertexOutput input) : SV_TARGET
    {
    	// Address 변수의 값에 따라 다른 샘플러를 사용하여 텍스처를 샘플링합니다.
    	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);
    }
    
    // 렌더링 기법을 정의합니다. 여기서는 두 개의 패스를 사용합니다.
    technique11 T0
    {
    	pass P0
    	{
    		// 첫 번째 패스: 버텍스 쉐이더와 픽셀 쉐이더를 설정합니다.
    		SetVertexShader(CompileShader(vs_5_0, VS()));
    		SetPixelShader(CompileShader(ps_5_0, PS()));
    	}
    	pass P1
    	{
    		// 두 번째 패스: 동일한 쉐이더를 재사용합니다.
    		SetVertexShader(CompileShader(vs_5_0, VS()));
    		SetPixelShader(CompileShader(ps_5_0, PS()));
    	}
    };

    프로젝트 호출

    생성한 Sampler는 픽셀 셰이더에서 사용됩니다. ID3D11DeviceContext::PSSetSamplers() 함수를 호출하여 픽셀 셰이더의 Sampler 슬롯에 바인딩합니다. 이렇게 하면 픽셀 셰이더에서 텍스처를 샘플링할 때 해당 Sampler의 설정을 사용하게 됩니다.

    SamplerDemo.h

    #pragma once
    #include "IExecute.h"
    #include "Geometry.h"
    #include "GameObject.h"
    
    class SamplerDemo : public IExecute
    {
    public:
    	void Init() override;
    	void Update() override;
    	void Render() override;
    
    	shared_ptr<Shader> _shader;
    
    	//Object
    	shared_ptr<Geometry<VertexTextureData>> _geometry;
    	shared_ptr<VertexBuffer> _vertexBuffer;
    	shared_ptr<IndexBuffer> _indexBuffer;
    
    	Vec3 _translation = Vec3(0.f, 0.f, 0.f);
    
    	Matrix _world = Matrix::Identity;
    
    	//Camera
    	shared_ptr<GameObject> _camera;
    
    	shared_ptr<Texture> _texture;
    };

    SamplerDemo.cpp

    #include "pch.h"
    #include "06. SamplerDemo.h"
    #include "GeometryHelper.h"
    #include "Camera.h"
    #include "CameraScript.h"
    #include "Transform.h"
    #include "Texture.h"
    
    void SamplerDemo::Init()
    {
    	_shader = make_shared<Shader>(L"05. Sampler.fx");
    
    	// Object
    	_geometry = make_shared<Geometry<VertexTextureData>>();
    	//GeometryHelper::CreateQuad(_geometry);
    	//GeometryHelper::CreateCube(_geometry);
    	//GeometryHelper::CreateSphere(_geometry);
    	GeometryHelper::CreateGrid(_geometry, 256, 256);
    
    	_vertexBuffer = make_shared<VertexBuffer>();
    	_vertexBuffer->Create(_geometry->GetVertices());
    	_indexBuffer = make_shared<IndexBuffer>();
    	_indexBuffer->Create(_geometry->GetIndices());
    
    	// Camera
    	_camera = make_shared<GameObject>();
    	_camera->GetOrAddTransform();
    	_camera->AddComponent(make_shared<Camera>());
    	_camera->AddComponent(make_shared<CameraScript>());
    	_camera->GetTransform()->SetWorldPosition(Vec3(0.f, 10.f, -2.f));
    
    	_texture = RESOURCES->Load<Texture>(L"UnityLogo", L"..\\Resources\\Texture\\UnityLogo.png");
    }
    
    void SamplerDemo::Update()
    {
    	_camera->Update();
    }
    
    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_WRAP);
    
    	uint32 stride = _vertexBuffer->GetStride();
    	uint32 offset = _vertexBuffer->GetOffset();
    
    	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);
    }

    결론

    Sampler는 DirectX11 게임 엔진에서 텍스처 샘플링 방식을 정의하는 중요한 구성 요소입니다. 적절한 샘플링 방식의 선택은 게임의 비주얼 품질과 성능에 큰 영향을 미칩니다. 다양한 SamplerState를 정의하고 적용함으로써, 게임이나 어플리케이션에서 원하는 비주얼 효과를 효율적으로 구현할 수 있습니다.

    반응형
    다음글
    다음 글이 없습니다.
    이전글
    이전 글이 없습니다.
    댓글
조회된 결과가 없습니다.
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
목차
표시할 목차가 없습니다.
    • 안녕하세요
    • 감사해요
    • 잘있어요

    티스토리툴바