노멀, 표면이 바라보는 정방향
라이트가 때리는 방향과 받는 오브젝트의 노멀값을 계산을 해서
빛을 표현해주는 것
물체가 있으면 표면이 있고, 표면이 있으면 노멀 (방향이 존재)
노멀과 빛의 방향이 직각 서로 닿아 있지 않으면, 제일 어둡게 나온다.
조명의 백터
표면의 백터
서로 마주보고 잇으면 제일 밝다
90도 직각을 이루고 있으면 제일 어둡다.
색상에서는 float2(0.5, 0.5) 는 회색
UV에서는 위치 중간
즉, 숫자(수치) : 색상, 위치, 방향이 될 수 있다.
-----
정육면체에서는 꺽이는 부분은 90도가 될 수 있으므로
나중에 우리는 부분을 중간값을 넣을것이다 (보간 기법)
----
버텍스 또한 각자의 노멀을 가지고 있다 .
-----
노멀벡터 - 조명벡터 = 가장 밝은 쪽 표현하기 위해서
-----
환경광 같은 옵션은 넣기 빼기
#pragma surface surf (옵션 붙이기)
Unity - Manual: Writing Surface Shaders (unity3d.com)
----
라이팅 바꾸기
Shader "Custom/Test"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Test noambient
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
float4 LightingTest(SurfaceOutput s, float3 lightDir, float atten){
}
ENDCG
}
FallBack "Diffuse"
}
만들때 기본 구조
------
float4 LightingTest(SurfaceOutput s, float3 lightDir, float atten){
}
float3 lightDir 는 (조명백터는)
위에 구조체에서는
1. 조명 벡터가 뒤집혀서 들어온다.
2. 단위 벡터이다. (방향만 가지고있는 것 0,1 1,0 이런것들)
------
구조체를 넣어보자
컬러
색을 넣는것 float4(RGB.a)
닷(엔디비아 dot // 엔디비아 CG API 찾기) // float으로 반환
float 으로 받는다. ndotl // n + do + tl 라는 단어로 많이 받는다.
LightingTest 는 float4로 받지만, float1 도 가능하다.
dot (표면 벡터, 조명벡터);
라이트를 만든다.
----
좀비로 테스트 // 루트 본이 필요하니깐 본 빼고 다 지우고
머리만 프리팹해서 사용하기
좀비머리에 테스트 메터리얼 넣기
현재는 램버트 라이트로 만들었음, 앰비언트 라이트면 -1 이면 문제가 생김.
float ndotl = saturate (dot(s.Normal, lightDir) );
saturate 를 써준다.
0보다 낮은 값은 0으로 클리핑해준다.
max (0, ) 도 같은 기능을 한다.
0 밑의 값을 클리핑해준다.
dot product는 코사인은 1 부터 -1까지 반복인데
max 또는 saturate 를 ㅆ ㅓ주면 0밑에 부분의 그래프를 짤려준다.
0.5를 더해주면, 전체적으로 그래프을 올려주는것이다.
밝아짐
----
노멀맵을 넣어서 확인 할 수도 있다 .
Shader "Custom/Test"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Normal ("Normal)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Test
#pragma target 3.0
sampler2D _MainTex;
sampler2D _Normal;
struct Input
{
float2 uv_MainTex;
float2 uv_Normal;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
fixed3 n = UnpackNormal(tex2D (_Normal, IN.uv_Normal));
o.Normal = n;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
float4 LightingTest(SurfaceOutput s, float3 lightDir, float atten){
//return float4(1,0,0,1);
float ndotl = max (0, (dot(s.Normal, lightDir)));
return ndotl;
}
ENDCG
}
FallBack "Diffuse"
}
여기까지가 기본적인 램버트 조명을 만들것이다.
-----
이제 하프 램버트를 만들어 볼것이다 (조금 더 콘스트라스트가 약한 버전)
램버트는 코사인 그래프로 하기 때문에 어둡고 밝은 차이가 심하다
float ndotl = dot(s.Normal, lightDir) * 0.5 +0.5;
max나 세츄레이트는 램버트 공식, 하프 램버트는 그걸 안쓰고, *0.5 +0.5 ; 를 dot 프로덕트에서 공식을 더해주면 된다.
콘스트라스트가 많이 사라진걸 확인가능
---
램버트와 하프램버트 공식
----
하프램버트 완성하기
이제 atten 인 감쇠와 라이트를 적용 시켜보자
★다이렉트 라이트는 atten 표현 불가능 point나 Area 조명이 가능함
거리에 따라 어둡고 밝기를 주는 것
SurfaceOutput o 에서 우리는 알베도와 몇가지 넣은걸 그대로 쓸수 있다.
최종적으로 합쳐서 내보내야한다.
_LightColor0.rgb 는 쉐이더 API에 있는 것이다.
_LightColor0. //반드시 이API로 해야한다.
_LightColor0 : 조명의 색상이나 강도가 저장된 내장변수
Shader "Custom/Test"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Normal ("Normal)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Test
#pragma target 3.0
sampler2D _MainTex;
sampler2D _Normal;
struct Input
{
float2 uv_MainTex;
float2 uv_Normal;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
fixed3 n = UnpackNormal(tex2D (_Normal, IN.uv_Normal));
o.Normal = n;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
float4 LightingTest(SurfaceOutput s, float3 lightDir, float atten){
////램버트 공식
//float ndotl = max (0, (dot(s.Normal, lightDir)));
//하프램버트 공식
float ndotl = dot(s.Normal, lightDir) * 0.5 +0.5;
float4 final;
final.rgb = ndotl * s.Albedo * _LightColor0.rgb * atten;
final.a = s.Alpha;
return final;
}
ENDCG
}
FallBack "Diffuse"
}
최종적으로 합쳐서 내보낸다.
마지막으로 환경광을 지워주면 제대로 퓨어한 하프 램버트가 만들어진다.
Shader "Custom/Test"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Normal ("Normal)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Test noambient
#pragma target 3.0
sampler2D _MainTex;
sampler2D _Normal;
struct Input
{
float2 uv_MainTex;
float2 uv_Normal;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
fixed3 n = UnpackNormal(tex2D (_Normal, IN.uv_Normal));
o.Normal = n;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
float4 LightingTest(SurfaceOutput s, float3 lightDir, float atten){
////램버트 공식
//float ndotl = max (0, (dot(s.Normal, lightDir)));
//하프램버트 공식
float ndotl = dot(s.Normal, lightDir) * 0.5 +0.5;
float4 final;
final.rgb = ndotl * s.Albedo * _LightColor0.rgb * atten;
final.a = s.Alpha;
return final;
}
ENDCG
}
FallBack "Diffuse"
}
지금까지한것이 레거시 쉐이더와 범프드 쉐이더를 똑같이 구현 한 것이다.
------
정리
텍스쳐 한장을 받는 쉐이더 생성
라이트이름 설정 : Test
Lighting + Test 이름으로 함수 선언
반환 타입은 float4
매개변수 (SurfaceOutput s, float 3 lightDir(단위 백터, 연산 쉽게하기 위해서 뒤집힌 방향), float atten(빛의 감쇠))
램버트 공식 (dot) : 표면벡터와 조명벡터를 내적해준다.
추가로 - 값이 나오면 문제가 생겨서 saturate 함수나 max 함수로 -값 클리핑 해줌
그 값을 반환
하프 램버트 공식 : dot(표면벡터와 조명벡터를 내적) * 0.5 + 0.5 해줌
라이트 함수 내에서 SurfaceOutput 구조체 값 사용가능
예) s.Albedo 값을 사용할 수있다.
_LightColor0 : 조명의 색상, 강도가 저장된 내장변수
'Unity > 그래픽스프로그래밍' 카테고리의 다른 글
0506_ 홀로그램 만들기 (0) | 2021.05.06 |
---|---|
0506 _ RIM 라이트 표현하기 (0) | 2021.05.06 |
0504 _ 라이트에 따른 쉐이더 // 노멀 및 여러맵 넣었을 때 차이점 (0) | 2021.05.04 |
0504_ 버텍스컬러 찍은 부분만 텍스쳐링 나오게하기 (0) | 2021.05.04 |
0504 _ 특정 부분만 러프니스 또는 메탈릭 주기 (버텍스 컬러, 그레이 스케일) (0) | 2021.05.04 |