요약
Unity URP의 한계를 뛰어넘어 물리 기반 유리 시뮬레이션을 구현한 VR 프로젝트. Depth Peeling, 물리 기반 광학 렌더링, 하이브리드 물리 시뮬레이션을 결합하여 실제 유리공예를 재현한 시각적/물리적 현실감을 달성했습니다.
역할
•
개인 프로젝트로 전체 시스템 설계 및 구현 (기여도 100%)
•
Unity URP Render Graph API 확장을 통한 6-Layer Depth Peeling 시스템 개발 (기여도 100%)
•
제어점 기반 하이브리드 물리 시뮬레이션 아키텍처 설계 (기여도 100%)
•
Beer's Law와 흑체복사를 적용한 물리 기반 렌더링 구현 (기여도 100%)
성과
•
VR 환경에서 78fps 안정적 구동으로 실시간 인터랙션 보장
•
기존 Vertex 기반 물리 대비 100배 성능 향상 달성
•
Unity URP에서 세계 최초 6-Layer Depth Peeling 구현
•
4fps에서 68fps로 극적인 성능 최적화 경험 축적
시기
•
2024.06 - 2024.08 (2개월 소요)
Unity URP 한계 돌파: 6-Layer Depth Peeling
"투명한 유리에서 정확한 두께를 어떻게 측정할까?"라는 단순한 질문이 Unity URP의 근본적 한계와 마주하게 했습니다. 기존 깊이 버퍼로는 겹치는 투명면들의 정확한 순서를 파악할 수 없었죠.
핵심 혁신: Unity URP Render Graph API를 확장하여 각 픽셀에서 깊이 순으로 최대 6개의 surface를 순차 추출하는 시스템을 구현했습니다. 이는 기존에 OpenGL/DirectX에서 사용되던 기법을 Unity 환경에 성공적으로 이식한 사례입니다.
기술적 도전: Render Graph의 지연 실행 특성으로 인한 Material Property 바인딩 문제를 Global Shader Property로 해결했습니다. 최대 15번의 texture read per pixel이 발생하지만 효율적인 GPU 메모리 접근 패턴으로 VR 성능 요구사항을 충족시켰습니다.
// 점진적 깊이 추출 핵심 로직
for(int i = 0; i < currentLayerIndex; i++) {
float prevDepth = SampleDepthFromLayer(i, screenUV);
if(input.linearDepth <= prevDepth + epsilon) discard;
}
C#
복사
하이브리드 물리 시스템: 성능과 정확성의 균형
처음 시도했던 Position Based Dynamics는 물리적으로 정확했지만 VR의 90fps 요구사항을 만족시킬 수 없었습니다. "스플라인에서 메쉬를 생성하는 비용이 더 싼데?"라는 발견에서 시작되었습니다.
핵심 아이디어: 제어점 그리드에서만 물리 연산을 수행하고, Bicubic 보간으로 전체 메쉬를 실시간 생성하는 하이브리드 접근법을 개발했습니다. 이를 통해 기존 방식 대비 100배 성능 향상을 달성했습니다.
최적화 경험: 프로파일러를 통해 313,920번의 중복 연산을 발견하고, 캐싱과 Compute Shader를 활용해 1277ms에서 14ms로 극적인 성능 개선을 달성했습니다. 이 과정에서 GPU 병렬 연산의 효율성을 체감할 수 있었습니다.
// 제어점 기반 실시간 메쉬 생성
void RegenerateMesh() {
for (int h = 0; h < heightSteps; h++) {
for (int c = 0; c < circumSteps; c++) {
Vector3 position = BicubicInterpolation(controlPoints, h, c);
vertices[index] = position;
}
}
}
C#
복사
물리 기반 렌더링: Beer's Law와 흑체복사 구현
정확한 두께 정보를 바탕으로 실제 유리의 광학적 특성을 시뮬레이션했습니다. 단순한 시각적 효과가 아닌, 물리 법칙에 기반한 현실적 표현을 구현하는 것이 목표였습니다.
Beer's Law 구현: 두께에 따른 광 흡수를 정확히 계산하여 얇은 부분은 투명하고, 두꺼운 부분은 진한 색상을 나타내도록 했습니다. 이를 통해 실제 유리와 같은 두께감을 부여했습니다.
float3 CalculateAbsorption(float thickness, float3 transmissionColor) {
float normalizedThickness = thickness / _ThicknessScale;
float absorptionDistance = pow(normalizedThickness * _AbsorptionIntensity + 1.0, _AbsorptionPower);
// Beer's Law: I = I₀ * e^(-αx)
float3 absorptionAmount = (1.0 - _GlassColor.rgb) * absorptionDistance;
return max(transmissionColor - absorptionAmount, 0.0);
}
C#
복사
흑체복사 시스템: 온도에 따른 발광 효과를 플랑크 법칙 기반으로 구현하여 물리적 정확성과 시각적 아름다움 사이의 균형을 맞췄습니다. 다층 굴절 시스템과 결합하여 현실적인 광학 효과를 완성했습니다.