Search Unity

Billboards generated with a Geometry shader, can't cast/receive shadows?

Discussion in 'Shaders' started by NemoKrad, Feb 23, 2016.

  1. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    So, as my title suggests, I have a vertex, geometry, fragment shader and, well I just want it to cast and recive shadows, I do the usual including #include "AutoLight.cginc" and putting LIGHTING_COORDS into my input structure, but then when I try to call TRANSFER_VERTEX_TO_FRAGMENT(); in my geom shader I get errors

    "invalid subscript 'vertex' 'mul': no matching 2 parameter intrinsic function; Possible intrinsic functions are: mul(float|half"

    I spotted on line someone suggested making sure a param in the input was called vertex, did this and still get the error. So thought, maybe I should be calling it in my vertex shader, but that does not make sense to me anyway as the vertex shader is just getting points, but even in there the TRANSFER_VERTEX_TO_FRAGMENT gives and error

    " undeclared identifier 'v' "

    Seems like quite a chore to just get my objects to receive and cast shadows, I know I am doing something daft, but for the life of me can't think what it is.

    I seem to have trouble doing the same with a regular vertex fragment shader too, I would love to be able to have my billboards write to the depth buffer too so effects like this can be used with them.

    Any ideas tips, are welcome.

    Also, as an aside, it really would be helpful if geometry shaders could also be used in conjunction with surface shaders :)
     
  2. barzb

    barzb

    Joined:
    Dec 12, 2015
    Posts:
    7
    Did you add the lightmode tag?
    Code (CSharp):
    1. Tags { "LightMode" = "ForwardBase"  }
    And the pragma?
    Code (CSharp):
    1. #pragma multi_compile_fwdbase
     
    NemoKrad likes this.
  3. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    Yea, I have been all over google/bing, have all that good stuff in there, but no joy :(

    I might end up boiling it down to a simple implementation and post it here, not that what I am doing now is complicated, it's just now messy with all the stuff I have added to try and get shadows to play :/
     
  4. barzb

    barzb

    Joined:
    Dec 12, 2015
    Posts:
    7
    I remember having the same issue but idk what exactly fixed it in the end.
    How does your data structure looks like? I think I had to rename the position to "pos" and it worked.
    Code (CSharp):
    1. struct g2f
    2. {
    3.     float4 pos : SV_POSITION;
    4.     float2 uv  : TEXCOORD0;
    5.     LIGHTING_COORDS(1, 2)
    6. };
     
    NemoKrad likes this.
  5. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    Yep, same :)
     
    barzb likes this.
  6. barzb

    barzb

    Joined:
    Dec 12, 2015
    Posts:
    7
    Does it work now? :D
     
  7. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    No sorry, I already have all that in there, it does not work still :( Ill get a sample up here in a bit and you can have a look. Tanks for taking time to respond by the way :D
     
    barzb likes this.
  8. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    OK, here is my simple version of the shader and script. I have cut it right back to the start, but left in allt he includes and Lighting bits I think that are needed, but as I say TRANSFER_VERTEX_TO_FRAGMENT errors no mater what I do, so have that commented out.

    This is how my billboard looks, so, as you can see it's not casting shadows


    My script looks like this:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class TestScript : MonoBehaviour
    5. {
    6.  
    7.     ComputeBuffer outputBuffer;
    8.  
    9.     Material material;
    10.  
    11.     public Texture2D sprite;
    12.     public Color color = new Color(1.0f, 0.6f, 0.3f, 0.03f);
    13.  
    14.     struct data
    15.     {
    16.         public Vector3 pos;
    17.     };
    18.  
    19.     data[] points;
    20.  
    21.  
    22.     // Use this for initialization
    23.     void Start()
    24.     {
    25.         Camera.main.depthTextureMode = DepthTextureMode.Depth;
    26.  
    27.         material = new Material(Shader.Find("Test/TestShader"));
    28.  
    29.         points = new data[] { new data() { pos = Vector3.zero } };
    30.  
    31.         outputBuffer = new ComputeBuffer(points.Length, 12);
    32.         outputBuffer.SetData(points);
    33.  
    34.         SetMaterial();
    35.     }
    36.  
    37.  
    38.  
    39.     void OnRenderObject()
    40.     {
    41.  
    42.         SetMaterial();
    43.  
    44.         Graphics.DrawProcedural(MeshTopology.Points, outputBuffer.count);
    45.     }
    46.  
    47.     void SetMaterial()
    48.     {
    49.         material.SetPass(0);
    50.         material.SetColor("_Color", color);
    51.         material.SetBuffer("buf_Points", outputBuffer);
    52.         material.SetTexture("_Sprite", sprite);
    53.         material.SetVector("_Size", transform.localScale);
    54.         material.SetVector("_worldPos", transform.position);
    55.     }
    56.  
    57.     void OnDestroy()
    58.     {
    59.         outputBuffer.Release();
    60.     }
    61. }
    62.  
    And my shader looks like this:
    Code (CSharp):
    1. Shader "Test/TestShader"
    2. {
    3.  
    4.     Properties
    5.     {
    6.         _Sprite("Sprite", 2D) = "white" {}
    7.         _Color("Color", Color) = (1,1,1,1)
    8.         _Size("Size", Vector) = (1,1,0,0)
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "Queue" = "Geometry" "IgnoreProjector" = "True"
    16.             "RenderType" = "Opaque"
    17.             "DisableBatching" = "True"
    18.             "LightMode" = "ForwardBase"
    19.         }
    20.  
    21.         LOD 100
    22.         Blend SrcAlpha OneMinusSrcAlpha
    23.  
    24.         Cull off
    25.         ZWrite off
    26.         ZTest LEqual
    27.  
    28.         Pass
    29.         {
    30.             Tags{ "LightMode" = "ForwardBase" }
    31.             CGPROGRAM
    32.             #pragma target 2.0
    33.  
    34.             #pragma vertex vert          
    35.             #pragma geometry geom
    36.             #pragma fragment frag
    37.  
    38.             #pragma multi_compile_fog
    39.             #pragma multi_compile_fwdadd_fullshadows
    40.             //#pragma multi_compile_fwdbase
    41.             #include "AutoLight.cginc"
    42.             #include "UnityCG.cginc"
    43.  
    44.             sampler2D _Sprite;
    45.             float4 _Color = float4(1,0.5f,0.0f,1);
    46.             float2 _Size = float2(1,1);
    47.             float3 _worldPos;
    48.  
    49.             float3 _WindVelocity;
    50.             float3 _Magnitude;
    51.  
    52.  
    53.             struct data
    54.             {
    55.                 float3 pos;
    56.             };
    57.  
    58.             //The buffer containing the points we want to draw.
    59.             StructuredBuffer<data> buf_Points;
    60.  
    61.             struct input
    62.             {
    63.                 float4 pos : SV_POSITION;
    64.                 float2 uv : TEXCOORD0;
    65.                 LIGHTING_COORDS(1, 2)
    66.                 UNITY_FOG_COORDS(1)
    67.  
    68.             };
    69.  
    70.             input vert(uint id : SV_VertexID)
    71.             {
    72.                 input o;
    73.                 UNITY_INITIALIZE_OUTPUT(input, o);
    74.                 o.pos = float4(buf_Points[id].pos + _worldPos, 1.0f);
    75.  
    76.                 return o;
    77.             }
    78.  
    79.             float4 RotPoint(float4 p, float3 offset, float3 sideVector, float3 upVector)
    80.             {
    81.                 float3 finalPos = p.xyz;
    82.  
    83.                 finalPos += offset.x * sideVector;
    84.                 finalPos += offset.y * upVector;
    85.  
    86.                 return float4(finalPos,1);
    87.             }
    88.  
    89.             [maxvertexcount(4)]
    90.             void geom(point input p[1], inout TriangleStream<input> triStream)
    91.             {
    92.                 float2 halfS = _Size;
    93.  
    94.                 float4 v[8];
    95.  
    96.                 v[0] = p[0].pos.xyzw + float4(-halfS.x, -halfS.y, 0, 0);
    97.                 v[1] = p[0].pos.xyzw + float4(-halfS.x, halfS.y, 0, 0);
    98.                 v[2] = p[0].pos.xyzw + float4(halfS.x, -halfS.y, 0, 0);
    99.                 v[3] = p[0].pos.xyzw + float4(halfS.x, halfS.y, 0, 0);
    100.  
    101.                 float uid = normalize(p[0].pos);
    102.  
    103.                 input pIn;
    104.  
    105.                 UNITY_INITIALIZE_OUTPUT(input, pIn);
    106.  
    107.                 pIn.pos = mul(UNITY_MATRIX_VP, v[0]);
    108.                 pIn.uv = float2(0.0f, 0.0f);
    109.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    110.                 triStream.Append(pIn);
    111.  
    112.                 //TRANSFER_VERTEX_TO_FRAGMENT(pIn);
    113.  
    114.                 pIn.pos = mul(UNITY_MATRIX_VP, v[1]);
    115.                 pIn.uv = float2(0.0f, 1.0f);
    116.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    117.                 triStream.Append(pIn);
    118.  
    119.                 //TRANSFER_VERTEX_TO_FRAGMENT(pIn);
    120.  
    121.                 pIn.pos = mul(UNITY_MATRIX_VP, v[2]);
    122.                 pIn.uv = float2(1.0f, 0.0f);
    123.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    124.                 triStream.Append(pIn);
    125.  
    126.                 //TRANSFER_VERTEX_TO_FRAGMENT(pIn);
    127.  
    128.                 pIn.pos = mul(UNITY_MATRIX_VP, v[3]);
    129.                 pIn.uv = float2(1.0f, 1.0f);
    130.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    131.                 triStream.Append(pIn);
    132.  
    133.                 //TRANSFER_VERTEX_TO_FRAGMENT(pIn);
    134.             }
    135.  
    136.             float4 frag(input i) : COLOR
    137.             {
    138.                 i.uv.y -= .01;
    139.                 fixed4 col = tex2D(_Sprite, i.uv) * _Color;
    140.  
    141.                 col.a *= 1.5 - i.uv.y;
    142.  
    143.                  col *= LIGHT_ATTENUATION(i);
    144.                 UNITY_APPLY_FOG(i.fogCoord, col); // apply fog
    145.  
    146.                 return col;
    147.             }
    148.  
    149.             ENDCG
    150.         }
    151.     }
    152.         Fallback "Legacy Shaders/Transparent/Cutout/VertexLit"
    153. }
    154.  
    So I guess what is missing is the calls to TRANSFER_VERTEX_TO_FRAGMENT
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    Shadow casting and shadow receiving requires your shader has a shadowcaster pass. This is used both for rendering to the view depth (used for shadow receiving of the main directional light) and shadow map depth. This is basically a copy of your main geometry shader that only outputs depth data. There's an example of how to add one to a basic vert frag shader on this page:
    http://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html

    It also shows how to get your shader to show shadows in the example below the shadow caster. Any method that uses Fallback or UsePass will not work for you as these are expecting a complete mesh coming from the CPU to render that only needs to be transformed with the appropriate matrix and will have no knowledge of the geometry shader.

    It's also going to be important to understand what those macros (the all in caps lines) are doing, and for that I suggest you download the built in shader source from here: https://unity3d.com/get-unity/download/archive

    Open up AutoLight.cginc and look for #define MACRO_NAME to see what they're doing. There's going to be multiple entries for each of them depending on what kind of light and shadow are being used, but each set should be commonly reading and writing from the same locations. This means some of those macros are expecting a struct named v to read from and data in specific names in that struct. You'll need to match this layout for the macros to work, or you'll need to write your own set of macros that match your own layout (there's a lot of permutations in there, so this path will be painful to try).

    Edit: I believe TRANSFER_VERTEX_TO_FRAGMENT is from Unity 4.0 and is now just around for backwards compatibility, but should no longer be used.
     
    Iron-Warrior and NemoKrad like this.
  10. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    @bgolus , thanks, great reply, lots to look up. I have the builtin shaders so Ill have a look, don't fancy re writing the pipeline lol

    I am thinking this should be simpler than this in the 5th iteration of the engine...
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    Shadows are hard, there's no easy "bMakeItWork" here, lots of data that needs to be modified, calculated, and transfered in very specific ways for many, many different situations (and they're all different!). Unity is by far the most stream lined way I've seen this handled, though I agree the geometry shader stuff is a little sparse on support, it's also not a commonly used feature by people who aren't already knowledgable enough to start digging through these files and understand them.

    I've worked with some engines in the past where to get shadows working required hand writing a different shader every single combination of light and shadow type individually, or having it be a 100% walled garden where if you wanted something other than the two built in shading models you were out of luck. So, Unity is actually pretty nice. :)
     
    astracat111 and NemoKrad like this.
  12. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    I have written deferred lighting engines, and I always hate shadows lol, but ultimately all you are doing (maybe I am a bit out of touch) is re rendering geometry from the perspective of the light and using that as a the shadow map for that light, you end up with a map per light perspective and then you can cascade them together. I was sort of hoping Unity would work that way, but I guess they have a number of render pipelines for all this good stuff to go down, so not as simple as I had hoped :)

    Thanks for the help, having a dig now, if I get it going ill post the code here :)
     
  13. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    That is what they're doing, but in a deferred renderer you can split that complexity apart to each light type doing it's own thing. In forward it needs to know how to do everything for all combination of types.* The real complexity is in reading the shadows from several distinct types of shadowing (directional screen space, directional, spot, point cube, and the last 3 of those with light cookies), not in the creation of the shadow maps.

    * Technically the forward base pass only needs to know about the main directional light, all other light types are done as additional passes with a forward add pass. But Unity still has two ways to do the main directional shadow with a prepass screen space shadow on most platforms, and an optional vanilla no cascade direct shadowmap lookup for platforms that don't support the screen space shadow technique. The macros just get used by both passes for simplicity sake. And if you want to use deferred rendering you can just do that and ignore getting forward passes to work, but you still need the shadow caster pass for casting shadows. On DX11 the screen depth in deferred doesn't require a separate pass.
     
    NemoKrad likes this.
  14. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    Yea, would be nice to get it working in all render pipelines, looks like I have a bit to re jig as the macros really are not expecting points :S I think this is where it's falling down.

    It really would be nice if they can bring geom shaders into the fold in both the macro's and the surface shaders. Ill keep at it and hope I can sort it, but not sure I will have a robust solution due to all the branching lol
     
  15. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    I still can't get this to work, it's driving me nuts it really should not be this difficult lol

    This is how my shader now looks, what on earth am I still doing wrong, anyone out there put me out of my misery :(

    Code (CSharp):
    1. Shader "Test/TestShader"
    2. {
    3.  
    4.     Properties
    5.     {
    6.         _Sprite("Sprite", 2D) = "white" {}
    7.         _Color("Color", Color) = (1,1,1,1)
    8.         _Size("Size", Vector) = (1,1,0,0)
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "Queue" = "Geometry" "IgnoreProjector" = "True"
    16.             "RenderType" = "Opaque"
    17.             "DisableBatching" = "True"
    18.             "LightMode" = "ForwardBase"
    19.         }
    20.  
    21.         LOD 100
    22.         Blend SrcAlpha OneMinusSrcAlpha
    23.  
    24.         Cull off
    25.         //ZWrite off
    26.         ZTest LEqual
    27.  
    28.         Pass
    29.         {
    30.             Tags{ "LightMode" = "ForwardBase" }
    31.             CGPROGRAM
    32.             #pragma target 2.0
    33.  
    34.             #pragma vertex vert          
    35.             #pragma geometry geom
    36.             #pragma fragment frag
    37.  
    38.             #pragma multi_compile_fog
    39.             #pragma multi_compile_fwdadd_fullshadows
    40.             //#pragma multi_compile_fwdbase
    41.             #include "AutoLight.cginc"
    42.             #include "UnityCG.cginc"
    43.  
    44.             sampler2D _Sprite;
    45.             float4 _Color = float4(1,0.5f,0.0f,1);
    46.             float2 _Size = float2(1,1);
    47.             float3 _worldPos;
    48.  
    49.  
    50.             struct data
    51.             {
    52.                 float3 pos;
    53.             };
    54.  
    55.             //The buffer containing the points we want to draw.
    56.             StructuredBuffer<data> buf_Points;
    57.  
    58.             struct input
    59.             {
    60.                 float4 pos : SV_POSITION;
    61.                 float2 uv : TEXCOORD0;
    62.                 LIGHTING_COORDS(1, 2)
    63.                 UNITY_FOG_COORDS(1)
    64.  
    65.             };
    66.  
    67.             input vert(uint id : SV_VertexID)
    68.             {
    69.                 input o;
    70.                 UNITY_INITIALIZE_OUTPUT(input, o);
    71.                 o.pos = float4(buf_Points[id].pos + _worldPos, 1.0f);
    72.  
    73.                 return o;
    74.             }
    75.  
    76.             float4 RotPoint(float4 p, float3 offset, float3 sideVector, float3 upVector)
    77.             {
    78.                 float3 finalPos = p.xyz;
    79.  
    80.                 finalPos += offset.x * sideVector;
    81.                 finalPos += offset.y * upVector;
    82.  
    83.                 return float4(finalPos,1);
    84.             }
    85.  
    86.             [maxvertexcount(4)]
    87.             void geom(point input p[1], inout TriangleStream<input> triStream)
    88.             {
    89.                 float2 halfS = _Size;
    90.  
    91.                 float4 v[4];
    92.  
    93.                 v[0] = p[0].pos.xyzw + float4(-halfS.x, -halfS.y, 0, 0);
    94.                 v[1] = p[0].pos.xyzw + float4(-halfS.x, halfS.y, 0, 0);
    95.                 v[2] = p[0].pos.xyzw + float4(halfS.x, -halfS.y, 0, 0);
    96.                 v[3] = p[0].pos.xyzw + float4(halfS.x, halfS.y, 0, 0);
    97.  
    98.                 float uid = normalize(p[0].pos);
    99.  
    100.                 input pIn;
    101.  
    102.                 UNITY_INITIALIZE_OUTPUT(input, pIn);
    103.  
    104.                 pIn.pos = mul(UNITY_MATRIX_VP, v[0]);
    105.                 pIn.uv = float2(0.0f, 0.0f);
    106.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    107.                 triStream.Append(pIn);
    108.  
    109.                 pIn.pos = mul(UNITY_MATRIX_VP, v[1]);
    110.                 pIn.uv = float2(0.0f, 1.0f);
    111.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    112.                 triStream.Append(pIn);
    113.  
    114.                 pIn.pos = mul(UNITY_MATRIX_VP, v[2]);
    115.                 pIn.uv = float2(1.0f, 0.0f);
    116.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    117.                 triStream.Append(pIn);
    118.  
    119.  
    120.                 pIn.pos = mul(UNITY_MATRIX_VP, v[3]);
    121.                 pIn.uv = float2(1.0f, 1.0f);
    122.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    123.                 triStream.Append(pIn);
    124.  
    125.             }
    126.  
    127.             float4 frag(input i) : COLOR
    128.             {
    129.                
    130.                 fixed4 col = tex2D(_Sprite, i.uv) * _Color;
    131.  
    132.                 col *= LIGHT_ATTENUATION(i);
    133.  
    134.                 UNITY_APPLY_FOG(i.fogCoord, col); // apply fog
    135.  
    136.                 return col;
    137.             }
    138.  
    139.             ENDCG
    140.         }
    141.  
    142.         Pass
    143.         {
    144.             Tags{ "LightMode" = "ShadowCaster" }
    145.  
    146.             CGPROGRAM
    147.             #pragma vertex vert
    148.             #pragma geometry geom
    149.             #pragma fragment frag
    150.             #pragma multi_compile_shadowcaster
    151.             #include "UnityCG.cginc"
    152.  
    153.             float2 _Size = float2(1,1);
    154.             float3 _worldPos;
    155.  
    156.             struct data
    157.             {
    158.                 float3 pos;
    159.             };
    160.  
    161.             StructuredBuffer<data> buf_Points;
    162.  
    163.             struct v2f {
    164.                 float4 pos : TEXCOORD0;
    165.             };
    166.  
    167.             v2f vert(uint id : SV_VertexID)
    168.             {
    169.                 v2f o;
    170.                 o.pos = float4(buf_Points[id].pos + _worldPos, 1.0f);
    171.                 return o;
    172.             }
    173.  
    174.  
    175.             float4 UnityClipSpaceShadowCasterPos2(float3 vertex)
    176.             {
    177.                 float4 clipPos;
    178.  
    179.                 // Important to match MVP transform precision exactly while rendering
    180.                 // into the depth texture, so branch on normal bias being zero.
    181.                 if (unity_LightShadowBias.z != 0.0)
    182.                 {
    183.                     float3 wPos = vertex;
    184.                     float3 wNormal = (float3(0,0,-1));
    185.                     float3 wLight = normalize(UnityWorldSpaceLightDir(wPos));
    186.  
    187.                     float shadowCos = dot(wNormal, wLight);
    188.                     float shadowSine = sqrt(1 - shadowCos*shadowCos);
    189.                     float normalBias = unity_LightShadowBias.z * shadowSine;
    190.  
    191.                     wPos -= wNormal * normalBias;
    192.  
    193.                     clipPos = mul(UNITY_MATRIX_VP, float4(wPos, 1));
    194.                 }
    195.                 else
    196.                 {
    197.                     clipPos = float4(vertex,1);
    198.                 }
    199.                 return clipPos;
    200.             }
    201.  
    202. #define TRANSFER_SHADOW_CASTER_NOPOS2(opos, vertex) \
    203.             opos = mul(UNITY_MATRIX_VP, vertex); \
    204.             opos = UnityApplyLinearShadowBias(opos);
    205.            
    206.  
    207.             [maxvertexcount(4)]
    208.             void geom(point v2f p[1], inout TriangleStream<v2f> triStream)
    209.             {
    210.                 float2 halfS = _Size;
    211.  
    212.                 float3 v[4];
    213.  
    214.                 v[0] = p[0].pos + float3(-halfS.x, -halfS.y, 0);
    215.                 v[1] = p[0].pos + float3(-halfS.x, halfS.y, 0);
    216.                 v[2] = p[0].pos + float3(halfS.x, -halfS.y, 0);
    217.                 v[3] = p[0].pos + float3(halfS.x, halfS.y, 0);
    218.  
    219.                 v2f pIn;
    220.  
    221.                 UNITY_INITIALIZE_OUTPUT(v2f, pIn);
    222.  
    223.                 //pIn.pos = mul(UNITY_MATRIX_VP, v[0]);
    224.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, v[0]);
    225.                 triStream.Append(pIn);
    226.                
    227.  
    228.                 //pIn.pos = mul(UNITY_MATRIX_VP, v[1]);
    229.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, v[1]);
    230.                 triStream.Append(pIn);
    231.  
    232.                 //pIn.pos = mul(UNITY_MATRIX_VP, v[2]);
    233.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, v[2]);
    234.                 triStream.Append(pIn);
    235.  
    236.                 //pIn.pos = mul(UNITY_MATRIX_VP, v[3]);
    237.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, v[3]);
    238.                 triStream.Append(pIn);
    239.                
    240.             }
    241.  
    242.             float4 frag(v2f i) : SV_Target
    243.             {
    244.                 SHADOW_CASTER_FRAGMENT(i)
    245.             }
    246.             ENDCG
    247.         }
    248.     }
    249.         Fallback off
    250. }
    251.  
     
  16. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    First issue:
    Code (CSharp):
    1.  
    2.         Tags
    3.         {
    4.             "Queue" = "Geometry" "IgnoreProjector" = "True"
    5.             "RenderType" = "Opaque"
    6.             "DisableBatching" = "True"
    7.             "LightMode" = "ForwardBase"
    8.         }
    You should not be setting the light mode on the SubShader, only within the passes. This is causing both the shadow caster pass and the forward base pass to get rendered during the final opaque forward rendering pass!

    Second issue to be aware of and stupidly I didn't notice earlier:
    Blend SrcAlpha OneMinusSrcAlpha

    Unity doesn't support shadow receiving on transparent objects. That's not actually the issue here though as it actually doesn't look at the blend mode, only the queue. Anything over queue 2500 won't be able to receive shadows. You are however rendering during the geometry queue which means things should be working, but you also might not get the results you think you are. If you want billboards with shadows you'll want to be using alpha test and not alpha blend.

    Next:

    #pragma multi_compile_fwdadd_fullshadows
    This is the forward base pass, that's not a valid multi_compile for this pass and is going to cause a lot of problems. The one you have commented out is the correct one, though you probably want to use this:
    #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight

    Next up:

    LIGHTING_COORDS(1, 2)
    UNITY_FOG_COORDS(1)


    These macros are for defining which TEXCOORD# to store data in. You're telling it to use TEXCOORD1 and TEXCOORD2 for lighting coords, then telling it to stomp on that data with the fog. LIGHTING_COORDS is also a Unity 4.0 macro and deprecated, you should be using SHADOW_COORDS(#) as per the example page I posted, along with adding a TRANSFER_SHADOW for each vertex output from the geometry shader and SHADOW_ATTENUATION not LIGHT_ATTENUATION.

    That TRANSFER_SHADER is going to be a tricky one as some variants of the define expects an object space vertex position in v.vertex, but there is no "v", and the vertex positions are already in world space. You could create a dummy v struct with the object space vertex position in it with v.vertex = mul(_World2Object, v[0]); or you could make your own override again. Screen space main directional light shadows just needs a valid .pos though, which you already have, so this is actually fine to use unmodified for the ForwardBase pass, it's the ForwardAdd pass that'll bite you, or systems that don't support screen space shadows.

    Now if you fix all of the above you should start seeing shadows on your billboards! They'll be the shadows of the objects behind them though since we haven't gotten to the shadow caster pass itself.

    First off the pos in the v2f struct you have is set to TEXCOORD0, this means there is no SV_POSITION for the rasterizer to use to render, ie: no geometry will be rendered! The whole "NOPOS" thing is because they normally output the SV_POSITION as a out var on the vertex function so that the fragment shader can use VPOS, but that doesn't work for geometry shaders so you need to have pos be SV_POSITION.

    After that you got really, really close with your TRANSFER_SHADOW_CASTER_NOPOS2, but the vertex you're passing in is a float3, and that needs to be a float4!

    So, with all of that fixed plus a few other tweaks we get:
    Code (CSharp):
    1. Shader "Test/TestShader"
    2. {
    3.     Properties
    4.     {
    5.         _Sprite("Sprite", 2D) = "white" {}
    6.         _Color("Color", Color) = (1,1,1,1)
    7.         _Size("Size", Vector) = (1,1,0,0)
    8.     }
    9.     SubShader
    10.     {
    11.         Tags
    12.         {
    13.             "Queue" = "AlphaTest" "IgnoreProjector" = "True"
    14.             "DisableBatching" = "True"
    15.         }
    16.         LOD 100
    17.         Cull off
    18.         ZWrite On
    19.         ZTest LEqual
    20.         Pass
    21.         {
    22.             Tags{ "LightMode" = "ForwardBase" }
    23.             CGPROGRAM
    24.             #pragma target 2.0
    25.             #pragma vertex vert        
    26.             #pragma geometry geom
    27.             #pragma fragment frag
    28.             #pragma multi_compile_fog
    29.             #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
    30.             #include "AutoLight.cginc"
    31.             #include "UnityCG.cginc"
    32.             sampler2D _Sprite;
    33.             float4 _Color;
    34.             float2 _Size;
    35.             float3 _worldPos;
    36.             struct data
    37.             {
    38.                 float3 pos;
    39.             };
    40.             //The buffer containing the points we want to draw.
    41.             StructuredBuffer<data> buf_Points;
    42.             struct input
    43.             {
    44.                 float4 pos : SV_POSITION;
    45.                 float2 uv : TEXCOORD0;
    46.                 SHADOW_COORDS(1)
    47.                 UNITY_FOG_COORDS(2)
    48.             };
    49.             input vert(uint id : SV_VertexID)
    50.             {
    51.                 input o;
    52.                 UNITY_INITIALIZE_OUTPUT(input, o);
    53.                 o.pos = float4(buf_Points[id].pos + _worldPos, 1.0f);
    54.                 return o;
    55.             }
    56.             float4 RotPoint(float4 p, float3 offset, float3 sideVector, float3 upVector)
    57.             {
    58.                 float3 finalPos = p.xyz;
    59.                 finalPos += offset.x * sideVector;
    60.                 finalPos += offset.y * upVector;
    61.                 return float4(finalPos,1);
    62.             }
    63.             [maxvertexcount(4)]
    64.             void geom(point input p[1], inout TriangleStream<input> triStream)
    65.             {
    66.                 float2 halfS = _Size;
    67.                 float4 v[4];
    68.                 v[0] = p[0].pos.xyzw + float4(-halfS.x, -halfS.y, 0, 0);
    69.                 v[1] = p[0].pos.xyzw + float4(-halfS.x, halfS.y, 0, 0);
    70.                 v[2] = p[0].pos.xyzw + float4(halfS.x, -halfS.y, 0, 0);
    71.                 v[3] = p[0].pos.xyzw + float4(halfS.x, halfS.y, 0, 0);
    72.                 float uid = normalize(p[0].pos);
    73.                 input pIn;
    74.                 UNITY_INITIALIZE_OUTPUT(input, pIn);
    75.                 pIn.pos = mul(UNITY_MATRIX_VP, v[0]);
    76.                 pIn.uv = float2(0.0f, 0.0f);
    77.                 TRANSFER_SHADOW(pIn);
    78.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    79.                 triStream.Append(pIn);
    80.                 pIn.pos = mul(UNITY_MATRIX_VP, v[1]);
    81.                 pIn.uv = float2(0.0f, 1.0f);
    82.                 TRANSFER_SHADOW(pIn);
    83.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    84.                 triStream.Append(pIn);
    85.                 pIn.pos = mul(UNITY_MATRIX_VP, v[2]);
    86.                 pIn.uv = float2(1.0f, 0.0f);
    87.                 TRANSFER_SHADOW(pIn);
    88.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    89.                 triStream.Append(pIn);
    90.                 pIn.pos = mul(UNITY_MATRIX_VP, v[3]);
    91.                 pIn.uv = float2(1.0f, 1.0f);
    92.                 TRANSFER_SHADOW(pIn);
    93.                 UNITY_TRANSFER_FOG(pIn, pIn.pos);
    94.                 triStream.Append(pIn);
    95.             }
    96.             float4 frag(input i) : COLOR
    97.             {
    98.              
    99.                 fixed4 col = tex2D(_Sprite, i.uv) * _Color;
    100.                 clip(col.a - 0.5);
    101.                 col *= SHADOW_ATTENUATION(i);
    102.                 UNITY_APPLY_FOG(i.fogCoord, col); // apply fog
    103.                 return col;
    104.             }
    105.             ENDCG
    106.         }
    107.         Pass
    108.         {
    109.             Name "ShadowCaster"
    110.             Tags { "LightMode" = "ShadowCaster" }
    111.             CGPROGRAM
    112.             #pragma vertex vert
    113.             #pragma geometry geom
    114.             #pragma fragment frag
    115.             #pragma multi_compile_shadowcaster
    116.             #include "UnityCG.cginc"
    117.             float2 _Size = float2(1,1);
    118.             float3 _worldPos;
    119.             struct data
    120.             {
    121.                 float3 pos;
    122.             };
    123.             StructuredBuffer<data> buf_Points;
    124.             struct v2f {
    125.                 float4 pos : SV_POSITION;
    126.                 float2 uv : TEXCOORD0;
    127.             };
    128.             v2f vert(uint id : SV_VertexID)
    129.             {
    130.                 v2f o;
    131.                 o.pos = float4(buf_Points[id].pos + _worldPos, 1.0f);
    132.                 o.uv = 0; // dummy data just to skip warning.
    133.                 return o;
    134.             }
    135. #define TRANSFER_SHADOW_CASTER_NOPOS2(opos, vertex) \
    136.             opos = mul(UNITY_MATRIX_VP, vertex); \
    137.             opos = UnityApplyLinearShadowBias(opos);
    138.          
    139.             [maxvertexcount(4)]
    140.             void geom(point v2f p[1], inout TriangleStream<v2f> triStream)
    141.             {
    142.                 float2 halfS = _Size;
    143.                 float3 v[4];
    144.                 v[0] = p[0].pos + float3(-halfS.x, -halfS.y, 0);
    145.                 v[1] = p[0].pos + float3(-halfS.x, halfS.y, 0);
    146.                 v[2] = p[0].pos + float3(halfS.x, -halfS.y, 0);
    147.                 v[3] = p[0].pos + float3(halfS.x, halfS.y, 0);
    148.                 v2f pIn;
    149.                 UNITY_INITIALIZE_OUTPUT(v2f, pIn);
    150.                 pIn.uv = float2(0.0f, 0.0f);
    151.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, float4(v[0], 1.0));
    152.                 triStream.Append(pIn);
    153.              
    154.                 pIn.uv = float2(0.0f, 1.0f);
    155.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, float4(v[1], 1.0));
    156.                 triStream.Append(pIn);
    157.                 pIn.uv = float2(1.0f, 0.0f);
    158.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, float4(v[2], 1.0));
    159.                 triStream.Append(pIn);
    160.                 pIn.uv = float2(1.0f, 1.0f);
    161.                 TRANSFER_SHADOW_CASTER_NOPOS2(pIn.pos, float4(v[3], 1.0));
    162.                 triStream.Append(pIn);
    163.              
    164.             }
    165.  
    166.             sampler2D _Sprite;
    167.             float4 frag(v2f i) : SV_Target
    168.             {
    169.                 fixed4 col = tex2D(_Sprite, i.uv);
    170.                 clip(col.a - 0.5);
    171.  
    172.                 SHADOW_CASTER_FRAGMENT(i)
    173.             }
    174.             ENDCG
    175.         }
    176.     }
    177. }


    Things that still don't work in this version:
    • Any shadow from lights other than the main directional light. You would need forward add passes for that, and because we're not applying the actual lighting from the lights that might look weird. That and getting the TRANSFER_SHADOW working on the ForwardAdd pass is more work than I want to do.
    • Ambient lighting, or any lighting really. Since we're not doing any lighting at all the stuff in shadow is just black. Might be good to apply the light color and the ambient light. You can do that by adding #include "UnityLightingCommon.cginc" and replacing the SHADOW_ATTENUATION line with: col.rgb *= _LightColor0.rgb * SHADOW_ATTENUATION(i) + UNITY_LIGHTMODEL_AMBIENT.rgb;
    • Alpha blend. As stated before Unity can't do shadow receiving and proper alpha blend. You can make it cast shadows, either hard edged like in the above code, or stippled with some more work (this is what they use VPOS for). It makes sense for the way they do the main directional light shadow with the screen space pre-pass, but it's frustrating they simply don't pass anything about the shadow maps or the light matrices to transparent objects.
     
  17. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    You @bgolus are an absolute bloody star mate!

    I knew I was doing some daft stuff in there, but think I have just gone code blind due to me not knowing the Unity Pipeline that well. This is going to help me understand it more no end.

    Thank you so much for sorting my mess out :) Can't wait for lunch time now so I can try it out, I dare say Ill end up making more daft errors and have to ask again, but in the mean time, this is just awesome :)
     
  18. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    :(

    Gutted, just tried it, (could not wait for lunch) and it's still not casting shadows in my scene...

    :(
     
  19. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    I tested it by applying the material to a quad and it worked there. Might be some remaining issues with rendering using Graphics.DrawProcedural though. I haven't delved too deeply into those, but it might require adding command buffers to the camera and light(s) to inject into the depth map to get it to actually show. Look at the Frame Debugger to see if it's even showing up during those passes.

    Edit: yep, DrawProcedural doesn't work with lighting. http://forum.unity3d.com/threads/no...-graphics-drawprocedural.260579/#post-1730443
     
    Last edited: Feb 24, 2016
    NemoKrad likes this.
  20. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    hmmm, don't know if I know what you are referring to, but ill have a look at the profiler when I next look at it (later today I hope).
     
  21. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    Frame Debugger, not the profiler. It's under the Windows menu. It lets you step through the draw calls and see what's actually being drawn.

    You might need to just drop the whole DrawProcedural idea though and do this as a mesh; maybe just make a triangle soup mesh with the vertices where you want your billboards so you're sending less to the GPU each frame.
     
  22. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    OOH! Cool Ill check that out, thanks :)

    Really, would be nice to be able to just pass the point array, as at some point I will want to load that buffer from a compute shader. If I end up doing it with a mesh, Ill the have a lag when pulling the data from the GPU, formatting it to then be passed back to the GPU :(
     
  23. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    Yep, it would be nice. That link I posted in my edit a few posts above looks like people were suggesting trying to use command buffers, but no one seems to have actually tried.
     
    NemoKrad likes this.
  24. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    Man, this really should be easier than this lol
     
  25. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,350
    Unity's support for instancing is very basic. In 5.4 they're adding a lot more, but I suspect DrawProcedural or some way to take a buffer from a compute shader and use it for the full lighting pipeline will still be missing. I mean they still don't have shadows on transparency which just needs them to pass the shadowmaps and light matrices they already have and pass to opaque objects to transparent objects. Their method for doing pre-pass main directional light cascaded shadows seems to be the only stickler they don't have any full forward support for.
     
  26. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    Yes saw something in instancing the other week, it's a shame, I could do so much more with Unity if this was in there... feeling a bit deflated today lol
     
  27. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    Anyone in Unity that could give me some pointers, or even just confirm that it can or can't be done yet?
     
  28. iamvideep

    iamvideep

    Joined:
    Oct 27, 2017
    Posts:
    118
    NemoKrad likes this.
  29. NemoKrad

    NemoKrad

    Joined:
    Jan 16, 2014
    Posts:
    632
    Cool, ill check it out, what version of Unity?
     
  30. iamvideep

    iamvideep

    Joined:
    Oct 27, 2017
    Posts:
    118
    Its unity 2018 :)
    Which version are you trying it in?

    PS: I am looking for contributors to this project as I am learning simulations. Please share the word if you find it interesting.
     
  31. AlexanderNystedt

    AlexanderNystedt

    Joined:
    Dec 16, 2018
    Posts:
    1
    I know this is really late but i got it working in the geometry shader. Would happily tell you how if you're intested. :)
     
  32. asdzxcv777

    asdzxcv777

    Joined:
    Jul 17, 2017
    Posts:
    29
    I would like to know ... maybe you could post it here