WinCNT

Meta Quest 2에서 오른쪽 스크린만 일부 오브젝트의 드로우 처리가 안 되거나 색상이 이상해지는 이슈 본문

Unity/Unity 개발 중 발생한 이슈 정리

Meta Quest 2에서 오른쪽 스크린만 일부 오브젝트의 드로우 처리가 안 되거나 색상이 이상해지는 이슈

WinCNT_SSS 2023. 9. 12. 11:21

발생한 이슈

유니티의 에디터 상에서는 문제 없는 것처럼 보이는데, VR기기(Meta Quest2)에서는 일부 오브젝트의 드로우 처리가 이상하지는 이슈가 발생했다

가장 큰 문제는 왼쪽은 문제 없는데 오른쪽 화면만 이상해진다는 것이었다


이슈 상세

환장하게도 VR기기에서 캡처를 해도 딱히 문제 없이 나와서 이번에는 에비던스도 없다…

에비던스 없이 글로만 쓰면 뭔가 거짓말 치는 느낌이 들긴 하는데 어쩔 수 없지

 

아무튼 일어났던 문제점을 대충 정리하자면 다음과 같다

우선 Nova Shader로 만든 특정 이펙트가 왼쪽으로 고개를 기울이면 오른쪽 화면에서 드로잉되지 않는 이슈가 발생했다

그리고 드로잉되는 상태에서도 지면에 있을 이펙트가 공중에 떠보인다는 위화감도 존재했다

(참고로 한쪽 눈으로만 보면 위화감이 사라졌기에 연관이 있는 이슈라고 판단함)

 

해당 이슈는 전혀 상관 없는 다른 셰이더의 에러를 수정하니 없어졌다

그런데 이제는 수정한 셰이더 쪽에서 비슷한 현상이 발생했다!

이번에는 오른쪽 화면에서 일부 오브젝트의 출력 색상이 달랐다

(자세히는 모르지만 왠지 림라이트가 강하게 출력되는 느낌이었다)


발생 원인

발생 원인은 크게 2가지로 볼 수 있었다

한 가지는 원인은 특정했는데 어떠한 원리로 이슈가 발생했는지 알 수가 없었고, 다른 한 가지는 원인은 둘째치고 헷갈릴 수 밖에 없는 명칭으로 삽질을 유도하고 있었다

 

하나씩 살펴보자

1. Nova Shader로 만든 특정 이펙트가 왼쪽으로 고개를 기울이면 오른쪽 화면에서 드로잉되지 않는 이슈의 원인

이쪽이 특정했는데 어떠한 원리로 이슈가 발생했는지 알 수가 없었던 원인이다

일단 문제가 되었던 건 #include <HLSLSupport.cginc>였다

HLSLSupport.cginc는 유니티의 셰이더가 CG언어에 대한 호환성을 위한 파일인 것 같다

Unity의 HLSL - Unity 매뉴얼

 

Unity의 HLSL - Unity 매뉴얼

Unity에서는 HLSL 프로그래밍 언어를 사용하여 셰이더 프로그램을 작성합니다.

docs.unity3d.com

 

CGPROGRAM / ENDCG를 사용하면 자동으로 HLSLSupport.cginc가 포함된다고 하는데 URP에서는 충돌이 발생할 수 있으니 사용을 자제하라는 말도 있다

https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@12.1/manual/writing-shaders-urp-basic-unlit-structure.html#subshader

 

URP unlit basic shader | Universal RP | 12.1.12

URP unlit basic shader This example shows a basic URP-compatible shader. This shader fills the mesh shape with a color predefined in the shader code. To see the shader in action, copy and paste the following ShaderLab code into the Shader asset. // This sh

docs.unity3d.com

 

아무튼 이번에 대응하고 있던 셰이더는 HLSLPROGRAM / ENDHLSL였음에도 불구하고 명시적으로 HLSLSupport.cginc를 포함하고 있었다 필자가 한 거 아님

 

멀쩡한 URP 셰이더에 HLSLSupport.cginc를 추가하면 에러나 경고가 발생한다

처음에는 안 나와도 Compile and show code를 누르거나 빌드하면 발생하며, HLSLSupport.cginc의 위치에 따라서는 에러는 안 나오고 경고만 나올 수도 있다

 

그래서 일단 해당 에러를 해결하자는 마인드로 필요도 없던 HLSLSupport.cginc를 삭제하니 왜인지는 모르겠지만 전혀 상관도 없던 Nova Shader로 만든 이펙트가 정상적으로 작동했다(왜?)

반대로 이펙트에 사용되던 Nova Shader에 HLSLSupport.cginc를 추가해보니 그것도 정상적으로 작동했다…

 

