셰이더 입문1

 

Per Vertex Lighting, No Specular Reflection - simpleLighting1.rfx
struct VS_INPUT
{
   float4 pos : POSITION;
   float3 normal : NORMAL;
};


struct VS_OUTPUT
{
   float4 pos : POSITION;
   float3 diffuse : TEXCOORD1;
};

float4x4 gWorldMat;
float4x4 gViewMat;
float4x4 gProjMat;

float4 gWorldLightPos;

VS_OUTPUT vs_main( VS_INPUT input)
{
   VS_OUTPUT output;
   
   output.pos = mul(input.pos, gWorldMat);
   
   float3 lightDir = output.pos.xyz - gWorldLightPos.xyz;
   lightDir = normalize( lightDir);
   
   output.pos = mul( output.pos, gViewMat);
   output.pos = mul( output.pos, gProjMat);
   
   float3 worldNormal = mul( input.normal, (float3x3)gWorldMat);
   worldNormal = normalize( worldNormal);
   
   output.diffuse = dot( -lightDir, worldNormal);
   
   return output;
}

//------------------------------------------------------------

struct PS_INPUT
{
   float3 diffuse : TEXCOORD1;
};


float4 ps_main( PS_INPUT input) : COLOR
{
   float3 diffuse = saturate( input.diffuse);
   return float4( diffuse, 1);   
}

다운로드 : simpleLighting1.rfx

Per Vertex Lighting, Specular Reflection
float4x4 gWorldMat;
float4x4 gViewMat;
float4x4 gProjMat;

float4 gLightPos;
float4 gViewPos;

struct VS_INPUT
{
   float4 pos : POSITION;
   float3 normal : NORMAL;
};

struct VS_OUTPUT
{
   float4 pos : POSITION;
   float3 diffuse : TEXCOORD1;
   float3 reflection : TEXCOORD2;
   float3 viewDir : TEXCOORD3;
};

VS_OUTPUT vs_main( VS_INPUT input )
{
   VS_OUTPUT output;

   output.pos = mul( input.pos, gWorldMat);
   
   float3 lightDir = output.pos.xyz - gLightPos.xyz;
   lightDir = normalize( lightDir);
   
   float3 viewDir = output.pos.xyz - gViewPos.xyz;
   output.viewDir = normalize( viewDir);
   
   output.pos = mul( output.pos, gViewMat);
   output.pos = mul( output.pos, gProjMat);
   
   float3 worldNormal = mul( input.normal, gWorldMat);
   worldNormal = normalize( worldNormal);
   output.diffuse = dot( -lightDir, worldNormal);
   
   output.reflection = reflect( lightDir, worldNormal);
   
   return( output );
   
}

//------------------------------------------------------------

struct PS_INPUT
{
   float3 diffuse : TEXCOORD1;
   float3 reflection : TEXCOORD2;
   float3 viewDir : TEXCOORD3;
};

float4 ps_main( PS_INPUT input) : COLOR
{   
   float3 diffuse = saturate( input.diffuse);
   
   float3 specular = 0;
   
   if( diffuse.x > 0)
   {
      float3 reflection = normalize( input.reflection);
      float3 viewDir = normalize( input.viewDir);
      
      specular = dot( reflection, -viewDir);
      specular = saturate( specular);
      
      specular = pow( specular, 20);
   }
   
   float3 ambient = float3( 0.1f, 0.1f, 0.1f);
   
   return( float4( ambient + specular + diffuse, 1.0f) );
}

다운로드 : Lighting.rfx

디퓨즈 맵과 스펙큘러 맵을 추가한다. 텍스쳐 추가시 빛의 양을 구하는 방법이다.

  • 난반사광 = 빛의 색상 X 디퓨즈맵의 값 X 난반사광의 양
  • 정반사광 = 빛의 색상 X 스펙큘러맵의 값 X 정반사광의 양
Specular Mapping
float4x4 gWorldMat;
float4x4 gViewMat;
float4x4 gProjMat;

float4 gLightPos;
float4 gViewPos;

struct VS_INPUT
{
   float4 pos : POSITION;
   float3 normal : NORMAL;
   float2 uv : TEXCOORD0;
};

