Unity/그래픽스프로그래밍

0506_ Lambert에서 BlinnPhong 스펙큘러 만들기

minquu 2021. 5. 6. 18:12
반응형

이미지 한 장을 받는 것을 만들어준다.

 

 

----

블린퐁 조명을 만들기 위해서는 공식이 존재한다.

 

 

반사 벡터를 구하는 공식 (리플렉션 구하는 공식)

 

R = 2 N(L * N) -  L 이 공식이다.

 

이건 반사 벡터 구하는거고

 

우리는 좀더 간략하게 된, 블린 퐁 공식을 사용할 것이다.

 

하프 백터 = V +  I

 

하프 벡터를 노멀라이즈를 해준다. (방향만)

 

 

구한 하프벡터에서 n 벡터와 Dot 연산을 해준다.

 

 

------

 

일단 완전 기본적인 램버트의 라이트를 만들어준다.

 

커스텀 라이트로 

 

Shader "Custom/Phong"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Normal ("Normal", 2D) = "Normal" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf _MyLambert

        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Normal;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_Normal;
            float3 viewDir;
        };



        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 Lighting_MyLambert(SurfaceOutput s, float3 lightDir, float atten){
            float ndotl = dot(s.Normal,lightDir);
            float4 final;
            final.rgb = s.Albedo * ndotl;
            final.a = s.Alpha;
            return final;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

 

-----

 

 

하프 백터 구해보기 -> dot 연산으로 스펙큘러 적용하기

Shader "Custom/Phong"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Normal ("Normal", 2D) = "Normal" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf _MyLambert

        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Normal;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_Normal;
            float3 viewDir;
        };
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 Lighting_MyLambert(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten){
            float ndotl = dot(s.Normal,lightDir);
            float4 final;

            float3 H = normalize(lightDir + viewDir);
            float spec = saturate(dot(H,s.Normal));
            return spec;
            //final.rgb = s.Albedo * ndotl;
            //final.a = s.Alpha;
            //return final;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

  float4 Lighting_MyLambert(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten){

 float3 로 라이트 디렉션, 뷰 디렉션을 받아줘야한다.

 

float3 H = normalize(lightDir + viewDir);

 

퐁 구하는 공식으로 대입해준다.

 

            float spec = saturate(dot(H,s.Normal));
            return spec;

 

구한 H 값을 dot 연산을 해줘야지 spec이 나온다.

 

 

 

-----

final에 알베도도 섞어서 내 보내기

 

hader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Normal ("Normal", 2D) = "white" {}

    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Test noambient
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Normal;
        struct Input
        {
            float2 uv_MainTex;
            float2 uv_Normal;
            float3 viewDir;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Normal = UnpackNormal(tex2D(_Normal,IN.uv_Normal));
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        float4 LightingTest(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten){
            float4 final;
            float3 H = normalize(lightDir + viewDir);
            float spec = saturate(dot(H, s.Normal));
            final.rgb = s.Albedo * spec ;
            final.a = s.Alpha;
            return final;
        }

        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

---

 

pow 식으로 스펙큘러 정도 조절하기

 

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Normal ("Normal", 2D) = "white" {}
        _SpecPow("SpecPow", Range(0,100)) = 0 
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Test
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Normal;
        float _SpecPow;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_Normal;
            float3 viewDir;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {

            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 LightingTest(SurfaceOutput s, float3 lighDir, float3 viewDir ,float atten){
            float4 final;
            float3 H = normalize(lighDir + viewDir);
            float spec = saturate(dot(H,s.Normal));
            spec = pow(spec, _SpecPow);
            final.rgb = s.Albedo * spec;
            final.a = s.Alpha;
            return final;
        }

        ENDCG
    }
    FallBack "Diffuse"
}

 

 

-----

스펙큘러에 색깔 넣어보기

 

 

 

 

-----

 

 

알베도 색 넣기

 

  float4 LightingTest(SurfaceOutput s, float3 lighDir, float3 viewDir ,float atten){
            float4 final;

            //램버트 공식
            float ndotl = saturate(dot(s.Normal, lighDir));

            //스펙큘러 공식 적용
            float3 H = normalize(lighDir + viewDir);
            float spec = saturate(dot(H,s.Normal));
            spec = pow(spec, _SpecPow);

            //스팩큘러 색깔 적용
            float3 SpecColor = spec * _SpecCol.rgb;

            //알베도 적용
            final.rgb = (ndotl * s.Albedo) + SpecColor.rgb;
            final.a = s.Alpha;

            return final;
        }

 

 

 

( 램버트 공식(기본 조명) * 알베도 ) + 스펙큘러 컬러 를 해줘야한다.

 

 내 코드

 

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Normal ("Normal", 2D) = "white" {}
        _SpecPow("SpecPow", Range(0,100)) = 0 
        _SpecCol("SpecColor", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Test
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Normal;
        float _SpecPow;
        float4 _SpecCol;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_Normal;
            float3 viewDir;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {

            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 LightingTest(SurfaceOutput s, float3 lighDir, float3 viewDir ,float atten){
            float4 final;

            //램버트 공식
            float ndotl = saturate(dot(s.Normal, lighDir));

            //스펙큘러 공식 적용
            float3 H = normalize(lighDir + viewDir);
            float spec = saturate(dot(H,s.Normal));
            spec = pow(spec, _SpecPow);

            //스팩큘러 색깔 적용
            float3 SpecColor = spec * _SpecCol.rgb;

            //알베도 적용
            final.rgb = (ndotl * s.Albedo) + SpecColor.rgb;
            final.a = s.Alpha;

            return final;
        }

        ENDCG
    }
    FallBack "Diffuse"
}

 

선생님 코드

 

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _BumpMap ("NormalMap", 2D) = "bump" {}
        _SpecPow ("Specular Power", Float) = 50.0
        _SpecCol ("specular Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf _Test noambient

        sampler2D _MainTex;
        sampler2D _BumpMap;
        float _SpecPow;
        float4 _SpecCol;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_BumpMap;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));

            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 Lighting_Test (SurfaceOutput s, float3 lightDir, float viewDir, float atten){

            //램버트 공식 
            float ndotl = dot(s.Normal, lightDir);

            //스패큘러 공식 적용 
            float3 H = normalize(lightDir + viewDir);
            float spec = dot(H, s.Normal);
            spec = pow(spec, _SpecPow);

            //스패큘러 색상 적용 , _SpecColor 내장 변수 
            float3 specColor;
            specColor = spec * _SpecCol.rgb;

            //알베도 적용 
            float4 final;
            final.rgb = (ndotl * s.Albedo) + specColor.rgb;
            final.a = s.Alpha;

            return final;
        }

        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

---

순서

 

텍스쳐 한장을 받는 쉐이더 작성

범프 넣기

커스텀 램버트 라이트만들기

스펙큘러 적용

스펙큘러 컬러 적용

알베도 적용

 

 

여기까지한 과정은 직접 수동으로 블린퐁(+스펙큘러)을 만들어 준 것이다.

반응형