Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Question Billboarding towards the camera

Discussion in 'Graphics for ECS' started by Simon-O, Jul 11, 2023.

  1. Simon-O

    Simon-O

    Joined:
    Jan 22, 2014
    Posts:
    51
    I'm attempting to create an unlit billboard shader for use in DOTS. I'm using quads to host the material



    (Some regular, some DOTS for comparison purposes)

    I've cribbed together something from this gist and other sources to render a sprite where I want it, however, it's not oriented towards the camera.

    Code (CSharp):
    1. Shader"DOTSTest/UnlitWithDotsInstancing"
    2. {
    3.    Properties
    4.    {
    5.        _BaseMap ("Base Texture", 2D) = "white" {}
    6.        _BaseColor ("Base Colour", Color) = (1, 1, 1, 1)
    7.    }
    8.  
    9.    SubShader
    10.    {
    11.        Tags
    12.        {
    13.            "RenderPipeline"="UniversalPipeline"
    14.            "Queue"="Geometry"
    15.            "RenderType"="Transparent"
    16.            "PreviewType"="Plane"
    17.        }
    18.  
    19.        //LOD100
    20.  
    21.        Blend SrcAlpha OneMinusSrcAlpha
    22.  
    23.        ZWrite Off
    24.  
    25.        Pass
    26.        {
    27.            Name"Forward"
    28.            Tags {
    29.                "LightMode"="UniversalForward"
    30.            }
    31.  
    32.            Cull Back
    33.  
    34.            HLSLPROGRAM
    35.            #pragma exclude_renderers gles gles3 glcore
    36.            #pragma target 4.5
    37.            #pragma vertex UnlitPassVertex
    38.            #pragma fragment UnlitPassFragment
    39.            #pragma multi_compile_instancing
    40.            #pragma instancing_options renderinglayer
    41.            #pragma multi_compile _ DOTS_INSTANCING_ON
    42.            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    43.  
    44.            struct Attributes
    45.            {
    46.                float4 positionOS : POSITION;
    47.                float2 uv : TEXCOORD0;
    48.                float4 color : COLOR;
    49.                            UNITY_VERTEX_INPUT_INSTANCE_ID
    50.            };
    51.  
    52.            struct Varyings
    53.            {
    54.                float4 positionCS : SV_POSITION;
    55.                float2 uv : TEXCOORD0;
    56.                float4 color : COLOR;
    57.                            UNITY_VERTEX_INPUT_INSTANCE_ID
    58.            };
    59.  
    60.            CBUFFER_START(UnityPerMaterial)
    61.            float4 _BaseMap_ST;
    62.            float4 _BaseColor;
    63.            CBUFFER_END
    64.  
    65.        
    66.  
    67.  
    68.            #ifdef UNITY_DOTS_INSTANCING_ENABLED
    69.                UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)
    70.                    UNITY_DOTS_INSTANCED_PROP(float4, _BaseColor)
    71.                UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)
    72.                #define _BaseColor UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(float4, _BaseColor)
    73.            #endif
    74.  
    75.            TEXTURE2D(_BaseMap);
    76.            SAMPLER(sampler_BaseMap);
    77.  
    78.            Varyings UnlitPassVertex(Attributes input)
    79.            {
    80.                Varyings output;
    81.  
    82.                UNITY_SETUP_INSTANCE_ID(input);
    83.                UNITY_TRANSFER_INSTANCE_ID(input, output);
    84.  
    85.                const VertexPositionInputs positionInputs = GetVertexPositionInputs(input.positionOS.xyz);
    86.                output.positionCS = positionInputs.positionCS;
    87.                output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
    88.                output.color = input.color;
    89.  
    90.                return output;
    91.  
    92.            }
    93.  
    94.            half4 UnlitPassFragment(Varyings input) : SV_Target
    95.            {
    96.                UNITY_SETUP_INSTANCE_ID(input);
    97.                half4 baseMap = half4(SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv));
    98.                return baseMap * _BaseColor * input.color;
    99.            }
    100.            ENDHLSL
    101.        }
    102.    }
    103. }
    It works (which is to say it renders, I haven't tried varying colors yet). Before I get to that, I want to fix the orientation.



    Previously, I've achieved that using something like this [also cribbed from other sources]

    Code (CSharp):
    1. v2f vert(appdata v)
    2. {
    3.    v2f o;
    4.    o.pos = UnityObjectToClipPos(v.vertex);
    5.    o.uv = v.uv.xy;
    6.  
    7.    // billboard mesh towards camera
    8.    float3 vpos = mul((float3x3)unity_ObjectToWorld, v.vertex.xyz);
    9.    float4 worldCoord = float4(unity_ObjectToWorld._m03, unity_ObjectToWorld._m13, unity_ObjectToWorld._m23, 1);
    10.    float4 viewPos = mul(UNITY_MATRIX_V, worldCoord) + float4(vpos, 0);
    11.    float4 outPos = mul(UNITY_MATRIX_P, viewPos);
    12.  
    13.    o.pos = outPos;
    14.  
    15.    UNITY_TRANSFER_FOG(o, o.vertex);
    16.    return o;
    17. }
    And while it's worked, I have to admit I don't understand what it's doing in the transformations.

    Whilst attempting to wire up that code, I noticed that the shader compiles just fine for use on a regular object, but the DOTS variant throws



    I've tried swapping `unity_ObjectToWorld` for `_Object2World` to no avail.

    If I include UnityCG.cginc I get a `_Time redefined` error (it appears to be clashing with `Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl`). Removing that include means I can no longer reference `UNITY_VERTEX_INPUT_INSTANCE_ID`.

    I found this page in the docs, which says

    • Declare all built-in engine properties, such as unity_ObjectToWorld or unity_WorldTransformParams, in a single CBUFFER called UnityPerDraw.
    So I tried adding a

    Code (CSharp):
    1. CBUFFER_START(UnityPerDraw)
    2. float4x4 unity_ObjectToWorld;
    3. CBUFFER_END
    Which then fails to compile as `unity_ObjectToWorld` is being defined twice in the non-DOTS shader.

    Moving it inside a conditional `#ifdef UNITY_DOTS_INSTANCING_ENABLED`

    Compiles fine for non-DOTS (of course) but then fails DOTS with

    Assuming this is the right approach, what's the DOTS-equivalent to unity_ObjectToWorld? And/or where do I need to import it from?

    If not, how should I be handling the orientation in the shader?
     
  2. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    180
    Try this:
    Code (CSharp):
    1.  
    2. [Varyings UnlitPassVertex(Attributes input)
    3. {
    4.     Varyings output;
    5.  
    6.     UNITY_SETUP_INSTANCE_ID(input);
    7.     UNITY_TRANSFER_INSTANCE_ID(input, output);
    8.     float3 positionWS = TransformObjectToWorld(0);
    9.     float3 positionVS = TransformWorldToView(positionWS);
    10.     positionVS += input.positionOS.xyz;
    11.     output.positionCS = TransformViewToHClip(positionVS);
    12.     output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
    13.     output.color = input.color;
    14.  
    15.     return output;
    16. }
    17.  
    Code do the following:
    Line 8: get sprite position
    Line 9: transform sprite position to view space.
    Line 10: move vertex to proper position by adding it local position in view space. This way, if sprite vertices are defined in XY plane, we will have view space sprite parallel to camera plane.
    Line 11: transform view space position to clip space position
     
    Lo-renzo likes this.
  3. Simon-O

    Simon-O

    Joined:
    Jan 22, 2014
    Posts:
    51
    Thanks, that looks promising but TransformViewToHClip is undefined. FWIW TransformWorldToHClip is defined but results in no visible geometry.

    Am I missing an include?
     
  4. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    180
    Not visible at all? Not in sceneview too?
     
  5. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    180
    My bad. Function is: TransformWViewToHClip
    It is defined in com.unity.render-pipelines.core\ShaderLibrary\SpaceTransforms.hlsl
     
  6. Simon-O

    Simon-O

    Joined:
    Jan 22, 2014
    Posts:
    51
    That did it. Thank you, and thanks for the detailed explanation above... Very informative.