본문 바로가기
유니티/Shader Study

URP Shader Study #12 - 카메라 벡터를 활용한 rim light의 적용

by witn331ss 2023. 12. 13.
Shader "URPTraining/RimLight_Shader"
{


   Properties
             {
            _RimPower("_RimPower", Range(0.01, 0.1)) = 0.1
            _RimInten("_RimInten", Range(0.01, 100)) = 1
            [HDR]_RimColor("RimColor", color) = (1,1,1,1)
            _AmbientColor("AmbientColor", color) = (1,1,1,1)


            
           	}  

	SubShader
	{  

	Tags
            {
	   "RenderPipeline"="UniversalPipeline"
                "RenderType"="Opaque"          
                "Queue"="Geometry"
            }
    	Pass
    	{  		
     	 Name "Universal Forward"
              Tags { "LightMode" = "UniversalForward" }

       	HLSLPROGRAM

        	#pragma prefer_hlslcc gles
        	#pragma exclude_renderers d3d11_9x
        	#pragma vertex vert
        	#pragma fragment frag

       	#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"        	
  
         	struct VertexInput
         	{
            	float4 vertex : POSITION;
                float3 normal : NORMAL;
          	};

        	struct VertexOutput
          	{
           	float4 vertex  	: SV_POSITION;
            float3 normal : NORMAL;
            float3 WorldSpaceViewDirection : TEXCOORD0;
            /*
            뷰 벡터를 직접 구하기 위해 지정한다.
            */
      	    };

            float _RimPower, _RimInten;
            half4 _RimColor, _AmbientColor;

      	VertexOutput vert(VertexInput v)
        	{

          	VertexOutput o;      
          	o.vertex = TransformObjectToHClip(v.vertex.xyz);
            o.normal = TransformObjectToWorldNormal(v.normal);

            o.WorldSpaceViewDirection = normalize(_WorldSpaceCameraPos.xyz - TransformObjectToWorld(v.vertex.xyz));
            /*
            이 코드는 물체의 표면이 카메라를 바라보는 방향을 계산하는 것을 목표로 한다

            전역 좌표계에 있는 카메라의 방향은 (WorldSpaceViewDirection) 이것을 대입한다 :
            정규화 된 카메라의 위치(CameraPos)에서 오브젝트의 월드 포지션을 뺀 값
            카메라 포지션에서 월드 포지션을 뺀다면 카메라 위치에서 물체의 버텍스까지의 방향 백터를 계산하는 것이다.

            그 다음에 그것을 카메라의 방향에 대입시켜서 결과적으로 카메라가 물체를 바라보게끔 하는 것이다.

            *정규화는 백터의 길이를 1으로 만드는 과정인데 이 과정을 거친다면 백터의 방향은 유지되면서 길이는 표준화 된다*
            *ViewDirection은 방향만 중요하지 길이는 중요하지 않아서 길이를 고려하지 않고 단순화 시킨 뒤
            방향 정보만을 사용하게끔 하는 것이 정규화를 쓰는 의미이다.
            *또한 조명과 반사는 방향에 따라 바뀔 수 있어서 정규화된 것을 사용하면 보다 정확한 효과를 얻을 수 있다*
            
            

            */
         	return o;
        	}

        	half4 frag(VertexOutput i) : SV_Target
        	{ 
            float3 light = _MainLightPosition.xyz;
            float4 color = float4(0.5,0.5,0.5,1);

            half3 ambient = SampleSH(i.normal);
            /*
            이 코드는 구면 조화 계산을 통해서 주변광을 계산한다는 뜻이다.

            SampleSH 함수는 구면 조화를 기반으로 하는 함수인데
            간단하게 환경전체(더 간단하게 큐브맵이나 HDRI?)를 수식으로 바꿔서 빛의 방향을 계산하는 방식이다.

            즉, 노멀이 가르키는 방향에서 오는 주변광의 양을 계산한다는 뜻이다.
            */

            half face = saturate(dot(i.WorldSpaceViewDirection, i.normal));
            /*
            월드 카메라와 노멀을 내적해서 방향의 대한 값을 구하는 것이다.
            기존 라이트 구하는 방식과 반대로 한 이유는 가장자리가 빛나게 하기 위해서.
            */

            half3 rim = 1.0 - (pow(face,_RimPower));
            /*
            이제 림이라는 함수를 만들어서 대입한다 :
            1에서 월드 카메라와 노멀을 내적한 값에 _RimPower 를 거듭제곱한 값을 뺀다.

            마치 fresnel 함수를 적용 한 것 처럼 _RimPower 값이 적을 수록 넓은 면적에 림라이트가 보일 것이고
            많을 수록 적은 면적에 보일 것이다. 이것을 준비하는 함수.
            */

            color.rgb *= saturate(dot(i.normal, light)) * _MainLightColor.rgb + ambient;
            // 라이트에 따라서 색이 변하게끔 만드는 함수 주변광은 덤이다.

            color.rgb += rim * _RimInten * _RimColor;
            // 계산한 림라이트를 _RimInten 에 따라서 움직이게 만든다. 그리고 색도 섞어야 하니 투입.
            //기존 라이트에 곱하는 것이 아닌 더하는 것이다 그 이유는 곱하면 덮어써지기 때문에.

            return color;
            /* 구면조화 함수를 그냥 솔리드로 바꾼다면 이걸 그냥 개별적으로 움직일 수 있게 할 수 있지 않을까
            half3 ambient = _AmbientColor; 이렇게 바꾸면 됨 헉 ㅋㅋ ㅅㅂ 내가 느낀바로는 SS를 이렇게 표현하면 될거 같은데 아닌가 티크니스가 훨씬가볍나?*/
            }

        	ENDHLSL  
    	}
     }
}