struct VS_OUTPUT
{
   float4 pos : POSITION;
   float2 uv : TEXCOORD0;
   float3 diffuse : TEXCOORD1;
   float3 reflection : TEXCOORD2;
   float3 viewDir : TEXCOORD3;
};

VS_OUTPUT vs_main( VS_INPUT input )
{
   VS_OUTPUT output;

   output.pos = mul( input.pos, gWorldMat);
   
   float3 lightDir = output.pos.xyz - gLightPos.xyz;
   lightDir = normalize( lightDir);
   
   float3 viewDir = output.pos.xyz - gViewPos.xyz;
   output.viewDir = normalize( viewDir);
   
   output.pos = mul( output.pos, gViewMat);
   output.pos = mul( output.pos, gProjMat);
   
   float3 worldNormal = mul( input.normal, gWorldMat);
   worldNormal = normalize( worldNormal);
   output.diffuse = dot( -lightDir, worldNormal);
   
   output.reflection = reflect( lightDir, worldNormal);
   
   output.uv = input.uv;
   
   return( output );
   
}

//------------------------------------------------------------

sampler2D DiffuseSampler;
sampler2D SpecularSampler;

float3 gLightColor;

struct PS_INPUT
{
   float2 uv : TEXCOORD0;
   float3 diffuse : TEXCOORD1;
   float3 reflection : TEXCOORD2;
   float3 viewDir : TEXCOORD3;
};

float4 ps_main( PS_INPUT input) : COLOR
{  
   float4 albedo = tex2D(DiffuseSampler, input.uv);
   float3 diffuse = gLightColor * albedo.rgb * saturate( input.diffuse);
      
   float3 specular = 0;
   
   if( diffuse.x > 0)
   {
      float3 reflection = normalize( input.reflection);
      float3 viewDir = normalize( input.viewDir);
      
      specular = dot( reflection, -viewDir);
      specular = saturate( specular);
      
      specular = pow( specular, 20);
      
      float4 specularIntensity = tex2D(SpecularSampler, input.uv);
      specular = gLightColor * specularIntensity.rgb * specular;
   }
   
   float3 ambient = float3( 0.1f, 0.1f, 0.1f) * albedo;
   
   return( float4( ambient + specular + diffuse, 1.0f) );
}

다운로드 : SpecularMapping.rfx

SpecularMappling.rfx 행렬을 아래와 같이 수정해보자.

월드 행렬, 뷰 행렬, 프로젝션 행렬을 한번에 계산하기 위해 gWorldViewProjMat 행렬을 이용하자.
정점 셰이더 계산시 lightDir, ViewDir을 계산하기 위해 월드 gWorldMat는 그대로 둔다.

다운로드 : SpecularMapping2.rfx

simpleLighting2.rfx 셰이더 코드에서 월드 행렬, 뷰 행렬, 프로젝션 행렬을 미리 계산해서 하나의 행렬만 전달해 보자.
gWorldViewProjMat 행렬을 통해서 공간 행렬을 전달 해준다.

월드공간을 오브젝트 공간으로 변환 할려면 월드 행렬의 역행렬을 곱하면 된다.

float3 objectLightPos = mul( gWorldLightPos, gInvWorldMat)

simpleLight2.rfx
struct VS_INPUT
{
   float4 pos : POSITION;
   float3 normal : NORMAL;
};

float4x4 gWorldViewProjMat;
float4x4 gInvWorldMat;

float4 gWorldLightPos;


struct VS_OUTPUT
{
   float4 pos : POSITION;
   float3 diffuse : TEXCOORD1;
};

VS_OUTPUT vs_main( VS_INPUT input )
{
   VS_OUTPUT output;

   output.pos = mul( input.pos, gWorldViewProjMat);
   
   float3 objectLightPos = mul( gWorldLightPos, gInvWorldMat);
   float3 lightDir = normalize(input.pos.xyz - objectLightPos);
   
   output.diffuse = dot( -lightDir, input.normal);
   
   return( output );
}

//------------------------------------------------------------

struct PS_INPUT
{
   float3 diffuse : TEXCOORD1;
};

float4 ps_main( PS_INPUT input) : COLOR
{   
   float3 diffuse = saturate( input.diffuse);
      
   return float4( diffuse, 1.0f);
}

다운로드 : simpleLighting2.rfx