본문 바로가기
근황

ND Block 셰이더 모델 추가

by IX. 2023/05/10 11:00:22

5.10

회사에서 작업을 하던 중 디렉터가 워포그를 주문했다.(스타크래프트에서 시야를 가리는 검은색 안개)

워포그는 격자의 플랜을 깔고 카메라에서 캐릭터에게 레이를 쏘아서

부딪히는 지점의 위치를 구한 후, 그 반지름만큼의 버텍스 컬러를 흰색으로 변경(CPU가 해야 한다 = 게임 로직임),

이를 셰이더에서 오팩시티로 적용하면 구현할 수 있다...고 유튜브에서 보았다.

 

하지만 이것이 디렉터의 의도와는 좀 다르다. 디렉터는 밤씬에서 게임에 포인트 라이트를 넣은 것처럼 주변이 밝아지는 효과를 원했다.

그럼 그냥 포인트 라이트를 쓰면 되지만.... 문제는 이게 10개도 넘게 나올 수 있다는 것이다. 뿐만아니라 타일베이스의 게임이다 보니 타일별로 불빛이 0과 1로 명확하게 나뉘어야 한다.

 

첫구현은 타일의 이미시브를 높여주는 것이었다. 하지만 이것은 그림자를 없앤다. 그림자는 유지된 채로 타일만 밝게 하고 싶다...

 

과거(언리얼 4.14이하)에는 커스텀 노드로 그림자를 가져올 수 있었다고 한다.

그렇다면 이걸 이미시브에 덧발라주면 해결된다.

return GetPerPixelLightAttenuation(float2 UV);

Textured Shadows Trick in Unreal Engine - Tom Looman

 

Textured Shadows Trick in Unreal Engine

This weekend I stumbled upon a reddit post about Dr. Facilier’s interesting shadow in The Princess and the Frog and it inspired me to experiment with Forward shading in Unreal Engine 4 to re-create a...

www.tomlooman.com

하지만 이것이 언리얼5에서는 작동이 안된다. 이 패스는 쓰레기 데이터를 리턴한다.

그래서 일이 커졌다...시작해 보자.

 

일단 셰이더 모델을 추가해야 한다.

사내 프로그래머의 증언에 따르면 윈도우 11을 쓰면 컴파일 할 때 모든 코어를 사용한다고 전해진다.

하지만 그걸 위해 윈도우 11을 깔고 싶진 않았으므로 그냥 진행하자.

 

...컴파일에 하루가 걸렸다.

(다음날)

 

5.11

컴파일은 성공했으나 몇가지 문제가 있었다.

당장 컴파일될 셰이더 순열부터 줄이자. 

Unreal Engine 4 Rendering Part 5: Shader Permutations | by Matt Hoffman | Medium

 

Unreal Engine 4 Rendering Part 5: Shader Permutations

Reducing shader permutations to make testing and iteration faster!

medium.com

아래 항목들을 모두 Disable시켜주어야 한다. UE5에선 메뉴의 이름이 조금 바뀌었다.

Lighting

  • Allow Static Lighting
  • Support Stationary Skylight
  • Support Low Quality Lightmap Shader Permutations
  • Support PointLight WholeSceneShadows
  • Support Atmospheric Affecting Height Fog

Mobile Shader Permutation Reduction

  • Support Combined Static and CSM Shadowing
  • Support Pre-baked Distance Field Shadows
  • Support Movable Directional Lights

Config/DefaultEngine.ini 의 렌더링 세팅에 다음을 추가

r.ForceDebugViewModes=2

 

...안줄었는데?!

처...처음이라 그런걸지도... 나중에 줄어드리라 기대해보자.

 

셰이더모델 추가의 주목적은 LightColor를 중간에 가로채서 제어하고 싶은 것이다.

이를 위해 베이스 패스 중간에 셰이더 모델에 따른 분기를 만들자

#if MATERIAL_SHADINGMODEL_ND_BLOCK		
		float3 FakeLightColor = GetMaterialCustomData0(MaterialParameters);
		AccumulateDirectionalLightingNDBlock(GBuffer, MaterialParameters.WorldPosition_CamRelative, CameraVector, MaterialParameters.ScreenPosition, SvPosition, DynamicShadowFactors, DirectionalLightShadow, DirectLighting, FakeLightColor);

그리고 라이트 데이터에서 컬러를 넣는 부분에 커스텀 핀의 컬러를 끼워넣자.

//LightData.Color = MobileDirectionalLight.DirectionalLightColor.rgb;
LightData.Color = FakeLightColor;

컴파일해보자.

오오.. 2000개밖에 안된다!

일단 가로챈 라이트컬러는 잘 작동한다.

하지만 커스텀 컬러는 float3를 받지 않는다. 조사해보니 half로 받는다...에라이...

이걸 고치는 법은 모르겠고, 그냥 다른 슬롯으로 받자. SSS를 안쓰니 이걸로 받자.

하지만... 어쩐지 작동이 안된다. 코드를 좀 더 살펴보니... 서브서페이스 모델일 경우만 핀정보를 받을 수 있나보다.

 

고쳐보자. 컴파일 걸고 퇴근

 

5.12

MaterialShared.h에서 다음 코드를 고쳐주면 커스텀 모델을 서브스페이스화(?)시킬 수 있다.

inline bool IsSubsurfaceShadingModel(FMaterialShadingModelField ShadingModel)
{
	return ... || ShadingModel.HasShadingModel(MSM_NDBlock);
}

이제 제대로 컬러를 받는다.

하지만 여전히 2가지 문제가 남아있다.

1. 조명의 밝기가 어둡다.

2. SSS를 활성화시켰을 때의 최적화 이슈

 

1번은 핀정보를 받을 때 Raw데이터를 받으면 될 것 같다. 머티리얼 템플릿.h를 보면 Raw데이터를 리턴받는 코드가 있다.

// .rgb:SubsurfaceColor, .a:SSProfileId in 0..1 range
half4 GetMaterialSubsurfaceDataRaw(FPixelMaterialInputs PixelMaterialInputs)
{
	return PixelMaterialInputs.Subsurface;
}

half4 GetMaterialSubsurfaceData(FPixelMaterialInputs PixelMaterialInputs)
{
	half4 OutSubsurface = GetMaterialSubsurfaceDataRaw(PixelMaterialInputs);
	OutSubsurface.rgb = saturate(OutSubsurface.rgb);
	return OutSubsurface;
}

이제 HDR을 지원

 

2번은 챗GPT에게 물어보니 포워드에선 사용할 수 없다고 한다. 

하지만 이 놈을 믿어야 하나.... 해서 코드를 살펴보니 디퍼드 렌더링과 스트라타에 관련된 셰이더패스에서만 서브서페이스가 발견되는 걸 확인할 수 있었다.

 

해서 SS는 문제가 없는데 모바일 디렉셔널 라이팅은 어쩐지 3배 약한 빛을 받고 있다.

x3을 하면 일단 해결은 된다.

허나 무엇이 다른걸까? 왜 이런 차이가 발생하는 걸까.

커스텀 노드가  언제 문제를 일으킬지 찜찜하니 그냥 커스텀핀을 하나 더 쓰기로 하자.

 

라이트 컬러와 마스크를 따로 받는다.

Mask는 Lerp로 구현, 0이면 본래의 조명이, 1이면 페이크조명이 켜진다.

이로서 하나의 스테이지에 2개의 조명이 존재하게 되었습니다.

구현 끝!