Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Stereo geometry shader for pointclouds

Discussion in 'AR/VR (XR) Discussion' started by tfrantz, Jul 27, 2020.

  1. tfrantz

    tfrantz

    Joined:
    Dec 7, 2017
    Posts:
    7
    I'm working with in VR/AR and and streaming point cloud data to the device. I have a geometry shader which takes each vertex and draws a white triangle around it. In the editor this works well, however on the device it's only rendered on the left display. The rest of the scene is rendered left and right. Unity is using Single Pass Instanced Rendering Mode.

    I initially tried flowing Unity's guide however that didn't help get the right display rendering.
    https://docs.unity3d.com/2018.3/Documentation/Manual/SinglePassStereoRenderingHoloLens.html

    I've also followed the advice on this thread, however, it doesn't seem to help.
    https://forum.unity.com/threads/how...rendering-with-custom-geometry-shader.543049/

    I'm basing my shader on the following source, however this is not set up for stereo.
    https://answers.unity.com/questions/1437520/implementing-a-geometry-shader-for-a-pointcloud.html

    Any help would be great!
    Am I not handeling the instancing correctly?

    Code (CSharp):
    1. Shader "Custom/PointCloud" {
    2.     Properties{
    3.         _Radius("Sphere Radius", float) = 0.005
    4.     }
    5.  
    6.         SubShader{
    7.         LOD 200
    8.         Tags { "RenderType" = "Opaque" }
    9.         Pass
    10.         {
    11.         Cull Off
    12.         CGPROGRAM
    13.         #pragma vertex vertex_shader
    14.         #pragma geometry geometry_shader
    15.         #pragma fragment fragment_shader
    16.         #pragma target 5.0
    17.         #pragma only_renderers d3d11
    18.         #include "UnityCG.cginc"
    19.  
    20.         // Variables
    21.         float _Radius;
    22.  
    23.         // VERTEX DATA
    24.         struct appData {
    25.             float4 pos : POSITION;
    26.             UNITY_VERTEX_INPUT_INSTANCE_ID
    27.         };
    28.  
    29.         // GEOMETRY DATA
    30.         struct v2g {
    31.             float4 pos : SV_POSITION;
    32.             float4 color : COLOR0;
    33.             float3 normal : NORMAL;
    34.             float r : TEXCOORD0;
    35.             UNITY_VERTEX_INPUT_INSTANCE_ID
    36.         };
    37.  
    38.         // FRAGMENT DATA
    39.         struct g2f {
    40.             float4 pos : POSITION;
    41.             float4 color : COLOR0;
    42.             float3 normal : NORMAL;
    43.             UNITY_VERTEX_OUTPUT_STEREO
    44.         };
    45.  
    46.         // FUNCTION: Calculate "random" number
    47.         float rand(float3 p) {
    48.             return frac(sin(dot(p.xyz, float3(12.9898, 78.233, 45.5432))) * 43758.5453);
    49.         }
    50.  
    51.         // FUNCTION: Calculate rotation
    52.         float2x2 rotate2d(float a) {
    53.             float s = sin(a);
    54.             float c = cos(a);
    55.             return float2x2(c, -s, s, c);
    56.         }
    57.  
    58.         // VERTEX SHADER: computes normal wrt camera
    59.         v2g vertex_shader(appData v) {
    60.  
    61.             // Output struct to geometry shader
    62.             v2g o;
    63.  
    64.             // For single passed stereo rendering
    65.             UNITY_SETUP_INSTANCE_ID(v);
    66.             UNITY_TRANSFER_INSTANCE_ID(v, o);
    67.  
    68.             // Output clipping position
    69.             o.pos = UnityObjectToClipPos(v.pos);
    70.  
    71.             // Distance from vertex to camera
    72.             float distance = length(WorldSpaceViewDir(v.pos));
    73.  
    74.             // White
    75.             o.color = float4(1, 1, 1, 1);
    76.  
    77.             // Normal facing camera
    78.             o.normal = ObjSpaceViewDir(v.pos);
    79.  
    80.             // Calc random value based on object space pos
    81.             o.r = rand(v.pos);
    82.  
    83.             return o;
    84.         }
    85.  
    86.  
    87.         // GEOMETRY SHADER: Creates an equilateral triangle centered at vertex
    88.         [maxvertexcount(3)]
    89.         void geometry_shader(point v2g i[1], inout TriangleStream<g2f> triangleStream)
    90.         {
    91.             UNITY_SETUP_INSTANCE_ID(i);
    92.  
    93.             // Dimention of geometry
    94.            float2 dim = float2(_Radius, _Radius);
    95.  
    96.            // Create equilateral triangle
    97.            float2 p[3];
    98.            p[0] = float2(-dim.x, dim.y * .57735026919);
    99.            p[1] = float2(0., -dim.y * 1.15470053838);
    100.            p[2] = float2(dim.x, dim.y * .57735026919);
    101.  
    102.            // Get the rotation from random vert input
    103.            float2x2 r = rotate2d(i[0].r * 3.14159);
    104.  
    105.            // Output struct
    106.            g2f o;
    107.            o.color = i[0].color;
    108.            o.normal = i[0].normal;
    109.  
    110.            // Update geometry
    111.            [unroll]
    112.            for (int idx = 0; idx < 3; idx++) {
    113.                p[idx] = mul(r,p[idx]);    // apply rotation
    114.                p[idx].x *= _ScreenParams.y / _ScreenParams.x; // make square
    115.                o.pos = i[0].pos + float4(p[idx],0,0) / 2.;
    116.                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    117.                triangleStream.Append(o);
    118.            }
    119.  
    120.         }
    121.  
    122.         // FRAGMENT SHADER
    123.         float4 fragment_shader(g2f i) : COLOR
    124.         {
    125.             // Use vertex color
    126.             return i.color;
    127.         }
    128. ENDCG
    129. }
    130.     }
    131.         FallBack "Diffuse"
    132. }
     
  2. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    98
    I have gathered from Unitys documentation https://docs.unity3d.com/Manual/SinglePassInstancing.html, the thread https://forum.unity.com/threads/how...rendering-with-custom-geometry-shader.543049/ you listed and the file "Unity\2020.1.0f1\Editor\Data\CGIncludes\UnityInstancing.cginc" that:

    legend:

    name of type of variable for output from shader =
    s

    name of variable for input to shader, possibly a list item =
    i

    name of variable for output from shader =
    o

    1. add
      UNITY_VERTEX_INPUT_INSTANCE_ID
      to every shader input data structure before the fragments shader input data structure
    2. add
      UNITY_VERTEX_OUTPUT_STEREO
      to the fragments shader input data structure
    3. call
      UNITY_SETUP_INSTANCE_ID(i)
      at the very beginning of the vertex shader
    4. do
      UNITY_INITALIZE_OUTPUT(s, o);
      directly after every shader output structure variable declaration [unrelated to XR, this applies always I guess]
    5. call
      UNITY_TRANSFER_INSTANCE_ID(i, o);
      after
      UNITY_INITALIZE_OUTPUT(s, o);
      beginning with the vertex shader all the way through hull, domain to geometry shader
    6. call
      UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i)
      at the very beginning of every shader after the vertex shader
    7. call
      UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i, o);
      in every shader stage after the call of
      UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i)
      and after
      UNITY_INITALIZE_OUTPUT(s, o);
    I've yet to verify I figured it out for the hull shader and the
    UNITY_patchconstantfunc
    when using tessellation because the
    UNITY_patchconstantfunc
    takes a list type of hull input and I'm not sure whether using the first item of that list as the source for the ids to be transferred to the domain input is sufficient.

    Edit: Note: do 7 for the vertex shader too, but use
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o)
    , there after
    UNITY_SETUP_INSTANCE_ID(i)
    instead of after
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i)
    which isn't present there; "after
    UNITY_INITALIZE_OUTPUT(s, o);
    " still applies
     
    Last edited: Aug 4, 2020
unityunity