TECHARTNOMAD | TECHARTFLOWIO.COM

UNREAL ENGINE

[알쓸신잡] Shader Define Keyword 와 Custom Expression.

jplee 2025. 3. 1. 01:37

뭐 당연히 알거라고 생각하지만 생각보다 구글이건 어디건 검색해도 ...

아니면 애픽 문서에도 모호하거나 누락 되어 있는 것 같아서 잠깐 남겨 봅니다.

원래는 CVars 로 Custom_Shader_Enable 뭐 이렇게 엔진에 추가를 하던 와중에... 

Custom Expression 에서 Pre-Defien 은 어떻게 동작하는지 잠깐 알고 싶어서였고 그래서 뭐 이렇게 적는 거 같습니다.

여기서는 간단하게 살펴볼 심산이라...

머트리얼 에디터의 Custom Expression 과 셰이더 소스의 MaterialTemplate 정도를 가지고 이야기 해 볼겁니다.

저는 라이더를 쓰고 있으니 파일 찾기로 materialtemplate 을 찾아 보죠.

MaterialTemplate.ush 가 있네요. 자 이걸 일단 열어봅시다.

MaterialTemplate.ush 파일은 언리얼 엔진에서 머티리얼 셰이더를 구성할 때 기본적으로 포함되는 셰이더 코드 템플릿 역할을 합니다. 이 파일은 머티리얼 속성이나 텍스처 샘플링, 조명 계산과 같은 공통 로직을 정의하고, 외부 머티리얼 셰이더(.usf, .ush 등)가 이를 참조하여 엔진 내부에서 일관성 있는 셰이더 처리를 수행하도록 돕습니다. 즉, 머티리얼과 관련된 필수 함수나 매크로, 구조체 등이 집약되어 있어 다양한 머티리얼 셰이더들이 공통된 기반 위에서 동작할 수 있도록 하는 핵심 모듈입니다.

아무튼...

동작 구조만 볼꺼니까... 

Base Color 를 찾아가 볼까요?

half3 GetMaterialBaseColorRaw(FPixelMaterialInputs PixelMaterialInputs)
{
	return PixelMaterialInputs.BaseColor;
}

half3 GetMaterialBaseColor(FPixelMaterialInputs PixelMaterialInputs)
{
	return saturate(GetMaterialBaseColorRaw(PixelMaterialInputs));
}

이 쯤이 될것 같습니다.

간단히 머티리얼 에디터에서 작성 된 노드가 Port 를 통해 전체 셰이더가 만들어 질 때 GetMaterialBaseColorRaw 이 함수는 입력으로 받은 PixelMaterialInputs 구조체에서 BaseColor 값을 그대로 반환합니다. BaseColor는 일반적으로 재질의 확산 색상(difuse color)을 나타내며, 셰이더에서 조명 계산 등에 사용됩니다. 그리고 GetMaterialBaseColor 함수는 GetMaterialBaseColorRaw를 호출하여 BaseColor 값을 얻고, 그 값에 saturate 함수를 적용하여 0과 1 사이로 값이 클램핑 하여 색상 값이 0 이상, 1 이하의 범위를 벗어나지 않도록 보장하고 있습니다. 아무튼 이 부분을 가지고 실험을 해 보는것이 좋겠네요!

검증을 위해서 CUSTOM_SHADER_DEFINED 라는 키워드를 아래처럼 정의 할 겁니다.

half3 GetMaterialBaseColorRaw(FPixelMaterialInputs PixelMaterialInputs)
{
	return PixelMaterialInputs.BaseColor;
}

half3 GetMaterialBaseColor(FPixelMaterialInputs PixelMaterialInputs)
{
	half3 baseColor = saturate(GetMaterialBaseColorRaw(PixelMaterialInputs));	
#if defined(CUSTOM_SHADER_DEFINE)
	return baseColor * float3(1.0, 0.0, 0.0);
#else
	return baseColor;
#endif
}

이렇게 했습니다.

이제 언리얼 에디터를 열고 머티리얼 편집기에서 뭔가를 추가 해 보죠.

기존에 팀원분이 제작 해 놓은 머티리얼을 하나 열었어요. 네임 라우터 노드중에서 Base 와 SetMaterialAttributes 중간 어딘가에 Custom Expression 을 하나 추가 할겁니다. 이 머트리얼 노드는 어차피 컴파일 하면 별도의 셰이더 파일을 만들어 낼껍니다. 저는 거기에 전처리 정의를 추가 하기만 하면 되거든요.

이미지의 저작권은 (주)게임테일즈에 있습니다. 해당 렌더링 이미지는 실제 게임 렌더링과 무관 합니다.

CUSTOM_SHADER_DEFINE 를 추가 하기 전의 렌더링 모습입니다.

이렇게 Custom Expression 을 Base 네임라우터와 곱해줬습니다. 이렇게 곱해준다고 해서 뭐 정말 곱셈이 되는건 아닙니다. 이렇게 해 줘야 생성되는 셰이더에 디파인 정의가 추가 되거든요.

Custom Expression 은 아래 그림처럼 설정을 해 줘야겠지요.

그 다음 Ctrl + Shift + . 으로 비동기 머티리얼 컴파일을 수행 해 보세요. 아니면 그냥 에디터를 껏다가 다시 켜봅시다.

 

이미지의 저작권은 (주)게임테일즈에 있습니다. 해당 렌더링 이미지는 실제 게임 렌더링과 무관 합니다.

base color 에 half3(1.0f,0.0f,0.0f) 를 곱해줬으니 빠알가케 물들었네요.

그럼 템플릿코드를 바꿔서 흑백 렌더링으로 바꿔 줘 보죠.

half3 GetMaterialBaseColorRaw(FPixelMaterialInputs PixelMaterialInputs)
{
	return PixelMaterialInputs.BaseColor;
}

half3 GetMaterialBaseColor(FPixelMaterialInputs PixelMaterialInputs)
{
	half3 baseColor = saturate(GetMaterialBaseColorRaw(PixelMaterialInputs));	
#if defined(CUSTOM_SHADER_DEFINE)
	half gray = dot(baseColor, half3(0.299f, 0.587f, 0.114f));
	return gray.rrr;
#else
	return baseColor;
#endif
}

이미지의 저작권은 (주)게임테일즈에 있습니다. 해당 렌더링 이미지는 실제 게임 렌더링과 무관 합니다.

뭐 이렇게 CUSTOM_SHADER_DEFINE 으로 감싸준 대로 결과가 출력 되었네요.

특별한건 아니고 딱히 문서로 정리 된 것이 없어보여서 간단히 언급을 해 봤습니다.

다만 한 가지 남은 문제점은 셰이더 파일을 수정 한 후 비동기 컴파일을 했을 때 결과가 즉각적으로 반응하지 않는다는 것입니다. 에디터를 껐다가 다시 켜 주는 것이 좋아요.

실무에서는 이렇게 하는 것 보다는 좀 더 복잡하지만 CVars 를 사용하고 렌더스레드세이프 환경에서 정식으로 전처리 키워드를 추가 하는 것이 좋구요. 

특별히 디바이스 프로필에 CVars 를 추가 해서 키워드에 의한 분기를 나눠주는 것이 아니라면 다른 쉬운 방법도 있습니다. 뭐 이 페이지에서는 이정도만 아루미 수박 겉 핡듯이 살펴보고 넘어가겠습니다. ^^

(주)게임테일즈에서 개발하고 컴투스가 서비스 할 더 스타라이트도 많은 관심과 사랑 부탁 드립니다.