Search Unity

Modifying sprite vertices (shear/scale) through code to create drop shadow

Discussion in '2D' started by tanoshimi, Nov 8, 2015.

  1. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    I'm trying to create simple dynamic drop shadows for 2D sprites.

    I don't have much experience with the "new" 2D aspects of Unity, but when I did this for a game in Unity 4.2 (in which 2D graphics were billboard textures on mesh quads), the approach was relatively straightforward - I duplicated the mesh, flipped the UV coordinates along the x-axis and modified the vertex positions through a scale/shear matrix, passed the modified mesh.vertices and mesh.uv back and applied a transparent shader - which gave exactly the result I wanted as below:

    dropshadow.jpg

    My problem is that I can't seem to repeat the same process when working with sprites...
    Unlike Mesh.vertices, Sprite.vertices is readonly, and it seems the only way to assign new vertices is to call Sprite.OverrideGeometry(). When I pass in the modified vertex array to OverrideGeometry, I get an "Invalid vertex array. Some vertices are outside the Sprite rectangle" error, but I don't understand this - I think the "Sprite rectangle" refers to the location of the sprite in the texture atlas, whereas I'm trying to shear and scale the mesh onto which the sprite is applied, not the rectangle from which the sprite texture is read. :(

    After bashing my head for a bit, I considered keeping the original object as a sprite, but making a mesh copy to act as the shadow so that I could keep my old method of shearing. However, the process of converting from a sprite to a quad is proving to be a bit cumbersome; I can do it and it works fine if the source sprite was rectangular. However, for tightly packed sprites I can't work out how I can convert the sprite's UV coordinates (which Unity calculates automatically) to the shadow mesh.

    If anyone can enlighten me as to how to shear/scale a sprite's mesh (or alternative methods to create the drop shadow above) I'd be very grateful! Otherwise, I think I'm going to scrap sprites altogether and go back to working with 2D axis-aligned quads in 3D space! (and don't even get me started on the "sorting order" issues I've been having!)

    Thanks.
     
  2. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    For the benefit of anyone else wondering, I solved this using a different approach: instead of trying to modify the geometry mesh or UVs, I sheared the vertices by applying a transformation matrix in the vertex function of the shader.

    Specifically, starting with the basis Sprites-Default.shader, add this to the vertex function:

    Code (CSharp):
    1. float4x4 shearTransformationMatrix = float4x4(
    2.     1, _HorizontalShear, 0, 0,
    3.     _VerticalShear, 1, 0, 0,
    4.     0, 0, 1, 0,
    5.     0, 0, 0, 1
    6. );
    7.  
    8. float4 shearedVertex = mul(shearTransformationMatrix, IN.vertex);
    9. OUT.vertex = mul(UNITY_MATRIX_MVP, shearedVertex);
    The only problem is that this won't work if sprites are batched because the mesh origin will change, so you also need to add the DisableBatching="True" tag, but other than that it seems a good solution.
     
    szimmermann likes this.
  3. magehernan

    magehernan

    Joined:
    Jul 6, 2012
    Posts:
    7
    Hi, i am trying to do the same, the first problem i get is the vertices i get from sprite.vertices are in a relative pos but is not from -1 to 1 is a werd value like -.8 to .9 in one case and when you use override you need to put pixel coords, i multiply the values for my width and height and i get almost de same mesh...
    The first issue is i put values less than 0 or highers than width/height unity throw an error and don't do anything.
    The second is if i make a mesh shear, the uv are calculated and the image continue the same.

    and i want to do batching...