Search Unity

[Oculus Go] Cubemap reflections for Single-Pass Multi-View

Discussion in 'AR/VR (XR) Discussion' started by JoeyStage, Oct 10, 2018.

  1. JoeyStage

    JoeyStage

    Joined:
    Aug 8, 2018
    Posts:
    3
    I've created a Surface shader in Unity that involves sampling from a cubemap. I am working on the Oculus Go with Single-Pass Multi-View rendering enabled. But in-game the cubemap looks as if it was just a completely flat texture applied to the surface with no stereo-depth to it(With generally "correct" cube-map samples but applied to the surface as if it was just a "_MainTex"). But when I apply a "Standard" shader on one of the meshes to the scene, the cubemap reflections appear to work where the view-direction of each eye is being accounted for during the reflection vector calculation and the reflection has proper "depth". I've downloaded the built-in shaders from the unity download page to see if i can dissect if I am doing anything wrong and followed the standard shaders setup but nothing stood out to me.

    The reflections appear to work fine when ran on the desktop using an Oculus rift, when Multi-Pass is enabled on the Oculus Go, or when I use one of the unity "Standard" shaders but not when I use my surface shader. Is there a flag or variable or variant flag or something I'm missing?

    Here's some key parts of my shader with some attempts to get it to retrieve stereo per-eye vectors.

    Code (CSharp):
    1.  
    2.     SubShader
    3.     {
    4.         Tags { "RenderType" = "Opaque" }
    5.         LOD 250
    6.         Cull Back
    7.         CGPROGRAM
    8.         #pragma target 4.0
    9.         #pragma surface surf BlinnPhong vertex:vert noforwardadd nodynlightmap nofog noshadow
    10.         #pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_MULTIVIEW_ON STEREO_CUBEMAP_RENDER_ON STEREO_INSTANCING_ON
    11.         #pragma multi_compile_instancing
    12.         #pragma multi_compile_fwdbase
    13.         #include "UnityCG.cginc"
    14. ...
    15.         struct Input
    16.         {
    17.             float2 uv_MainTex;
    18.             float2 uv_BumpMap;
    19.             float2 uv_Glossiness;
    20.             float3 worldPos;
    21.             float worldNormal;
    22.             float3 worldRefl;
    23.             INTERNAL_DATA
    24.             float3 viewDir;
    25.             UNITY_VERTEX_OUTPUT_STEREO
    26.         };
    27.  
    28.         void vert (inout appdata_full v, out Input o) {
    29.             UNITY_INITIALIZE_OUTPUT(Input,o);
    30.             UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    31.         }
    32. ...
    33.         void surf (Input IN, inout SurfaceOutput o)
    34.         {
    35.             UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN)
    36.             fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
    37.             fixed4 glossTex = tex2D(_Glossiness, IN.uv_Glossiness);
    38.             o.Albedo = tex.rgb;
    39.             o.Gloss  = glossTex * _GlossinessPower;
    40.             o.Alpha  = tex.a;
    41.             o.Specular = _Specularity;
    42.             o.Normal = UnpackScaleNormal(
    43.                 tex2D(_BumpMap, IN.uv_BumpMap),
    44.                 _BumpPower
    45.             );
    46.  
    47.             const float3 ReflectionDirection = BoxProjectedCubemapDirection(
    48.                 WorldReflectionVector(IN, o.Normal).xyz,
    49.                 IN.worldPos,
    50.                 unity_SpecCube0_ProbePosition,
    51.                 unity_SpecCube0_BoxMin,
    52.                 unity_SpecCube0_BoxMax
    53.             );
    54.  
    55.             const float4 ProbeColor = UNITY_SAMPLE_TEXCUBE_LOD(
    56.                 unity_SpecCube0,
    57.                 ReflectionDirection,
    58.                 UNITY_SPECCUBE_LOD_STEPS * (o.Gloss + _ReflectionBlurBoost)
    59.             );
    60.  
    61.             o.Emission = ProbeColor * _ReflectionPower;
    62.         }
    I also notice that in the compiled shader in the "STEREO_MULTIVIEW_ON" variant, it seems to always use matrices from the left eye(0). Is this possibly a unity bug?

    Code (CSharp):
    1.  
    2. ...
    3. -- Hardware tier variant: Tier 3
    4. -- Fragment shader for "gles3":
    5. Shader Disassembly:
    6. // All GLSL source is contained within the vertex program
    7.  
    8. //////////////////////////////////////////////////////
    9. Keywords set in this variant: DIRECTIONAL STEREO_MULTIVIEW_ON
    10. -- Hardware tier variant: Tier 1
    11. -- Vertex shader for "gles3":
    12. Shader Disassembly:
    13. #ifdef VERTEX
    14. #version 300 es
    15. ...
    16.     u_xlat0.y = vs_TEXCOORD3.w;
    17.     u_xlat0.z = vs_TEXCOORD4.w;
    18.     u_xlat1.xyz = (-u_xlat0.xyz) + unity_StereoWorldSpaceCameraPos[0].xyz; // <<< It's always sampling the left eye???
    19.     u_xlat30 = dot(u_xlat1.xyz, u_xlat1.xyz);
    20.     u_xlat30 = inversesqrt(u_xlat30);
    21. ...
    22.  
     
    Last edited: Oct 10, 2018
  2. JoeyStage

    JoeyStage

    Joined:
    Aug 8, 2018
    Posts:
    3
    Wanted to update and say that when I compile the unity standard shader, it seems to properly get the correct camera position and uses the correct stereo index. Why is my shader not using this and how would i get it to properly work for stereo?
    Code (CSharp):
    1.  
    2. //////////////////////////////////////////////////////
    3. Keywords set in this variant: DIRECTIONAL STEREO_MULTIVIEW_ON
    4. -- Hardware tier variant: Tier 1
    5. -- Vertex shader for "gles3":
    6. Shader Disassembly:
    7. #ifdef VERTEX
    8. #version 300 es
    9. #extension GL_OVR_multiview2 : require
    10. ...
    11.     u_xlat0.xyz = hlslcc_mtx4x4unity_ObjectToWorld[3].xyz * in_POSITION0.www + u_xlat0.xyz;
    12.     u_xlatu9 = gl_ViewID_OVR; // < Why isnt my surface shader using this?
    13.     vs_TEXCOORD1.xyz = u_xlat0.xyz + (-unity_StereoWorldSpaceCameraPos[int(u_xlatu9)].xyz);
    14.     vs_TEXCOORD8.xyz = u_xlat0.xyz;
    15.     vs_BLENDWEIGHT0 = unity_StereoEyeIndices[int(u_xlatu9)].x; // << Gets the correct eye?
     
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I don't know the answer — I'm terrible at shaders — but wanted to make sure you've seen this page of the docs. Might there be something helpful there?
     
  4. JoeyStage

    JoeyStage

    Joined:
    Aug 8, 2018
    Posts:
    3
    I practically have this page on my bookmarks and just about every tutorial out there seems to go right to going to totally custom shaders rather than standard/surface shaders.
    I feel like this may be a bug on unity's part as the consistent compiled-shader output seems to always use stereo index 0 when compiling multi-view shaders but I did find a way to bypass this issue by passing in the world camera position to the fragment shader by adding another field in the input struct and conditionally writing the correct camera position to it from within the vertex shader.
    Code (CSharp):
    1.         struct Input
    2.         {
    3. ...
    4.             float3 WorldCameraPos;
    5.         };
    6.  
    7.         void vert (inout appdata_full v, out Input o) {
    8. ...
    9.             #if STEREO_MULTIVIEW_ON
    10.             o.WorldCameraPos = unity_StereoWorldSpaceCameraPos[unity_StereoEyeIndex];
    11.             #else
    12.             o.WorldCameraPos = _WorldSpaceCameraPos.xyz;
    13.             #endif
    14. ...
    15.  
    16.         void surf (Input IN, inout SurfaceOutput o)
    17.         {
    18. ...
    19.             const float3 worldRefl = -reflect(
    20.                 IN.WorldCameraPos - IN.worldPos.xyz,
    21.                 WorldNormalVector(IN,o.Normal)
    22.             );
    23. ...
    24.         }
     
    JoeStrout likes this.