수업


주제

  • DirectX11 기반 텍스처 시스템에서 UV 좌표 샘플링 방식의 차이를 이해하고, 이를 Shader에서 Address 모드와 Filter 설정을 통해 제어하는 방법을 실습한다.
  • SamplerState 설정을 통해 UV 좌표가 범위를 벗어났을 때 Wrap, Mirror, Clamp, Border 방식으로 각각 어떻게 시각적으로 출력되는지를 확인하고,
  • Address 값을 통해 픽셀 셰이더에서 동적으로 샘플링 방식을 변경하는 구조를 구현한다.

개념

  • 텍스처 샘플링(Sampling): 픽셀 셰이더에서 텍스처와 UV 좌표를 통해 특정 위치의 색상을 추출하는 과정.

  • SamplerState: HLSL에서 텍스처 샘플링에 사용할 Filter (보간 방식)Address Mode (UV 초과 처리 방식)을 정의하는 상태 객체.

  • Filter: 텍스처가 확대되거나 축소될 때 중간 색상(보간값)을 어떻게 계산할지 결정함.

  • Address Mode: 텍스처 좌표(UV)가 0~1의 범위를 벗어났을 때 어떤 방식으로 텍스처를 표시할지를 지정함.

    각 Address Mode는 다음과 같은 특징을 가진다:

    모드설명
    WrapUV > 1 일 때 텍스처가 반복됨
    MirrorUV > 1 일 때 대칭적으로 반사되어 반복됨
    Clamp텍스처 가장자리 픽셀이 고정된 상태로 계속 채워짐
    Border텍스처 범위를 벗어난 영역은 지정한 색상(BorderColor)으로 채워짐

용어정리

용어설명
UV 좌표텍스처 매핑에 사용되는 2D 정규 좌표계. (0,0)~(1,1) 범위를 갖는다
SamplerState텍스처 샘플링 방식과 UV 초과 처리 방식을 정의하는 HLSL 상태 객체
Address ModeUV 범위를 벗어난 좌표의 처리 방식 (Wrap, Mirror, Clamp, Border)
Filter확대/축소 시 보간 처리 방식 (예: Linear, Point 등)
BorderColorBorder 모드 사용 시 텍스처 외 영역을 채우는 색상
Shader Resource View (SRV)GPU 텍스처 자원을 셰이더에 전달할 때 사용하는 인터페이스

코드 분석

✅ HLSL - Sampler.fx

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;
}
  • 정점 셰이더는 위치 정보를 행렬 변환해 클립 공간으로 넘겨주고, UV는 그대로 픽셀 셰이더로 전달

✅ SamplerState 4종 선언

SamplerState SamplerAddressWrap {
    AddressU = Wrap;
    AddressV = Wrap;
};

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

SamplerState SamplerAddressClamp {
    AddressU = Clamp;
    AddressV = Clamp;
};

SamplerState SamplerAddressBorder {
    AddressU = Border;
    AddressV = Border;
    BorderColor = float4(1, 0, 0, 1); // 붉은색으로 외곽 표시
};
  • 각각 U와 V 축에서 같은 방식으로 처리
  • BorderColor는 오직 Border 모드에서만 적용

✅ 픽셀 셰이더 분기 처리

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(SamplerAddressClamp, input.uv); // 기본값
}
  • Address 값에 따라 어떤 SamplerState를 사용할지를 분기
  • 예외 처리로 기본값 Clamp 지정

✅ Technique 설정

technique11 T0 {
    pass P0 {
        SetVertexShader(CompileShader(vs_5_0, VS()));
        SetPixelShader(CompileShader(ps_5_0, PS()));
    }
};
  • 셰이더 기술 구성: 하나의 패스(P0)로 구성된 텍스처 샘플링 처리

✅ C++ SamplerDemo::Render()

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

// 행렬 및 텍스처 바인딩
_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());

// 샘플링 모드 선택
_shader->GetScalar("Address")->SetInt(ADDRESS_WRAP);  // 테스트 시 0~3 변경 가능

// 정점/인덱스 버퍼 바인딩 및 드로우
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);
  • enumSetInt()를 이용해 Sampler.fx에 설정된 Address 값 전달
  • 다양한 샘플링 결과를 눈으로 직접 확인 가능

핵심

  1. 텍스처 UV 좌표가 0~1을 초과할 경우 Address 모드에 따라 처리 방식이 달라진다.
  2. HLSL 셰이더에서는 SamplerState를 선언하고, AddressU/AddressV를 Wrap, Mirror, Clamp, Border로 설정한다.
  3. 픽셀 셰이더에서는 조건문으로 Address 값을 기준으로 Sampler를 분기 적용한다.
  4. Border 모드는 외곽을 특정 색상으로 채워 시각적인 테두리를 만들 수 있다.
  5. Filter는 확대/축소 시 중간값을 보간하는 방식이지만, 시각적인 차이는 Address보단 미묘하므로 실습에선 Address 위주로 테스트.
  6. C++에서는 GetScalar("Address")->SetInt()를 통해 Address 값을 실시간으로 셰이더에 전달한다.

profile
李家네_공부방

0개의 댓글