2. 오른쪽 화면에서 일부 오브젝트의 출력 색상이 다른 이슈의 원인

이번 이슈의 최종적인 원인은 이쪽으로 생각된다

결론부터 말하자면 싱글 패스 인스턴스화 렌더링에 관련 문제였다(아마…)

 

초기 VR은 한쪽 스크린을 먼저 그리고 다른 쪽은 그 뒤에 그리는 방식이었으며 이를 멀티 패스 렌더링이라고 불렀다

하지만 최근의 VR은 양쪽 스크린을 동시에 그리는 게 일반적인데 이를 싱글 패스 인스턴스화 렌더링이라고 한다

싱글 패스 스테레오 렌더링(더블 와이드 렌더링) - Unity 매뉴얼

 

싱글 패스 스테레오 렌더링(더블 와이드 렌더링) - Unity 매뉴얼

싱글 패스 스테레오 렌더링 은 PC 및 Playstation 4 기반 VR 애플리케이션의 기능입니다. 이 기능은 왼쪽 및 오른쪽 눈 이미지를 너비가 한쪽 눈 텍스처의 두 배인 패킹된 단일 렌더 텍스처로 동시에

docs.unity3d.com

그걸 좀 더 최적화한 것이 싱글 패스 인스턴스화 렌더링라고 한다

싱글 패스 인스턴스화 렌더링 - Unity 매뉴얼

 

싱글 패스 인스턴스화 렌더링 - Unity 매뉴얼

Single Pass Instanced 렌더링(’스테레오 인스턴싱’이라고도 불림)을 사용하면 GPU가 단일 렌더 패스를 수행하여 각 드로우 콜을 인스턴스화된 드로우 콜로 교체합니다. 이렇게 하면 두 드로우 콜 간

docs.unity3d.com

 

그런데 이게 명칭이 통일되어 있는 건 아니라서 플랫폼에 따라서 다르게 불리기도 한다

더 빡치는 건 Oculus(Android)의 경우 멀티 패스와 멀티 뷰라는 얼핏 보면 같은 것으로 생각되는 명칭을 붙여놓았다

필자도 한창 삽질하던 때에 위의 설정이나 UNITY_STEREO_MULTIVIEW_ENABLED에 대해서 몇 번이나 찾아봤지만 명칭이 비슷해서 헛다리 짚었나 싶어서 추가 조사를 하지 않았었다

하지만 싱글 패스 인스턴스화 렌더링을 위한 셰이더 코드 중 하나를 추가하니 이슈가 해결되었다

도대체 왜?!


해결법

1. Nova Shader로 만든 특정 이펙트가 왼쪽으로 고개를 기울이면 오른쪽 화면에서 드로잉되지 않는 이슈

#include <HLSLSupport.cginc>를 삭제하는 쪽으로 대응했다

사실 HLSLSupport도 어느 변수가 fixed4이라 사용됐을 뿐, 그 외는 필요도 없기에 바로 삭제했다

 

2. 오른쪽 화면에서 일부 오브젝트의 출력 색상이 다른 이슈의 원인

유니티의 공식 문서에 싱글 패스 인스턴스화 렌더링을 위한 셰이더 코드 샘플이 있다

싱글 패스 인스턴스화 렌더링 - Unity 매뉴얼

 

싱글 패스 인스턴스화 렌더링 - Unity 매뉴얼

Single Pass Instanced 렌더링(’스테레오 인스턴싱’이라고도 불림)을 사용하면 GPU가 단일 렌더 패스를 수행하여 각 드로우 콜을 인스턴스화된 드로우 콜로 교체합니다. 이렇게 하면 두 드로우 콜 간

docs.unity3d.com

Android용 싱글 패스 스테레오 렌더링 - Unity 매뉴얼

 

Android용 싱글 패스 스테레오 렌더링 - Unity 매뉴얼

Unity는 멀티뷰를 지원하는 Android 기기용 싱글 패스 스테레오 렌더링을 지원합니다. 멀티뷰는 GL_OVR_multiview2와 GL_OVR_multiview_multisampled_render_to_texture OpenGL ES 확장자로 구성됩니다. 이러한 확장자에

docs.unity3d.com

우선 버텍스 셰이더의 인풋 데이터에 UNITY_VERTEX_INPUT_INSTANCE_ID를 추가한다

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;

    UNITY_VERTEX_INPUT_INSTANCE_ID // 이거 추가
};

마찬가지로 버텍스 셰이더의 아웃풋 데이터에 UNITY_VERTEX_OUTPUT_STEREO를 추가한다

struct v2f
{
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;

    UNITY_VERTEX_OUTPUT_STEREO // 이거 추가
};

