본문 바로가기
ComputerGraphics/HLSL

쉐이더프로그래밍 / 디퓨즈 스페큘러 맵핑

by lucidmaj7 2020. 6. 24.
728x90
반응형

이번에 공부한 내용은 디퓨즈 맵과 스페큘러 맵을 이용하여 물체 표면의 특성에 따라 반사량이 달라지는 스페큘러 맵핑입니다.

예를 들어 디퓨즈 스페큘러맵핑을 이용하면 얼굴을 렌더링 한다고 할때 이마나 코는 기름기 때문에 좀 더 반짝거리며 다른 부분은 덜 반짝 거리는 것을 표현할 수 있습니다.

이러한 정반사량과 난반사량을 부분에 따라서 조절하기 위해 스패큘러맵 텍스처와 디퓨즈맵 텍스처를 사용한다고 합니다. 즉 텍스처가 두개가 필요합니다.

쉐이더프로그래밍입문

구현에 필요한 텍스처 리소스는 아래 git레포지토리에서 구 할 수 있습니다.

https://github.com/popekim/ShaderPrimerKR/tree/master/05_DiffuseSpecularMapping

 

popekim/ShaderPrimerKR

Source Code for the Korean version of Shader Programming Primer Book. - popekim/ShaderPrimerKR

github.com

정점 쉐이더

정점쉐이더는 지난번 난반사, 정반사 쉐이더와 크게 다를게 없습니다.

float4x4 gWorldMatrix;
float4x4 gViewMatrix;
float4x4 gProjectionMatrix;


float4 gWorldLightPosition;
float4 gWorldCameraPosition;


struct VS_INPUT
{
   float4 mPosition : POSITION;
   float3 mNormal: NORMAL;
   float2 mUV : TEXCOORD0; //텍스쳐 좌표 
};


struct VS_OUTPUT
{
   float4 mPosition : POSITION;
   float3 mDiffuse : TEXCOORD1;
   float3 mViewDir: TEXCOORD2;
   float3 mReflection: TEXCOORD3;
   float2 mUV : TEXCOORD0; // 텍스처 좌표 
};


VS_OUTPUT vs_main( VS_INPUT Input )
{
   VS_OUTPUT Output;


   Output.mPosition = mul( Input.mPosition, gWorldMatrix );


   float3 lightDir = Output.mPosition.xyz - gWorldLightPosition.xyz;
   lightDir = normalize(lightDir);

   float3 viewDir = normalize(Output.mPosition.xyz - gWorldCameraPosition.xyz);
   Output.mViewDir = viewDir;

   Output.mPosition = mul( Output.mPosition, gViewMatrix );
   Output.mPosition = mul( Output.mPosition, gProjectionMatrix );

 


   float3 worldNormal = mul( Input.mNormal, (float3x3)gWorldMatrix );
   worldNormal = normalize(worldNormal);


   Output.mDiffuse = dot(-lightDir, worldNormal);
   Output.mReflection = reflect(lightDir, worldNormal);
   Output.mUV = Input.mUV;

   return Output;
}

 

픽셀 쉐이더

struct PS_INPUT
{
   float2 mUV: TEXCOORD0;
   float3 mDiffuse : TEXCOORD1;
   float3 mViewDir: TEXCOORD2;
   float3 mReflection: TEXCOORD3;
};

sampler2D DiffuseSampler; //디퓨즈 맵 텍스처 샘플러 
sampler2D SpecularSampler; // 스페큘러 맵 텍스처 샘플러 

float3 gLightColor; // 빛의 색깔



float4 ps_main(PS_INPUT Input) : COLOR
{
    float4 albedo = tex2D(DiffuseSampler, Input.mUV); //디퓨즈맵 값
   float3 diffuse = gLightColor * albedo.rgb *  saturate(Input.mDiffuse);
   //난반사광 = 빛의 색 * 디퓨즈맵 값 * 난반사량

   float3 reflection = normalize(Input.mReflection);
   float3 viewDir = normalize(Input.mViewDir);
   float3 specular = 0;
   if ( diffuse.x > 0 )
   {
      specular = saturate(dot(reflection, -viewDir ));
      specular = pow(specular, 50.0f); // 정반사 량 계산 
      float4 specularIntensity = tex2D(SpecularSampler, Input.mUV); //스페큘러 맵 값 가져오기 
      specular*= specularIntensity.rgb * gLightColor; // 정반사 = 정반사량* 빛의 색* 스패큘러맵 값 
      
   }


   float3 ambient = float3(0.1f, 0.1f, 0.1f) * albedo;

   return float4(ambient + diffuse + specular, 1);
}

픽셀 쉐이더에서는 디퓨즈맵과 스페큘러맵을 사용합니다. 픽셀쉐이더에서 최종 난반사량과 정반사량은 다음과 같이 구해집니다.

난반사광 = 빛의 색상 * 난반사광의 양 * 디퓨즈맵의 값
정반사광 = 빛의 색상 * 정반사광의 양 * 스페큘러맵의 값

 

결과

벽돌 사이사이에 스페큘러맵의 영향을 받아 반사량이 감소한 것을 볼 수 있습니다.

스페큘러맵핑.rfx
0.05MB

 

DirectX 11 구현

DirectX11 에서 구현하여 출력한 결과입니다.

https://github.com/lucidmaj7/directx11test/tree/SpecularMappingShader/MyShaderTest

 

lucidmaj7/directx11test

directx11test. Contribute to lucidmaj7/directx11test development by creating an account on GitHub.

github.com

 

728x90
반응형

댓글