콘텐츠로 이동

Unity Shader Graph 커스텀 함수 노드

Shader Graph의 Custom Function Node는 HLSL 코드를 직접 작성해 기본 제공 노드로는 표현하기 어려운 수학 함수, 특수 효과, 성능 최적화 셰이더를 구현할 때 사용합니다.


Shader Graph 창 → 빈 공간 우클릭 → Create Node → Custom Function
또는 노드 검색 창에서 "Custom Function" 입력

Node 설정:

  • Name: 함수 이름 (HLSL 함수명과 동일)
  • Source: String (인라인 코드) 또는 File (외부 .hlsl 파일)
  • Inputs/Outputs: 포트 정의

/* Custom Function Node 설정:
Name: Remap
Inputs: In(Float), InMin(Float), InMax(Float), OutMin(Float), OutMax(Float)
Outputs: Out(Float)
Body: */
void Remap_float(float In, float InMin, float InMax,
float OutMin, float OutMax, out float Out)
{
Out = OutMin + (In - InMin) * (OutMax - OutMin) / (InMax - InMin);
}

Assets/Shaders/CustomFunctions.hlsl
#ifndef CUSTOM_FUNCTIONS_INCLUDED
#define CUSTOM_FUNCTIONS_INCLUDED
// 물결 효과
void WaveOffset_float(float2 UV, float Speed, float Frequency,
float Amplitude, float Time, out float2 Out)
{
float wave = sin(UV.x * Frequency + Time * Speed) * Amplitude;
Out = float2(UV.x, UV.y + wave);
}
// 디졸브 효과
void Dissolve_float(float2 UV, Texture2D NoiseTexture,
SamplerState NoiseSampler, float Threshold,
float EdgeWidth, out float Alpha, out float Edge)
{
float noise = SAMPLE_TEXTURE2D(NoiseTexture, NoiseSampler, UV).r;
Alpha = step(Threshold, noise);
Edge = step(Threshold - EdgeWidth, noise) - Alpha;
}
#endif

Custom Function Node에서 File 모드로 이 파일을 참조하고 함수명을 지정합니다.


// Texture2D와 SamplerState를 받아야 함
void SampleWithOffset_float(
float2 UV, float2 Offset,
Texture2D MainTex, SamplerState Sampler,
out float4 Color)
{
Color = SAMPLE_TEXTURE2D(MainTex, Sampler, UV + Offset);
}

Shader Graph에서 포트 타입:

  • 텍스처 입력: Texture2D 타입
  • 샘플러 입력: SamplerState 타입 (별도 포트)

void ApplyNormalMap_float(
float3 NormalMap, // 노멀 맵 샘플 (0~1)
float3 Normal, // 버텍스 노멀 (월드)
float3 Tangent, // 버텍스 탄젠트 (월드)
float3 Bitangent, // 버텍스 바이탄젠트 (월드)
out float3 WorldNormal)
{
// 0~1 → -1~1 범위로 변환
float3 n = NormalMap * 2.0 - 1.0;
// TBN 매트릭스로 탄젠트→월드 변환
float3x3 tbn = float3x3(Tangent, Bitangent, Normal);
WorldNormal = normalize(mul(n, tbn));
}

void Checkerboard_float(float2 UV, float Scale, out float Out)
{
float2 scaled = UV * Scale;
float2 id = floor(scaled);
Out = fmod(id.x + id.y, 2.0);
}

// 모바일에서는 half 정밀도로 성능 향상
void RimLight_half(half3 ViewDir, half3 Normal,
half RimPower, out half RimFactor)
{
half NdotV = saturate(dot(Normal, ViewDir));
RimFactor = pow(1.0h - NdotV, RimPower);
}

// UV 좌표를 색상으로 시각화
void DebugUV_float(float2 UV, out float4 Color)
{
Color = float4(UV.x, UV.y, 0.0, 1.0);
}
// 노멀을 색상으로 시각화
void DebugNormal_float(float3 Normal, out float4 Color)
{
Color = float4(Normal * 0.5 + 0.5, 1.0);
}

Custom Function Node의 핵심은 함수 이름이 {Name}_float (또는 _half) 형식이어야 한다는 것입니다. 외부 .hlsl 파일을 사용하면 여러 Shader Graph에서 함수를 재사용할 수 있고, 버전 관리도 용이합니다. 텍스처 샘플링은 반드시 SAMPLE_TEXTURE2D 매크로를 사용해 SRP 호환성을 유지하세요.