본문 바로가기
셰이더 (Shader)/셰이더 프로그래밍 입문 - Pope Kim (완)

[HLSL] 챕터6 - 툰셰이더

by Minkyu Lee 2023. 3. 19.

// 행렬 합치기

행렬을 미리 곱해 놓은 뒤 정점변환에 사용한다.

속도가 더 빠르다.

성능상 행렬 3번 곱하는 것보다 1번 곱하는게 빨라 미리 합치는 것이 좋다.

 

// 역행렬

반대로 공간 변환을 할 때 유용하다.

 

// 툰 셰이딩이란?

비사실적 렌더링 기법이다.

칼같이 끊어진 2~3단계의 명암 표현이다.

 

계단식으로 명암을 표현하는 것이 핵심이다.

난반사광을 0.2단위로 무조건 올림하여 표현한다.

 

// 월드공간 -> 지역공간으로 변환법

난반사광 계산시 월드행렬이 필요하다.

월드공간에서의 정점 위치와, 정점 법선을 만드는데 필요하였다.

따로 월드 행렬을 전역변수로 전달해줘야하나?

그래도 되지만, 1번만으로 똑같은 일이 가능하다.

 

핵심은 모든 변수가 동일 공간에 있어야한다이다.

빛의 위치를 지역공간으로 변환해주면 된다. (1번만 행렬곱)

 

월드공간을 지역공간으로 변환하는법

월드행렬의 역행렬을 곱하면 된다. (inverse matrix)

 

정점셰이더

struct VS_INPUT
{
   float4 mPosition : POSITION;
   float4 mNormal : NORMAL;
};

struct VS_OUTPUT
{
   float4 mPosition : POSITION;
   float3 mDiffuse : TEXCOORD1;
};

float4x4 gWorldViewProjectionMatrix;
float4x4 gInvWorldMatrix;
float4 gWorldLightPosition;

VS_OUTPUT vs_main(VS_INPUT Input)
{
   VS_OUTPUT Output;
   Output.mPosition = mul(Input.mPosition, gWorldViewProjectionMatrix);
   float3 objectLightPosition = mul(gWorldLightPosition, gInvWorldMatrix);
   float3 lightDir = normalize(Output.mPosition - objectLightPosition);
   Output.mDiffuse = dot(normalize(Input.mNormal), -lightDir);
   return Output;
}

정점의 위치를 투영공간으로 한번에 변환하였다.

 

빛의 위치를 역행렬을 이용해 지역공간으로 변환하였다.

lightDir 방향벡터를 만든다.

 

픽셀셰이더

float3 gSurfaceColor;

struct PS_INPUT
{
   float3 mDiffuse : TEXCOORD1;
};

float4 ps_main(PS_INPUT Input) : COLOR
{
   float3 diffuse = saturate(Input.mDiffuse);
   diffuse = ceil(diffuse * 5.0) / 5.0;
   return float4(gSurfaceColor * diffuse, 1.0);
}

// 난반사광에서 0이하의 값을 잘라내기

필요없는 수들이다.

 

// 단계적 명암 표현 (ceil함수)

0.2 단위로 자른다.

ceil함수를 이용한다.

정수로만 올림한다.

따라서 곱셈 후 나눗셈을 이용한다.

 

0~1의 값을 0~5의 범위로 바꾸고, ceil을 적용한다.

0, 1, 2, 3, 4, 5 값이 된다.

 

이를 다시 5로 나눈다.

0, 0.2, 0.4, 0.6, 0.8, 1.0 값 중에 하나가 된다.

댓글