TECHARTNOMAD | TECHARTFLOWIO.COM

UNITY3D

URP 기술적 개선 제안 (2025.09.15 추가)

jplee 2025. 9. 15. 22:33

중국 엔지니어가 포팅 후 테스트 한 영상이다.

아무튼 관련 해서 유니티 엔진을 사용하는 고객사가 있기 때문에 2025년 3분기에 진행 할 내용들을 정리 해 봤다.


1. PBR 구현의 정확성 개선 방안

에너지 보존 검증: 언급된 에너지 보존 원칙이 핵심인데, 실제 구현에서 다음을 추가로 고려하면 좋을 것 같습니다:

Multi-scattering compensation 추가

높은 roughness에서 에너지 손실을 보정하는 것이 중요합니다. Heitz et al.의 연구에 따르면 단일 산란 모델은 roughness가 증가할수록 최대 40%의 에너지를 잃을 수 있습니다. 이를 해결하기 위한 방법:

// Fdez-Agüera의 에너지 보존 BRDF 구현 예시
vec3 Fr = max(vec3_splat(1.0 - roughness), F0) - F0;
vec3 k_S = F0 + Fr * pow(1.0 - NoV, 5.0);
vec3 FssEss = k_S * f_ab.x + f_ab.y; // f_ab는 사전 계산된 LUT
  • Energy Compensation LUT: Kulla-Conty 방식의 2D/3D LUT 사용 고려
  • Analytical Approximation: 실시간 성능을 위해 Davide Sforza의 분석적 근사법 활용

White Furnace Test

Enterprise PBR 모델에서 제시한 검증 방법

  • Uniform 환경광(모든 방향에서 1.0)에서 albedo 1.0일 때 완전 백색 출력 확인
  • 에너지 보존 위반 시 시각적으로 어두워지는 문제 발생

2. 환경광 반사 품질 개선

Unity와 UE의 반사 품질 차이점에 대한 구체적 개선 방안:

Importance Sampling 구현

Epic Games의 접근법을 Unity에 적용:

// Hammersley 시퀀스를 이용한 중요도 샘플링
vec2 Hammersley(uint i, uint N) {
    float E1 = fract((float)i / (float)N);
    float E2 = float(ReverseBits32(i)) * 2.3283064365386963e-10;
    return vec2(E1, E2);
}

// GGX 중요도 샘플링
vec3 ImportanceSampleGGX(vec2 Xi, float roughness, vec3 N) {
    float a = roughness * roughness;
    float phi = 2.0 * PI * Xi.x;
    float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
    float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
    // ... tangent space to world space 변환
}

Split-sum Approximation 개선

Brian Karis의 방법론

  • Pre-filtered environment map: 각 mip 레벨별로 다른 roughness 적용
  • BRDF Integration LUT: 16비트 정밀도 사용 권장

3. Unity 6 + Rendering Graph 활용

Unity 6의 새로운 기능들을 활용한 최적화

Deferred+ 렌더링

  • Cluster-based light culling: 타일 기반 대신 3D 클러스터 사용
  • GPU Resident Drawer 통합: BatchRendererGroup API 자동 활용
  • 성능 향상: 많은 광원이 있는 씬에서 Forward+ 대비 개선

GPU Resident Drawer

실제 테스트 결과

  • CPU 워크로드 50% 감소 (대규모 복잡한 씬)
  • Draw call 대폭 감소: 35,000개 오브젝트에서 128개로 감소
  • 메모리 오버헤드: 약 100MB 증가
  • GPU Occlusion Culling: 이전 프레임의 depth buffer 활용

설정 방법:

// GPU Resident Drawer 활성화 확인
using UnityEngine.Rendering;

public class GPUResidentDrawerChecker : MonoBehaviour {
    void Start() {
        if (GraphicsSettings.currentRenderPipeline is UniversalRenderPipelineAsset urpAsset) {
            bool isEnabled = urpAsset.gpuResidentDrawerMode == 
                           GPUResidentDrawerMode.InstancedDrawing;
            Debug.Log("GPU Resident Drawer: " + isEnabled);
        }
    }
}

4. SubsurfaceProfile 최적화

Separable SSS 구현

Jorge Jimenez의 Separable SSS 기법

주요 특징:

  • 2-pass screen-space convolution: 기존 12-pass 대신 2-pass로 처리
  • 실행 시간: 프레임당 0.5ms 미만
  • 샘플링: Jittering 전략으로 픽셀당 7개 샘플만 필요
// Separable SSS 커널 적용
float4 SSSSBlurPS(float2 texcoord : TEXCOORD0,
                   float2 pixcoord : VPOS) : COLOR0 {
    // 첫 번째 패스: 수평 블러
    // 두 번째 패스: 수직 블러
    float sssWidth = subsurfaceProfile.scatterDistance;
    
    // Jittered sampling으로 aliasing 감소
    float2 offset = getJitteredOffset(pixcoord);
    
    // 가우시안 커널 대신 profile 기반 커널 사용
    return performSeparableConvolution(texcoord, offset, sssWidth);
}

Transmission LUT 캐싱

  • 사전 계산: 다양한 thickness 값에 대한 투과율 저장
  • 실시간 lookup: thickness map과 결합하여 사용

5. 성능 최적화 제안

Shader Variant 최소화

// shader_feature 사용 예시
#pragma shader_feature_local _ANISOTROPY
#pragma shader_feature_local _CLEARCOAT
#pragma shader_feature_local _SUBSURFACE

// 조건부 컴파일로 불필요한 계산 제거
#ifdef _ANISOTROPY
    // Anisotropic GGX 계산
#else
    // 기본 GGX 계산
#endif

Mobile 최적화

  • Half precision 적극 활용:
half3 color = half3(0, 0, 0);
half roughness = saturate(half(_Roughness));
half metallic = saturate(half(_Metallic));
  • Simplified BRDF 모델 옵션 제공:
#if defined(SHADER_API_MOBILE)
    // Mobile용 간소화된 BRDF
    half3 brdf = SimplifiedGGX(N, V, L, roughness);
#else
    // Desktop용 전체 BRDF
    half3 brdf = BRDF_GGX(N, V, L, roughness, F0);
#endif

6. Hair 셰이딩 개선

Marschner 모델 구현에 추가로:

  • Dual scattering approximation: 더 사실적인 금발/밝은 색 머리카락
  • Azimuthal roughness: TT lobe의 glint 효과 개선

7. 검증 도구 개선

픽셀 단위 비교를 위한 추가 도구:

  • A/B test viewer: Unity 내에서 UE 결과와 실시간 비교
  • Difference visualization: 차이를 heat map으로 시각화
  • Component-wise debugging: Diffuse/Specular/Transmission 각각 독립적 검증

8. ASE 대안 고려

ASE 의존성을 줄이기 위해:

  • Shader Graph Custom Function Node 활용
  • Better Shaders 같은 더 가벼운 대안 고려
  • 핵심 로직을 독립적인 .hlsl 라이브러리로 분리