*개요
Unity 2021.2.4f1 기준 URP에서 기존 빌트인 처럼 쉐이더에서 Grabpass가 불가능해졌습니다.
그래서 아래 포스팅과 같이 렌더파이프라인에서 생성된 _CameraOpaqueTexture를 참조해서 Grabpass를 구현할 수 있습니다.
https://chulin28ho.tistory.com/555
하지만 URP 내부적으로 불투명 오브젝트만 캡처하여 반투명 오브젝트는 Grabpass에 렌더링되지 않는 이슈가 있습니다.
이번 포스팅은 커스텀 렌더피쳐를 기반으로 반투명 Grabpass 구현하는 법에 대해 작성하겠습니다.
프리뷰
샘플 프로젝트
Unity 2021.2.4f1 URP에서 구현
https://github.com/CatDarkGame/CustomGrabPassFeature
테스트 이력
- iPhone12 Mini (Metal)
- Galaxy s10e (ARM)
프로젝트 세팅 방법
샘플 프로젝트가 아닌 신규 & 다른 프로젝트에서 해당 렌더 피쳐 적용에서 쉐이더 사용방법까지 작성합니다.
1. 렌더 피쳐 세팅
렌더 피쳐 세팅에 앞서 먼저 Grabpass 타겟 오브젝트 전용 레이어를 하나 생성합니다.
- Grabpass 타겟 오브젝트 = 굴절효과 적용할 오브젝트
다음 RendererData파일에서 아래 세팅을 합니다.
- Opaque & Transparent Layer Mask에서 이전에 추가한 레이어 제외.
- Intermediate Texture를 Always로 설정.
- Render Feature에 Custom Grab Pass Feature 추가.
CustomGrabPassFeature 옵션 설명
1. 쉐이더에서 참조할 그랩패스 텍스처 Global Property 이름.
2. 그랩패스 실행할 렌더 순서 설정.
3. 그랩패스 텍스처 샘플링 설정.
4. 타겟 오브젝트 레이어 설정.
5. 타겟 오브젝트 쉐이더 태그 설정.(해당 ShaderTag를 가진 쉐이더만 렌더링)
2. Shader Graph 기반 굴절 쉐이더 구현
기존 _CameraOpaqueTexture방식과 비슷하게 Texture2D변수를 생성 후 렌더피쳐에서 설정한 PropertyName을 Reference에 세팅합니다.
그리고 Screen Position을 UV에 넣으면 그랩패스 텍스처가 렌더링됩니다.(Exposed는 체크 해제)
아래는 간단한 굴절 쉐이더 전체 노드입니다.
추가 세팅
- SurfaceType : Transparent
- Blending Mode : Alpha
3. HLSL(코드)기반 굴절 쉐이더 구현
// Global Texture Property
sampler2D _CustomCameraTexture;
//sampler2D _CameraOpaqueTexture; // 만약 기존 Opaque방식을 사용하면 이 변수를 사용
// GrapPass
float4 grabPassUV = i.screenPosition;
grabPassUV.xy += noise * _NoiseIntensity;
float4 grabPass = tex2Dproj(_CustomCameraTexture, grabPassUV);
// float4 grabPass = tex2Dproj(_CameraOpaqueTexture, grabPassUV);
(전체 코드는 git에서 SimpleDistortion.shader를 확인해주세요.)
HLSL도 마찬가지로 Global Property변수를 받아서 그랩패스 렌더링 가능합니다.
4. 오브젝트에 쉐이더 적용
굴절 효과를 적용할 오브젝트의 레이어를 Distort로 세팅하고 마테리얼을 적용하면 끝.
구현 과정 & 원리
기본적으로 아래 git자료를 기반으로 분석해서 구현했습니다.
https://gist.github.com/Refsa/54da34a9e2fc8e45472286572216ad17
카메라 렌더 텍스처를 TempRT와 Pass에 렌더링
먼저 카메라의 렌더링 데이터를 TempRT와 Pass에 등록하는 과정입니다.
1. TempRT 다운샘플링하여 필요하면 렌더텍스처 용량을 최적화 할 수 있습니다.
2. 임시 RT를 생성하고 GlobalTextureProperty에 등록하여 쉐이더가 렌더텍스처를 참조할 수 있도록 합니다.
3. 생성된 커스텀 Pass에 카메라 데이터를 렌더링합니다.
TempRT관련
RenderData에서 Intermediate Texutre옵션이 만약 Auto로 되어 있다면 TempRT가 검은색으로 나오는 이슈가 있습니다.
Intermediate Texture을 번역하면 중간 텍스처라고 하는데 TemporaryRT처럼 임시 렌더 텍스처를 의미하는것 같습니다.
위 유니티 도큐먼트를 보면 Auto 옵션을 선택하면 인증된 중간 텍스처 외에 렌더링하지 않는다고 되어 있습니다, 이것이 원인으로 추측되는데 해당 문서에 나온데로 ConfigureInput을 호출했지만 효과는 없었습니다.
해당 옵션이 성능 부분에서 빈 프로젝트에서는 차이는 없으니 일단 Always로 세팅합니다.
타겟 오브젝트 필터링
Grabpass이후 렌더링되는 Pass입니다.
단순히 타겟 오브젝트를 Grabpass 다음으로 렌더링하는 역할을 합니다.
타겟 오브젝트를 Grabpass 다음에 렌더링해야하는 이유
카메라의 렌더링 데이터를 가져오는 과정에서, 타겟 오브젝트가 앞을 가리면 아래 처럼 거울 효과와 뒤가 제대로 그려지지 않는 이슈가 발생합니다.
그래서 타겟 오브젝트를 메인 렌더링에서 제외하고 FilteredRenderPass를 통해 Grabpass 다음으로 렌더링해야합니다.
Grabpass 타겟 오브젝트는 맨위에 렌더링될 수 밖에 없는 이슈
타겟 오브젝트가 가장 마지막에 렌더링되는 이유로 항상 앞에 렌더링 될 수 밖에 없는 이슈가 있습니다.
해당 이슈를 해결하기 위해서는 이 포스팅에서 소개하는 렌더피쳐 방식이 아닌 다른 방식으로 구현해야 할 것 같습니다.
가능성있는 방법으로는, URP 내부 코드에서 _CameraOpaqueTexture를 AfterRenderingTransparent로 변경하면 될 것 같습니다.(안해봄)
ShaderTagString 필터 설명
LayerMask로 필터하는것과 같이 렌더피쳐의 ShaderTagStrings에 포함된 태그를 가진 쉐이더만 FilteredRenderPass에 렌더링됩니다.
만약 신규 커스텀 쉐이더를 제작할때 그랩패스를 사용하고 싶으면 태그 맞춰줘야합니다.
성능 프로파일링
기존 _CameraOpaqueTexture 방식과 GPU 프로파일링을 통해 성능 비교를 했습니다.
GPU 성능 측정이 핵심이기 때문에 동일한 환경에 해상도만 변경해서 측정했습니다.
측정 환경
- iPhone12 Mini (Metal)
- Xcode GPU FrameCapture
Total GPU ms | Total Memory | Copycolor / Grabpass | target rendering ms | RT Size (4x bilinear) |
|
Opaque 720p | 6.78ms | 99.9mb | 0.052ms | 1.08ms | 256kb |
Opaque 1080p | 10.53ms | 210.4mb | 0.111ms | 1.85ms | 656kb |
Transparent 720p | 6.86ms | 99.9mb | 0.048ms | 1.12ms | 256kb |
Transparent 1080p | 9.89ms | 210.4mb | 0.079ms | 1.72ms | 656kb |
- 측정결과 유의미한 차이가 없습니다.
'Unity > Shader & VFX' 카테고리의 다른 글
유니티 빌보드 쉐이더 구현 & 분석 (1) | 2022.11.04 |
---|---|
털(Fur) 쉐이더 R&D - 로스트아크에서 털 표현하는 방법 (0) | 2022.11.01 |
[Tutorial] Hexagon Barrier (0) | 2020.02.14 |
Vertex Fragment - Shadow Receive & Cast (0) | 2020.02.12 |
[Stencil] 3D 영정사진 (0) | 2020.02.10 |
WRITTEN BY
- CatDarkGame
Technical Artist dhwlgn12@gmail.com