텍스쳐 한 장을 받는 쉐이더 스크립터를 만들어준다.
램버트 라이팅 세팅으로
Shader "Custom/Test"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
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;
}
ENDCG
}
FallBack "Diffuse"
}
----
큐브맵을 받을수 있는 프로퍼티를 뚫는다 .
큐브맵을 받는 형식은 Cube로
윈도우 - 렌더링 - 라이팅 세팅에 넣어야한다.
먼저
메터리얼에 큐브맵을 넣어준다.
메터리얼을 스카이박스메터리얼에 넣어준다.
★ 책에서 나온게 버전업 되면서 바뀌었다.
우리가 만든 메테리얼을 넣는게 아니라 검색해서 넣어야한다.
우리가 만든 메테리얼은 로봇에다가 넣을 것 이기 때문에
로봇 켈리 넣고,
메터리얼 넣고
sky박스가 반사되도록 만들것이다.
Input 에
월드 리플렉션이 있음 이걸 사용
이걸 똑같이 안쓰면 하드한 리플렉션 공식을 넣어야함
texCUBE (엔디비아 CG 용어)를 사용해서 이미지를 넣어야한다.
texCUBE(큐브텍스트 이미지 , 월드 리플렉션) = float4 로 반한
이미지션에 넣어서 테스트 하기
Shader "Custom/Test"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Cube ("CubeMap", Cube) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
samplerCUBE _Cube;
struct Input
{
float2 uv_MainTex;
float3 worldRefl;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
float4 ref = texCUBE(_Cube, IN.worldRefl);
o.Albedo = c.rgb;
o.Emission = ref.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
반사되는걸 확인 가능
이미션에 넣는 이유, 밝고 어두움을 반사하는데 빛을 넣는다고 밝아 지는게 아니기 때문에 (거울 예제)
지금은 흰색인 이유는 알베도에 흰색에 있고, 이미션에도 있어서 1이 넘어서 그럼
// 알베도랑 이미션을 같이 쓰면 밝아진다.
그래서 알베도를 0으로 만들고, 이미션에 반사된 값을 출력해보자
---
노멀을 넣으면 오류가 생긴다 .
이터널 데이터를 써줘야한다
이터널 데이터를 써주지 않으면
★ 월드 리플렉션이랑 월드 노멀을 같이 쓸수가 없다.
인풋에 넣어주고
노멀을 넣으면 월드 노멀을 넣ㅇ어줘야한다
노멀에 해당하는 반사벡터를 얻을려면 WorldReflctionVector 써줘야함
노멀을 먼저 쓰고 그걸 받아서 써주는 것이다 !
----
Shader "Custom/Test"
{
Properties
{
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Normal ("Normal (RGB)", 2D) = "white" {}
_Cube ("CubeMap", Cube) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
samplerCUBE _Cube;
sampler2D _Normal;
struct Input
{
float2 uv_MainTex;
float3 worldRefl;
float2 uv_Normal;
INTERNAL_DATA
};
void surf (Input IN, inout SurfaceOutput o)
{
o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
float4 ref = texCUBE(_Cube, WorldReflectionVector(IN, o.Normal));
o.Albedo = 0;
o.Emission = ref.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
----
총 과정
메터리얼 하나 받는 쉐이더 작성
기본 Lambert 라이트 모델 적용
큐브맵을 받게 프로퍼티 작성
타입을 Cube
변수선언시 타입을 samplerCUBE로
Input 구조체에 worldRefl 정의
texCUBE 함수를 사용해 큐브맵 적용 (_Cube, IN.worldRefl)
결과값이 re 값을 확인(Emission에서)
범프 텍스쳐 넣을 수 있게 속성정의
노멀이 적용된 반사벡터를 구하기 위해서 WorldReflectionVector함수 사용
결과 확인 (Emission)
노말맵을 추가시켰더니 에러가 난다. 에러 내용을 대충 훑어보면
Shader error in 'Custom/Post_Work1': Surface shader Input structure needs
INTERNAL_DATA for this WorldNormalVector or WorldReflectionVector usage at
line 200 (on d3d11)
INTERNAL_DATA , WorldNormalVector, WorldReflectionVector 관련해서
키워드를 얻을 수 있어서 유니티 홈페이지에서 찾아보았다.
정확히는 무슨 말인지는 모르겠지만 worldRefl을 사용할 때 노말 맵을 쓸 경우
WorldReflectionVector를 사용하는데, 픽셀당 반사 벡터를 사용하기 위해
Input구조체에서 INTERNAL_DATA를 선언해서 뭔가 컴파일해주는 듯..?
좀 더 쉽게 설명하면 탄젠트 좌표계를 월드 좌표계로 변환시켜주어야 하는데
그 과정에서 변환이 되지 않아 에러가 났던 것이고 INTERNAL_DATA를 통해서
변환해주는 듯하다. (자세한 것은 모르겠다..)
유니티가 PBR로 바뀌면서 이런 식으로 큐브 맵 사용이 변경되었다 한다.
그러면 일단 한번 수정해보자.
헬멧 MaskMap 추가
만들었던 큐브맵 머티리얼을 헬멧 모델에 적용하여
금속 재질인 것처럼 표현하고 마스크 맵을 적용하여 부분적으로 적용되도록 해보겠다.
Shader "Custom/Post_Work1"
{
Properties
{
_MainTex("Albedo (RGB)", 2D) = "white" {}
_NormalMap("NormalMap", 2D) = "bump" {}
_MaskMap("MaskMap", 2D) = "bump" {}
_CubeMap("CubeMap", cube) = "" {}
[HDR]_Color("Color", color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
CGPROGRAM
#pragma surface surf Lambert
#pragma target 3.0
sampler2D _MainTex, _NormalMap, _MaskMap;
samplerCUBE _CubeMap;
struct Input
{
float2 uv_MainTex, uv_NormalMap, uv_MaskMap;
float3 worldRefl;
INTERNAL_DATA
};
float4 _Color;
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
fixed4 m = tex2D(_MaskMap, IN.uv_MaskMap);
o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
o.Emission = texCUBE(_CubeMap, WorldReflectionVector(IN, o.Normal)) * m.a * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
Reflection Probe 사용하기
리플렉션 프로브란 해당 오브젝트를 배치하여 구역 내에 주변 static오브젝트들을
캡처하여 큐브 맵 데이터로 저장하는 기능이다.
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
fixed4 m = tex2D(_MaskMap, IN.uv_MaskMap);
o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
fixed3 wr = WorldReflectionVector(IN, o.Normal);
//fixed3 p = texCUBE(_CubeMap, wr);
fixed3 r = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, wr) * unity_SpecCube0_HDR.r;
o.Emission = r * m.a;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
유니티에서 리플렉션 프로브로 큐브 맵을 받기 위해서는 UNITY_SAMPLE_TEXCUBE()를 사용해야 한다.
unity_SpecCube0, unity_SpecCube0_HDR은 리플렉션 프로브 데이터를 가지고 있으며,
unity_SpecCube가 아니라 unity_SpecCube0이 붙은걸 보면 뒤에 1도 존재한다는 것도 알 수 있고
HDR도 1이 존재한다.
이를 설명하기 위해서 오브젝트 Mesh Renderer 인스펙터 부분을 보면 Light Probes에
Blend Probes라는 항목이 존재하는데, 리플렉션 프로브 영역으로 이동할 때 리플렉션 이미지가 갑자기 바뀌는 것을 방지하기 위해 블렌딩 해주는 것이라고 한다.
'그래픽스(Graphics) > Shader' 카테고리의 다른 글
픽킹 (0) | 2022.12.31 |
---|---|
오른손 법칙과 투영 (0) | 2022.10.29 |
빛의 성질-5 (Characteristics of Light-5): 빛의 방사와 조사(Radiance and Irradiance of Lights), 입체각(Solid Angle) (0) | 2022.09.07 |
BRDF (Bidrectional Reflectance Distributing Function) (0) | 2022.08.30 |
Object Outlines in Unity (0) | 2022.08.21 |