버텍스 셰이더에도 추가할 코드가 있다

v2f vert (appdata v)
{
    v2f o;
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert
}

보통은 여기서 끝인 것 같은데 마지막으로 프래그먼트 셰이더에도 추가 한 줄 추가해야 한다

fixed4 frag (v2f i) : SV_Target
{
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
}

 

UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX를 추가해야 unity_StereoEyeIndex라는 변수를 사용할 수 있고 포스트 프로세싱인 경우는 필수인 것 같다

이번에 이슈가 발생한 프로젝트는 소화 요원으로 잠깐 참가한 것 뿐이라 잘은 모르지만, 프레임 디버그의 가장 마지막에 UPR의 Uber 셰이더에 의한 포스트 프로세싱 항목이 있었으니 사용은 되고 있는 것으로 생각된다(별다른 처리는 없었지만)

 

그래서 이쪽에 영향을 미친 것이 아닐까 추측이 무성할 뿐이다…

일단 참고가 될만한 사이트를 찾았으니 다음에 읽어보자

Unity の XR 向けシングルパスステレオレンダリングについて調べてみた - 凹みTips

 

Unity の XR 向けシングルパスステレオレンダリングについて調べてみた - 凹みTips

はじめに Unity での XR Settings に含まれる Stereo Rendering Method ですが、みなさんは理解されていますか?ちなみに私は理解していませんでした。。 なんとなく マルチパス は遅くて シングルパス

tips.hecomi.com

아무튼 이번에 발생한 이슈는 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX 한 줄을 추가하니 해결되었다

 

사족으로 딱히 검증한 것은 아니지만 Multiview를 설정하면 빌드 시에 UNITY_SINGLE_PASS_STEREO나 UNITY_STEREO_MULTIVIEW_ENABLED같은 키워드가 추가되는 게 아닐까 싶다


마무리

만 하루를 나랑 동료 한 명이 삽질하면서 어떻게든 해결한 이슈였다

사실 직접적인 해결책을 찾은 건 동료였다

셰이더를 잘 모르는데도 코드를 하나 하나 코멘트하고 빌드하는 식으로 찾아내곤 했다

정말 존경스럽…


참고 자료

싱글 패스 스테레오 렌더링(더블 와이드 렌더링) - Unity 매뉴얼

 

싱글 패스 스테레오 렌더링(더블 와이드 렌더링) - Unity 매뉴얼

싱글 패스 스테레오 렌더링 은 PC 및 Playstation 4 기반 VR 애플리케이션의 기능입니다. 이 기능은 왼쪽 및 오른쪽 눈 이미지를 너비가 한쪽 눈 텍스처의 두 배인 패킹된 단일 렌더 텍스처로 동시에

docs.unity3d.com

싱글 패스 인스턴스화 렌더링 - Unity 매뉴얼

 

싱글 패스 인스턴스화 렌더링 - Unity 매뉴얼

Single Pass Instanced 렌더링(’스테레오 인스턴싱’이라고도 불림)을 사용하면 GPU가 단일 렌더 패스를 수행하여 각 드로우 콜을 인스턴스화된 드로우 콜로 교체합니다. 이렇게 하면 두 드로우 콜 간

docs.unity3d.com

Android용 싱글 패스 스테레오 렌더링 - Unity 매뉴얼

 

Android용 싱글 패스 스테레오 렌더링 - Unity 매뉴얼

Unity는 멀티뷰를 지원하는 Android 기기용 싱글 패스 스테레오 렌더링을 지원합니다. 멀티뷰는 GL_OVR_multiview2와 GL_OVR_multiview_multisampled_render_to_texture OpenGL ES 확장자로 구성됩니다. 이러한 확장자에

docs.unity3d.com

Question - No single pass or single pass instanced option for Oculus quest

 

Question - No single pass or single pass instanced option for Oculus quest

Hello, I have enabled the Oculus plug-in and i just can choose multi pass or multiview, there is not single pass instanced for Oculus quest or Oculus...

forum.unity.com

Universal Render Pipeline(URP)乗り換えハマりポイントまとめ

 

Universal Render Pipeline(URP)乗り換えハマりポイントまとめ

バッジを贈って著者を応援しよう バッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。 バッジを贈る

zenn.dev

Unity の XR 向けシングルパスステレオレンダリングについて調べてみた - 凹みTips

 

Unity の XR 向けシングルパスステレオレンダリングについて調べてみた - 凹みTips

はじめに Unity での XR Settings に含まれる Stereo Rendering Method ですが、みなさんは理解されていますか?ちなみに私は理解していませんでした。。 なんとなく マルチパス は遅くて シングルパス

tips.hecomi.com