일단 유니티 Lit 셰이더의 PBR 연산은 LitForwardPass 에서 시작하고 , 거기 안에서 조명 연산 부분은 half4 color = UniversalFragmentPBR(inputData, surfaceData); 이게 사실 전부인데,
UniversalFragmentPBR 은 Lighting.hlsl에 정의되어 있고 여기서 UniversalFragmentPBR(InputData inputData, SurfaceData surfaceData) 라는 함수로 정의되어 있습니다. 뭐야 실체는 다 밖에 있는거네.
그럼 이제 UniversalFragmentPBR(InputData inputData, SurfaceData surfaceData) 함수를 봐야겠죠
꽤 깁니다. 이거 뭐 왜 긴지는 뻔한데.. 이거저거요거 다 들어 있어서 그래요 게다가 각종 디파인이 들어 있어서 그런데요. 저놈의 디파인 땜에 우버셰이더는 무거워지는거지.. 게다가 공부할때 힘들게 만든 요인도 저 녀석입니다.
자 그럼.. 위의 디파인은 다음과 같습니다.
#if defined(_SPECULARHIGHLIGHTS_OFF) 스페큘러 연산할때 조명 하이라이트 연산은 날리느냐 가져가느냐예요 #if defined(DEBUG_DISPLAY) 디버그 디스플레이 모드일때 렌더링 되는 데이터예요 #ifdef _LIGHT_LAYERS 라이트 레이어 옵션 제어하는데예요. 여기에 해당하는 라이트 레이어만 렌더링하죠 #if defined(_ADDITIONAL_LIGHTS) Additinal Light 계산하는 부분이예요. 메인 디렉셔널 하나 빼고는 전부 Additinal Lihgt죠 #if USE_FORWARD_PLUS Forward Plus 렌더링 모드냐 물어보는 거예요. 포워드+ 는 포워드를 개량해서 라이트를 더 많이 쓸 수 있게 만들죠 그러면 Additinal Light 사용할 수 있는 양이 늘어나니까 Additinal Light 안에 옵션이 있어요
#if defined(_ADDITIONAL_LIGHTS_VERTEX) 버텍스 라이트 쓸 때 도는 모드예요. URP 에서는 버텍스 라이트를 쓸 일이 많이 줄었지만, 옵션을 낮추면 Additinal Light가 버텍스 라이트로 돌아요 그 때 씀. #if REAL_IS_HALF 유니티에서는 float 이나 half , fixed 말고 real 이라는 형식을 하나 만들었는데요, 이건 뭐 별건 아니고 플렛폼과 상황에 따라 float 이나 half 를 동적으로 와리가리 할 수 있게 하는 거예요 . 즉 지금은 real 이 half 일때 정밀도 같은 이유 때문에 계산을 추가해 주는것.
휴 각종 디파인이 있군요. 저 디파인은 사실 보는데 걸리적대니까 다 삭제해 버리면 메인 라이트 연산 하나만 남겠죠?
CalculateShadowMask(inputData); 셰도우 마스크 연산을 위한 함수입니다. 라이트맵에서 셰도우 마스크 방식과 연관있습니다.
CreateAmbientOcclusionFactor(inputData, surfaceData); SSAO 연산을 위한 함수입니다. SSAO 연산을 안할거면 별 필요 없죠
GetMainLight(inputData, shadowMask, aoFactor); 조명의 여러 값들을 받아옵니다.
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI); 리얼타임 GI와 BakedGI를 합쳐줍니다. 라이트 프로브랑 라이트맵을 합쳐준다 뭐 그런 쪽이죠
CreateLightingData(inputData, surfaceData); 라이팅 데이터 구조체를 정리해 줍니다.
GlobalIllumination(brdfData, brdfDataClearCoat, surfaceData.clearCoatMask, inputData.bakedGI, aoFactor.indirectAmbientOcclusion, inputData.positionWS, inputData.normalWS, inputData.viewDirectionWS, inputData.normalizedScreenSpaceUV); lightingData.giColor 를 만들어 주는 함수죠. PBR 에서 간접광 연산이 여기서 전부 일어난다고 볼 수 있습니다.
LightingPhysicallyBased(brdfData, brdfDataClearCoat, mainLight, inputData.normalWS, inputData.viewDirectionWS, surfaceData.clearCoatMask, specularHighlightsOff); 사실 이게 진짜입니다. 이게 진짜 PBR 조명연산을 처리하죠. 여기에서 나온 값들을 전부 lightingData 구조체로 보내서 나중에 합쳐 줍니다. CalculateFinalColor(lightingData, surfaceData.alpha); 함수를 통해서요
CalculateFinalColor 함수는 어떻게 되어 있는가?
우선 공식을 보려면 마지막에 전부 더해주는 부분을 체크해 보는게 좋죠 CalculateFinalColor 함수는 일단 아래걸 사용하네요
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_EMISSION))
{
lightingColor += lightingData.emissionColor;
}
return lightingColor;
}
여기가 뭐냐면 ..
여기에 사용되는 놈이예요
여기에 보면 각종 연산값들을 검증해 볼 수 있잖아요
이런것들을 위해 출력해주는 부분입니다. 그래서 보기 힘듬.
차근차근히 보죠. 우선 giColor 를 받아오고 거기에 mainLightColor를 더해줍니다. 그리고 additionalLightsColor 를 더해주고요 다시 거기에 vertexLightingColor 를 더해줍니다. 그렇게 더해준 라이트칼라 값에 albedo를 곱해주네요. 그리고 필요하면 emissionColor 를 더해주는 방식으로 되어 있습니다. 흠 입력받는 albedo 가 1이라서 albedo를 나중에 곱해주는 방식이 이채롭네요
댓글