디퓨즈/스페큘러 매핑

    일반적으로 물체는 특정 한가지 색만 존재하는것이 아니다.

    그렇다면 3D상에서 여러 색을 표현하려면 어떻게 해야할까?

     

    이때 사용하는 것이 난반사광에 적용하는 텍스처, 바로 디퓨즈맵diffuse map이다.

    정반사광 또한 마찬가지로 스페큘러맵specular map을 사용하여 원하는 부분에 원하는 값으로 표현이 가능하다.

     

    쉽게말해

    난반사광 = 빛의 색상 X 난반사광의 양 X 디퓨즈맵의 값

    정반사광 = 빛의 색상 X 정반사광의 양 X 스페큘러맵의 값

     

    렌더몽키에서 셰이더 코드를 작성하기 전 필요한 사전 작업이 있다.

    DiffuseMap과 SpecularMap으로 사용할 이미지를 Workspace에 포함시켜준 뒤 Pass0에 연결시켜준다.
    텍스처의 UV좌표 또한 읽어와야 하므로 float2 TEXCOORD 채널도 포함시켜준다.

     

    정점셰이더 Vertex Shader

    float4x4 gWorldMatrix;
    float4x4 gViewMatrix;
    float4x4 gProjectionMatrix;
    
    float4 gWorldLightPosition;
    float4 gWorldCameraPosition;
    
    struct VS_INPUT 
    {
       float4 Position : POSITION0;
       float3 Normal : NORMAL;
       
       // 픽셀셰이더에서 텍스처매핑을 하기위해 정점버퍼에서 UV좌표를 가져온다.
       float2 UV : TEXCOORD0;
    };
    
    struct VS_OUTPUT 
    {
       float4 Position : POSITION0;
       float2 UV : TEXCOORD0;
       float3 Diffuse : TEXCOORD1;
       float3 ViewDir : TEXCOORD2;
       float3 Reflection : TEXCOORD3;
    };
    
    VS_OUTPUT vs_main( VS_INPUT Input )
    {
       VS_OUTPUT Output;
    
       Output.Position = mul( Input.Position, gWorldMatrix );
       
       float3 lightDir = Output.Position.xyz - gWorldLightPosition.xyz;
       lightDir = normalize(lightDir);
       
       float3 viewDir = normalize( Output.Position.xyz - gWorldCameraPosition.xyz );
       Output.ViewDir = viewDir;
       
       Output.Position = mul( Output.Position, gViewMatrix );
       Output.Position = mul( Output.Position, gProjectionMatrix);
       
       float3 worldNormal = mul( Input.Normal, (float3x3)gWorldMatrix );
       worldNormal = normalize(worldNormal);
       
       Output.Diffuse = dot(-lightDir, worldNormal);
       Output.Reflection = reflect(lightDir, worldNormal);
       
       // 정점셰이더 함수에 UV좌표를 전달해준다.
       Output.UV = Input.UV;
       
       return( Output );
    }

     

    픽셀셰이더 Pixel Shader

    float gPowValue;
    
    // 추가한 전역 변수들을 선언한다.
    sampler2D DiffuseSampler;
    sampler2D SpecularSampler;
    float3 gLightColor;
    
    struct PS_INPUT
    {
       // UV 좌표를 추가한다.
       float2 UV : TEXCOORD0;
       float3 Diffuse : TEXCOORD1;
       float3 ViewDir : TEXCOORD2;
       float3 Reflection : TEXCOORD3;
    };
    
    float4 ps_main(PS_INPUT Input) : COLOR0
    {  
       // 디퓨즈맵을 샘플링한다.
       // 샘플링 : 어떤 자료에서 일부 값을 추출하는 것을 의미힌다.
       float4 albedo = tex2D(DiffuseSampler, Input.UV);
       
       // 픽셀이 반사하는 색깔에는
       // 빛의 색상과 난반사광의 양을 곱해준다.
       float3 diffuse = gLightColor * albedo.rgb * saturate(Input.Diffuse);
       
       float3 reflection = normalize(Input.Reflection);
       float3 viewDir = normalize(Input.ViewDir);
       float3 specular = 0;
       
       if(diffuse.x>0)
       {
          specular = saturate(dot(reflection, -viewDir));
          specular = pow(specular, gPowValue);
          
          // 스페큘러맵을 샘플링하고
          float4 specularIntensity = tex2D(SpecularSampler, Input.UV);
          
          // 이것과 빛의 색상을 specular에 곱한다.
          specular *= specularIntensity.rgb * gLightColor;
       }
       
       // 난반사광이 사라지는 순간부터 디퓨즈 텍스처의 디테일도 같이 사라지기때문에
       // 임의로 정한 주변광에 디퓨즈맵을 곱해준다
       float3 ambient = float3(0.1f, 0.1f, 0.1f) * albedo;
       
       return float4(ambient + diffuse + specular, 1.0f);
    }

     

    DiffuseMap과 SpecularMap이 적용된 모습
    SpecularMap을 적용하지 않았을시 다소 강한 정반사광도 확인할 수 있다.

    스페큘러맵을 통해 텍스처는 색상 정보만을 저장하는 것이 아님을 확인할 수 있다.

     

    출처 : 셰이더 프로그래밍 입문

    'Shader & 포스트 프로세싱' 카테고리의 다른 글

    Half Lambert  (0) 2022.03.08
    툰셰이더(1)  (0) 2022.02.24
    기초적인 조명셰이더(2)_정반사광specular light  (0) 2022.02.23
    기초적인 조명셰이더(1)_난반사광diffuse light  (0) 2022.02.22
    텍스처매핑  (0) 2022.02.15

    댓글