이번에 만들어볼 것은 Hologram effect 입니다.
Hologram Effect는 두가지를 구현 해야 합니다.
1. Rim Light
2. Hologram Animation
Rim Lighting이란 피사체의 뒤에서 강한 빛을 쏘았을때, 피사체의 윤곽 부분이 rim(테두리)이 빛나는
것을 의미한다.
특히 반사재질이 아닌 물체들은 이 현상이 강하게 표현이 된다.
이러한 특징으로 게임 캐릭터가 선택되었을때의 effect로도 널리 사용이 됩니다.
Rim Lighitng은 프레넬 공식을 사용하여 구현할 수가 있습니다.
프레넬은 공식은 빛의방향과 보는 각도의 따라서 빛의 굴절과 반사율이 달라 진다는 것입니다.
물을 90도 위 에서 보면 Reflection이 덜 되어서 물안의 내용물이 보이지만,
0도에서 볼때는 Reflection이 많이 되어서 반사된 하늘을 볼수 있습니다.
Reflection이 많이 된 부분은 다른 부분보다 더 밝을 것입니다,
이런 현상을 blin-Phong 라이팅 모델에서 설명할 수 없기에 Rim lighiting을 적용합니다.
1. Rim Light 적용 해봅니다.
====================================================
Rim Lighting
// l : 버텍스에서 바라보는 조명의 방향
// v : 버텍스에서 바라보는 카메라의 방향
rim = 1 - dot(l, v)
스펙큘러 라이팅을 계산할때, n dot L 을 많이 사용합니다.
노멀과 조명의 벡터가 수직일때, 가장 빛나는 것처럼,
조명과 카메라를 내적하면,
카메라가 바라보는 부분이 1과 가까울 것이며, 멀어질수록 0에 가까울 것 입니다.
1을 빼주게 되면,
카메라가 바라보는 부분이 0과 가까울 것이며, 멀어질수록 1에 가깝게 됩니다.
즉 모델의 외곽부분이 더 밝게 되는 것이지요
여기서 렌더링을 해보면 꽤나 넓은 부분이 1에 해당합니다.
saturate 함수는 0 ~ 1 사이 값으로 고정시켜줍니다.
밝은 부분을 줄이기 위하여 Pow 함수를 사용하여 지수승을 해줍니다.
스펙큘러를 구할때도 반사되어 빛나는 부분의 영역을 좁게 하기 위하여 pow를 사용 합니다.
l, v는 단위 벡터이기 때문에 내적을 하게되면 결국 cos세타 값으로 0 ~ 1 의 값이 되어,
x값이 증가 함에 따라 y 값이 아주 천천히 올라가다가
x값이 1에 가까워 질때 y 값이 급격하게 1에 가까워 집니다.
정리하면, 카메라와 거리가 제일 먼 부분에 가장 밝게 빛나게 되는 것입니다.
2. 홀로그램 애니메이션을 적용 해보겠습니다.
====================================================
아래에서 위로 올라가는 영역을 먼저 구하고, 그 영역을 이동시키면 될 것 같습니다.
영역에 해당하는 position을 얻어야 합니다,.
Surface Shader surf 함수에서 첫번째 파라메터인 Input IN 내부에서 월드 좌표를 얻을 수 있습니다.
아래에서 위로가는 animation 이기에 world 좌표에서 y값만 가져 옵니다.
셰이더에서 일정한 반복되는 구간을 구하기 위해 frac 함수를 사용을 많이 합니다.
좌표에 frac 함수를 적용을 합니다.
frac 내부에 값을 더해 보면 아래처럼 영역이 내려가는 것을 볼 수 있습니다.
여기에 _Time.y 값을 빼주면 영역이 아래에서 위로 올라가는 Animation이 완성 될 것입니다.
그런데 영역이 2개 밖에 없습니다. ( 상체, 하체 )
영역을 늘리기 위해서는 y값을 크게 해주면 됩니다.
예를들어) y 값에 2를 곱하면
1.0 ~ 1.4 영역이 본래 0.5 ~ 0.7 영역이기 때문에, 영역이 2배 많아집니다.
영역을 10개로 늘려봅시다.
영역의 컬러값이 너무 일정합니다.
영역의 컬러 값 그라데이션 효과를 주기 위해서는 rim light에서 적용했던 것처럼
Pow 함수를 통하여 영역을 좁게 만들어 봅니다.
이제 y 이동 애니메이션을 위해 y 값에 _Time.y를 빼줍니다.
마지막에 상수 값을 곱하면 색상이 좀 더 밝아지면서 그럴듯한 홀로그램이 완성됩니다.
림라이트에서 적용한 color과 더해서
최종 홀로그램을 완성 합니다.
Shader "Custom/HoloGram"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_BumpMap("BumpMap", 2D) = "white" {}
_RimPower("RimPower", Range(0, 10)) = 3
_RimColor("RimColor", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue" = "Transparent" }
CGPROGRAM
#pragma surface surf Lambert noambient alpha:fade
#pragma target 3.0
sampler2D _MainTex;
sampler2D _BumpMap;
float _RimPower;
fixed4 _RimColor;
struct Input
{
float2 uv_MainTex;
float2 uv_BumpMap;
float3 viewDir;
float3 worldPos;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
fixed3 n = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
o.Normal = n;
float rim = saturate(dot(o.Normal, IN.viewDir));
rim = pow(1 - rim, 3);
rim = rim + pow(frac(IN.worldPos.y * 3 - _Time.y), 10) * 1.5;
o.Emission = _RimColor;
o.Alpha = rim;
}
ENDCG
}
FallBack "Diffuse"
}
'Unity - Surface Shader' 카테고리의 다른 글
5. 알파블렌딩과 컷아웃 (3) | 2023.11.20 |
---|---|
4. Cubemap을 사용하여 반사매질을 표현해보자. (0) | 2023.11.19 |
3. Vertex Shader를 사용하여 Toon Shading 해보기 (0) | 2023.11.14 |
2. Blin - phong Specular + Rim Lighiting (0) | 2023.11.11 |
시작하면서... (0) | 2023.11.10 |