Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

게임 프로그래밍

[Unity-Shader] Blinn-Phong 본문

프로그래밍/유니티

[Unity-Shader] Blinn-Phong

Junwe 2020. 5. 1. 22:19

스펙큘러 표현 공식은 다양하지만 가장 유명하고 전통적인 방식은 Phong반사 입니다.

이 공식의 기본 원리는

"내가 보는 방향으로부터 반사된 방향에 조명이 있으면 그 부분의 하이라이트가 가장 높다" 입니다.

Blinn-Phong의 공식은

"시선 벡터와 조명 벡터의 중간값인 '하프 벡터'를 구하고, 이를 노멀 벡터와 내적한다."

그렇다하면 하프 벡터는 어떻게 구할 수 있을까요?

벡터의 특징중에 하나를 살펴보면 "길이가 같은 두 벡터를 더 하면, 두 벡터 사이의 절반인 각도가 나온다" 라는 특징이 있습니다.

이를 통해 하프 벡터는 "시선 벡터" 와 "조명 벡터" 를 더 하고 이를 normalize 해주면 됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Shader "Custom/CustomBlinnPhong"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _specCol("SpecColor",Color) = (1,1,1,1)
        _specPow("SpecPow",Range(10,100)) = 100
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
 
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Test
 
 
        sampler2D _MainTex;
        float _specPow;
        float4 _specCol;
 
        struct Input
        {
            float2 uv_MainTex;
        };
 
        void surf (Input IN, inout SurfaceOutput o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
 
        float4 LightingTest(SurfaceOutput s, float3 lightDir,float3 viewDir, float3 atten)
        {
            float3 DiffColor;
            float ndotl = saturate(dot(s.Normal,lightDir));
            float4 final;
 
            float3 SpecColor;
            float3 H = normalize(lightDir+viewDir);
            float spec = saturate(dot(H,s.Normal));
            spec = pow(spec,_specPow);
            SpecColor = spec * _specCol.rgb;
 
            DiffColor = ndotl * s.Albedo * _LightColor0.rgb * atten;
            final.rgb = DiffColor + SpecColor.rgb;
            final.a = s.Alpha;
 
            return final;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
 
cs

전체 소스입니다. 기본 Lamvert 라이트에 Spec을 추가한 연산입니다.

 

1
2
3
4
5
float3 SpecColor;
float3 H = normalize(lightDir+viewDir);
float spec = saturate(dot(H,s.Normal));
spec = pow(spec,_specPow);
SpecColor = spec * _specCol.rgb;
cs

LightingTest에 이 부분을 보시면, H라는 얘는 normalize(lightDir+viewDir) 로 되어 있습니다. 

이는 normalize(시선벡터+조명벡터)로 위에 언급했던 "하프 벡터"를 만드는 공식입니다.

이렇게 만든 하프 벡터를 saturate(dot(H,s.Normal)) -> 노멀 벡터와 내적을 합니다.

그 후, pow 함수를 이용해 스펙큘러의 넓이를 지정해주었습니다.

마지막으로 스펙큘러의 컬러 값을 곱합니다.

 

이러한 형태가 나오게 될 것입니다.

 

Comments