{{ label!='' ? 'Label : ' : (q!='' ? '검색 : ' : '전체 게시글') }} {{ label }} {{ q }} {{ ('('+(pubs|date:'yyyy-MM')+')') }}

[DirectX12] ddx(), ddy()

텍스처의 밉맵 수준은 언제 결정되나요?

  DirectX12에서 적절한 대답은, "Sample() 함수를 호출할 때"이다. 즉, 픽셀 셰이더 단계가 될 것이다. Sample() 함수 내에서는 다시 SampleGrad()를 호출한다. SampleGrad()에는 ddx, ddy 값을 의미하는 매개변수가 전달되며, 이를 통해서 밉맵 수준을 결정할 수 있는 것이다.


ddx, ddy의 값을 어떻게 얻나요?

  그렇다면 Sample() 내에서 SampleGrad()를 호출하기 위해 ddx, ddy 값을 계산해야 할 것이다. HLSL에서는 ddx(), ddy() 내장 함수를 지원하며, 이를 통해서 해결할 수 있다.

  ddx(), ddy()에 대한 설명을 읽어보면 화면 공간의 x, y에 대해서 지정된 값의 편도함수를 반환한다고 써져있다. 이를 이해하는 데 약간의 혼란이 있을 수 있다. 이것이 어떻게 동작하는지를 알면 조금 더 명확해질 것이다.


  그래픽 하드웨어는 병렬적으로 프로세스를 처리하며, 워프의 개념이 있어서 가령 32개의 스레드가 동일한 코드를 발맞추어 실행한다. 픽셀 셰이더는 특히 픽셀 단위로 처리되며, 각각의 스레드도 최소한 2x2 픽셀 단위로 처리된다. 따라서 해당 스레드는 자신 주변의 픽셀에 대한 정보 역시 알 수 있게 된다.


  따라서 ddx()와 ddy()는 "내 픽셀에서 평가된 매개변수로 주어진 값"과 "옆 픽셀에서 평가된 매개변수로 주어진 값"의 차이를 반환하는 것이다. 예를 들어, 다음과 같은 코드를 작성하면 화면 공간에서 x나 y로 움직일 때 텍스처 좌표의 변화가 얼마나 급격하게 변하는지를 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
PixelOut PS(VertexOut pin)
{
    PixelOut pixelOut;
    
    // ...
    pixelOut.color = float4(
length(ddx(pin.TexC)), 
length(ddy(pin.TexC)),
 0.0f, 
1.0f) * 100.0f;

    return pixelOut;
}
cs


빨간색을 띨수록 x축에 대한 텍스처 좌표의 변화가 크고,
초록색을 띨수록 y축에 대한 텍스처 좌표의 변화가 크다.


  즉, 내 픽셀에서 평가된 pin.TexC와 옆 픽셀에서 평가된 pin.TexC를 비교하여 그 차이를 알려주는 것이다. 예를 들어, ddx(), ddy() 함수의 매개변수에 상수 값을 넣게 되면 다음처럼 검은 화면만 보이게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
PixelOut PS(VertexOut pin)
{
    PixelOut pixelOut;
    
    // ...
    pixelOut.color = float4(
length(ddx(0.5f)), 
length(ddy(0.5f)),
 0.0f, 
1.0f);

    return pixelOut;
}
cs



  왜냐하면 내 픽셀이든 옆 픽셀이든 해당 값은 상수이므로 변화가 없기 때문이다. 상수 함수를 미분하면 0이지 않은가? 이런 식으로 ddx(), ddy()는 동작하며 이를 통해서 텍스처의 밉맵 수준을 결정할 수 있게 된다.


댓글

이 블로그의 인기 게시물

[코딩의탑] 4층: 툰 쉐이딩

[코딩의탑] 3층: 바다 렌더링

[코딩의탑] 5층: 포탈(Portal), 더 나아가기