Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Camera facing billboard messing up with layers ZIndex and shadows

Discussion in 'General Graphics' started by Danil0v3s, May 18, 2023.

  1. Danil0v3s

    Danil0v3s

    Joined:
    Sep 22, 2014
    Posts:
    43
    Hi all!

    I'm trying to build a 2d sprite (using quads) with 3d world, there is a problem with billboarding by copying the camera rotation which makes the object "poke through" the 3d objects and the shadows will stay above the sprite at some angles. Following this thread https://forum.unity.com/threads/pro...-sprites-clipping-into-3d-environment.680374/, the answer from bgolus solves two problems however it introduces a new one, whenever I have more than one layer in the same object, they have their z messed up. Almost like their z position was reversed. Like this

    upload_2023-5-18_17-58-10.png

    If I only billboard with the shader, using this piece of code

    Code (CSharp):
    1.  
    2. float3 vpos = mul((float3x3)unity_ObjectToWorld, vertex.xyz);
    3. float4 worldCoord = float4(unity_ObjectToWorld._m03_m13_m23, 1);
    4. float4 viewPos = mul(UNITY_MATRIX_V, worldCoord) + float4(vpos, 0);
    5. float4 outPos = mul(UNITY_MATRIX_P, viewPos);
    This is the result:
    upload_2023-5-18_18-11-54.png upload_2023-5-18_18-14-17.png

    This is their structure upload_2023-5-18_18-15-19.png

    And here's my shader:

    Code (CSharp):
    1. float rayPlaneIntersection(float3 rayDir, float3 rayPos, float3 planeNormal, float3 planePos)
    2. {
    3.     float denom = dot(planeNormal, rayDir);
    4.     denom = max(denom, 0.000001);
    5.     float3 diff = planePos - rayPos;
    6.     return dot(diff, planeNormal) / denom;
    7. }
    8.  
    9. float4 billboardMeshTowardsCamera(float4 vertex)
    10. {
    11.     // billboard mesh towards camera
    12.     float3 vpos = mul((float3x3)unity_ObjectToWorld, vertex.xyz);
    13.     float4 worldCoord = float4(unity_ObjectToWorld._m03_m13_m23, 1);
    14.     float4 viewPivot = mul(UNITY_MATRIX_V, worldCoord);
    15.  
    16.     // construct rotation matrix
    17.     float3 forward = -normalize(viewPivot);
    18.     float3 up = mul(UNITY_MATRIX_V, float3(0, 1, 0)).xyz;
    19.     float3 right = normalize(cross(up, forward));
    20.     up = cross(forward, right);
    21.     const float3x3 facingRotation = float3x3(right, up, forward);
    22.  
    23.     float4 viewPos = float4(viewPivot + mul(vpos, facingRotation), 1.0);
    24.     float4 pos = mul(UNITY_MATRIX_P, viewPos);
    25.  
    26.     // calculate distance to vertical billboard plane seen at this vertex's screen position
    27.     const float3 planeNormal = normalize((_WorldSpaceCameraPos.xyz - unity_ObjectToWorld._m03_m13_m23) * float3(1, 0, 1));
    28.     const float3 planePoint = unity_ObjectToWorld._m03_m13_m23;
    29.     const float3 rayStart = _WorldSpaceCameraPos.xyz;
    30.     const float3 rayDir = -normalize(mul(UNITY_MATRIX_I_V, float4(viewPos.xyz, 1.0)).xyz - rayStart); // convert view to world, minus camera pos
    31.     float dist = rayPlaneIntersection(rayDir, rayStart, planeNormal, planePoint);
    32.  
    33.     // calculate the clip space z for vertical plane
    34.     float4 planeOutPos = mul(UNITY_MATRIX_VP, float4(rayStart + rayDir * dist, 1.0));
    35.     float newPosZ = planeOutPos.z / planeOutPos.w * pos.w;
    36.  
    37.     // use the closest clip space z
    38.     #if defined(UNITY_REVERSED_Z)
    39.     pos.z = max(pos.z, newPosZ);
    40.     #else
    41.     pos.z = min(pos.z, newPosZ);
    42.     #endif
    43.  
    44.     return pos;
    45. }
    Code (CSharp):
    1.  
    2. Shader "UnityRO/BillboardSpriteShader"
    3. {
    4. Properties
    5. {
    6. _MainTex("Texture", 2D) = "white" {}
    7. _PaletteTex("Texture", 2D) = "white" {}
    8. _Alpha("Alpha", Range(0.0, 1.0)) = 1.0
    9. _UsePalette("Use Palette", Float) = 0
    10.  
    11. _Color("Color", Color) = (1,1,1,1)
    12. _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
    13. }
    14.  
    15. SubShader
    16. {
    17. Tags
    18. {
    19. "Queue" = "AlphaTest+50"
    20. "RenderType" = "Geometry"
    21. "DisableBatching" = "True"
    22. }
    23.  
    24. CGINCLUDE
    25. #include "UnityCG.cginc"
    26. #include "SpriteUtilities.cginc"
    27.  
    28. sampler2D _MainTex;
    29. sampler2D _PaletteTex;
    30.  
    31. float4 _MainTex_TexelSize;
    32. float _Alpha;
    33. float _UsePalette;
    34. ENDCG
    35.  
    36. Pass
    37. {
    38. Tags
    39. {
    40. "LightMode" = "ForwardBase"
    41. }
    42. Blend SrcAlpha OneMinusSrcAlpha
    43.  
    44. CGPROGRAM
    45. #pragma vertex vert
    46. #pragma fragment frag
    47. #pragma multi_compile_fog
    48.  
    49. // compile shader into multiple variants, with and without shadows
    50. // (we don't care about any lightmaps yet, so skip these variants)
    51. #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
    52. // shadow helper functions and macros
    53. #include "AutoLight.cginc"
    54. #include "LightUtilities.cginc"
    55.  
    56. v2f_base vert(appdata_base v)
    57. {
    58. v2f_base o;
    59. o.uv = v.texcoord;
    60.  
    61. o = applyLighting(o, v.normal);
    62. o.pos = billboardMeshTowardsCamera(v.vertex);
    63.  
    64. UNITY_TRANSFER_FOG(o, o.pos);
    65. // compute shadows data
    66. TRANSFER_SHADOW(o)
    67.  
    68. return o;
    69. }
    70.  
    71. fixed4 frag(v2f_base i) : SV_Target
    72. {
    73. fixed3 lighting = getLighting(i);
    74.  
    75. fixed4 col = _UsePalette
    76. ? bilinearSample(_MainTex, _PaletteTex, i.uv, _MainTex_TexelSize)
    77. : tex2D(_MainTex, i.uv);
    78.  
    79. col.rgb *= lighting * 1.1;
    80.  
    81. if (col.a == 0.0) discard;
    82. col.a *= _Alpha;
    83.  
    84. UNITY_APPLY_FOG(i.fogCoord, col);
    85.  
    86. return col;
    87. }
    88. ENDCG
    89. }
    90.  
    91. Pass
    92. {
    93. Name "Caster"
    94. Tags
    95. {
    96. "LightMode" = "ShadowCaster"
    97. }
    98.  
    99. CGPROGRAM
    100. #pragma vertex vert
    101. #pragma fragment frag
    102. #pragma target 2.0
    103. #pragma multi_compile_shadowcaster
    104. #pragma multi_compile_instancing // allow instanced shadow pass for most of the shaders
    105.  
    106. struct v2f
    107. {
    108. V2F_SHADOW_CASTER;
    109. float2 uv : TEXCOORD1;
    110. UNITY_VERTEX_OUTPUT_STEREO
    111. };
    112.  
    113. uniform float4 _MainTex_ST;
    114.  
    115. v2f vert(appdata_base v)
    116. {
    117. v2f o;
    118. UNITY_SETUP_INSTANCE_ID(v);
    119. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    120. TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
    121. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    122. o.pos = billboardMeshTowardsCamera(v.vertex);
    123.  
    124. return o;
    125. }
    126.  
    127. uniform fixed _Cutoff;
    128. uniform fixed4 _Color;
    129.  
    130. float4 frag(v2f i) : SV_Target
    131. {
    132. fixed4 col = _UsePalette
    133. ? bilinearSample(_MainTex, _PaletteTex, i.uv, _MainTex_TexelSize)
    134. : tex2D(_MainTex, i.uv);
    135.  
    136. clip(col.a * _Color.a - _Cutoff);
    137. col.a *= _Alpha;
    138.  
    139. SHADOW_CASTER_FRAGMENT(i)
    140. }
    141. ENDCG
    142. }
    143. }
    144. }
    145.  

    How can I use a billboard facing camera and still have my objects to be properly drawn?
     

    Attached Files: