연구 목적: Unity 6.2.1 이상 버전에서 HDRP(High Definition Render Pipeline)와 URP(Universal Render Pipeline)의 셰이더 코드 작성 시 API 차이점, 문법 차이점, Include 구조 차이점을 체계적으로 분석하고 정리
연구 범위: Unity 6.2.1+ 버전 기준 셰이더 코드 작성 가이드라인
1. 개요 및 파이프라인 호환성
1.1 기본 호환성 정보
HDRP와 URP로 작성된 프로젝트는 상호 호환되지 않으며, Built-in Render Pipeline과도 호환되지 않습니다.
개발 시작 전 렌더 파이프라인을 결정해야 하며, 파이프라인 간 전환은 매우 큰 비용이 발생합니다.
1.2 셰이더 코드 호환성
- Surface Shader 지원 없음: 두 파이프라인 모두 #pragma surface 기반 Surface Shader를 지원하지 않음
- Built-in 셰이더 호환성: Built-in 렌더 파이프라인용 커스텀 셰이더는 자동 업그레이드 불가
- SRP Batcher 호환성: 두 파이프라인 모두 SRP Batcher를 위한 특별한 구조 요구
2. 기본 셰이더 구조 차이점
2.1 URP 기본 구조
기본 Include 구조
Shader "Custom/URPExample" {
Properties {
_BaseMap ("Base Texture", 2D) = "white" {}
_BaseColor ("Base Color", Color) = (1,1,1,1)
}
SubShader {
Tags {
"RenderType"="Opaque"
"RenderPipeline"="UniversalRenderPipeline"
}
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
float4 _BaseColor;
CBUFFER_END
ENDHLSL
Pass {
Name "UniversalForward"
Tags { "LightMode"="UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
// 구현부...
ENDHLSL
}
}
}
2.2 HDRP 기본 구조
기본 Include 구조
Shader "Custom/HDRPExample" {
Properties {
_BaseColorMap("BaseColorMap", 2D) = "white" {}
_BaseColor("BaseColor", Color) = (1,1,1,1)
}
SubShader {
Tags {
"RenderPipeline"="HDRenderPipeline"
"RenderType"="Opaque"
}
Pass {
Name "Forward"
Tags { "LightMode" = "Forward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl"
// 구현부...
ENDHLSL
}
}
}
3. Include 파일 구조 및 역할 비교
3.1 URP Core Include 파일들
3.1.1 핵심 Include 파일
Include 파 | 역할 및 기능 |
Core.hlsl | 기본 변환 매트릭스, 좌표 변환 함수, 기본 유틸리티 함수 |
Lighting.hlsl | 라이팅 계산, PBR 관련 함수, 그림자 샘플링 |
Input.hlsl | 카메라, 시간, 렌더링 관련 전역 변수 |
Shadow.hlsl | 그림자 관련 함수 및 매크로 |
ShaderVariablesFunctions.hlsl | 셰이더 변수 접근 함수들 |
3.1.2 URP 전용 함수 예시
// URP 좌표 변환
VertexPositionInputs positionInputs = GetVertexPositionInputs(input.positionOS.xyz);
o.positionCS = positionInputs.positionCS;
// 또는 간단한 변환
o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
// URP 라이팅
Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
BRDFData brdfData;
InitializeBRDFData(surfaceData, brdfData);
3.2 HDRP Core Include 파일들
3.2.1 핵심 Include 파일
Include 파일 | 역할 및 기능 |
ShaderVariables.hlsl | HDRP 전용 전역 변수 및 상수 |
Material.hlsl | PBR 머티리얼 관련 함수 및 구조체 |
Lighting.hlsl | HDRP 라이팅 시스템, 고급 라이팅 기법 |
Common.hlsl | 공통 유틸리티 함수 |
BSDF.hlsl | 고급 BRDF/BSDF 함수들 |
3.2.2 HDRP 전용 함수 예시
// HDRP 좌표 변환
float4 positionCS = TransformObjectToHClip(input.positionOS);
// HDRP 라이팅 (더 복잡한 구조)
BSDFData bsdfData;
BuiltinData builtinData;
GetSurfaceAndBuiltinData(input, V, positionSS, bsdfData, builtinData);
4. 주요 API 및 문법 차이점
4.1 좌표 변환 API 차이
URP
// 방법 1: 구조체 사용 (권장)
VertexPositionInputs positionInputs = GetVertexPositionInputs(input.positionOS.xyz);
output.positionCS = positionInputs.positionCS;
output.positionWS = positionInputs.positionWS;
// 방법 2: 직접 변환
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.positionWS = TransformObjectToWorld(input.positionOS.xyz);
HDRP
// HDRP는 더 직접적인 접근
output.positionCS = TransformObjectToHClip(input.positionOS);
output.positionWS = TransformObjectToWorld(input.positionOS);
// 또는 HDRP 전용 함수 사용
float4 worldPos = GetAbsolutePositionWS(TransformObjectToWorld(input.positionOS));
4.2 라이팅 시스템 차이
URP 라이팅
URP 라이팅
// URP는 단순화된 라이팅 접근
InputData inputData;
InitializeInputData(input, normalTS, inputData);
Light mainLight = GetMainLight(inputData);
half4 shadowMask = CalculateShadowMask(inputData);
// PBR 계산
BRDFData brdfData;
InitializeBRDFData(surfaceData.albedo, surfaceData.metallic,
surfaceData.specular, surfaceData.smoothness,
surfaceData.alpha, brdfData);
half4 color = UniversalFragmentPBR(inputData, surfaceData);
HDRP 라이팅
// HDRP는 더 복잡하고 고급 라이팅 시스템
BSDFData bsdfData;
BuiltinData builtinData;
// 표면 데이터 구성 (더 복잡)
GetSurfaceAndBuiltinData(fragInputs, V, posInput, bsdfData, builtinData);
// 고급 라이팅 계산
LightLoopContext lightLoopContext;
PreLightData preLightData = GetPreLightData(V, posInput, bsdfData);
// 다중 라이트 처리
float3 diffuseLighting, specularLighting;
LightLoop(V, posInput, preLightData, bsdfData, builtinData,
diffuseLighting, specularLighting);
4.3 텍스처 샘플링 차이
URP 텍스처 샘플링
// URP 방식
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
// 프래그먼트에서
half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
HDRP 텍스처 샘플링
// HDRP 방식 (비슷하지만 컨텍스트가 다름)
TEXTURE2D(_BaseColorMap);
SAMPLER(sampler_BaseColorMap);
// 더 고급 샘플링 옵션 지원
half4 baseColor = SAMPLE_TEXTURE2D(_BaseColorMap, sampler_BaseColorMap, input.uv);
5. 고급 기능 차이점
5.1 그림자 처리
URP 그림자
// URP 그림자는 상대적으로 단순
float4 shadowCoord = TransformWorldToShadowCoord(positionWS);
half shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
// 추가 라이트 그림자
int lightIndex = GetAdditionalLightsCount();
for (int i = 0; i < lightIndex; ++i) {
Light light = GetAdditionalLight(i, positionWS);
half shadowAttenuation = AdditionalLightRealtimeShadow(i, positionWS);
}
HDRP 그림자
// HDRP는 더 고급 그림자 시스템
// 캐스케이드 그림자, 콘택트 그림자 등 지원
float shadow = GetDirectionalShadowAttenuation(lightLoopContext,
posInput.positionSS.xy,
positionWS,
shadowData,
L);
// 볼류메트릭 그림자, 스크린 스페이스 그림자 등 고급 기능
5.2 서브서피스 스캐터링 (SSS)
URP SSS (커스텀 구현 필요)
// URP에는 기본 SSS가 없어 직접 구현해야 함
// GPU GEM 3 방식의 Diffusion Profile 구현 예시
float3 SubsurfaceScattering(float3 albedo, float3 normal,
float3 lightDir, float3 viewDir,
float subsurfaceRadius) {
// 커스텀 SSS 구현
float3 H = normalize(lightDir + normal * subsurfaceRadius);
float VdotH = saturate(dot(viewDir, -H));
float sss = pow(VdotH, _SSSPower) * _SSSIntensity;
return albedo * sss;
}
HDRP SSS (내장 지원)
// HDRP는 내장 SSS 지원
// Diffusion Profile을 통한 고급 SSS
float3 sssResult = EvaluateTransmission(bsdfData,
builtinData.diffusionProfileIndex,
lightData,
NdotL,
NdotV);
6. 성능 최적화 고려사항
6.1 SRP Batcher 호환성
URP SRP Batcher
// URP에서 SRP Batcher 호환성을 위한 구조
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
half4 _BaseColor;
half _Metallic;
half _Smoothness;
CBUFFER_END
// 모든 머티리얼 프로퍼티는 CBUFFER 안에 있어야 함
HDRP SRP Batcher
// HDRP도 유사하지만 더 복잡한 구조
CBUFFER_START(UnityPerMaterial)
float4 _BaseColorMap_ST;
float4 _BaseColor;
float _Metallic;
float _Smoothness;
float _NormalScale;
CBUFFER_END
6.2 Mobile 최적화
URP Mobile 최적화
- URP는 mobile 타겟팅이 강함
- half 정밀도 적극 활용
- Simple Lit 셰이더 제공
- 더 적은 라이트 개수 지원
HDRP Mobile 제한
- HDRP는 고사양 플랫폼 타겟팅
- Mobile에서 제한적 지원
- 더 높은 성능 요구사항
7. 실제 구현 예시 비교
.1 캐릭터 스킨 셰이더 구현
URP 캐릭터 스킨 구현
// URP에서 커스텀 SSS 구현
float3 SkinSSS(float3 albedo, float3 normal, float3 lightDir,
float3 viewDir, float sssRadius) {
float3 H = normalize(lightDir + normal * sssRadius);
float VdotH = saturate(dot(viewDir, -H));
float sss = pow(VdotH, _SSSPower);
return albedo * sss * _SSSColor.rgb;
}
// Horizon Occlusion 구현
half HorizonOcclusion(half3 R, half3 normalWS, half3 vertexNormal, half horizonFade) {
half specularOcclusion = saturate(1.0 + horizonFade * dot(R, vertexNormal));
return specularOcclusion * specularOcclusion;
}
7.2 Hair Anisotropic 셰이더
URP Hair 셰이더
// Hair Anisotropic Specular
half3 ShiftTangent(half3 T, half3 N, float shift) {
half3 shiftedT = T + shift * N;
return normalize(shiftedT);
}
float StrandSpecular(half3 T, half3 V, half3 L, float exponent, float gloss) {
half3 H = normalize(L + V);
float dotTH = dot(T, H);
float sinTH = sqrt(1 - dotTH * dotTH);
float dirAtten = smoothstep(-1, 0, dotTH);
return min(100, dirAtten * pow(sinTH, exponent) * gloss);
}
8. 마이그레이션 가이드라인
8.1 Built-in에서 URP로 전환
- Surface Shader 제거: vertex/fragment 셰이더로 재작성
- Include 구조 변경: URP 전용 include 사용
- 라이팅 함수 교체: URP 라이팅 API 사용
- SRP Batcher 호환성: CBUFFER 구조 적용
8.2 URP에서 HDRP로 전환 (또는 그 반대)
- Include 경로 변경: 파이프라인별 include 경로 수정
- 라이팅 시스템 재구성: 각 파이프라인의 라이팅 API 사용
- 고급 기능 고려: HDRP의 추가 기능 활용 또는 URP 제약 고려
- 성능 타겟 재검토: 타겟 플랫폼에 맞는 최적화
9. 결론 및 권장사항
9.1 선택 기준
- Mobile/VR 타겟: URP 권장
- High-end PC/Console: HDRP 권장
- 크로스 플랫폼: URP가 더 적합
- 고급 라이팅 요구: HDRP가 더 적합
9.2 개발 시 주의사항
- 파이프라인 결정은 초기에: 나중에 변경하기 매우 어려움
- SRP Batcher 호환성 유지: 성능을 위해 필수
- 타겟 플랫폼 고려: 각 파이프라인의 지원 플랫폼 확인
- 커스텀 기능 구현: 각 파이프라인별 구현 방식 이해 필요
9.3 향후 발전 방향
Unity 6.0 이후 버전에서는 두 파이프라인 간의 통합이 점진적으로 이루어질 것으로 예상되며, Shader Graph를 통한 크로스 파이프라인 호환성도 개선될 것으로 보입니다.
참고 문헌 및 소스
- Unity 공식 문서: HDRP/URP 셰이더 가이드
- 내부 프로젝트 경험 및 구현 사례
- 커뮤니티 리소스 및 기술 아티클
'UNITY3D' 카테고리의 다른 글
MagicaCloth2 Dynamic Optimizer (0) | 2025.07.22 |
---|---|
고객사와 함께 읽는 울티밋 가이드 프로파일링 유니티 (4) | 2025.07.08 |
DirectBRDF_DualLobeSpecular (1) | 2025.06.20 |
유니티 6.1 인스턴싱 로컬 키워드 추가 리스트. (0) | 2025.06.04 |
GetDefaultDepthBufferBits() 메서드 (1) | 2025.06.04 |