Search Unity

  1. All Pro and Enterprise subscribers: find helpful & inspiring creative, tech, and business know-how in the new Unity Success Hub. Sign in to stay up to date.
    Dismiss Notice
  2. Dismiss Notice

SpriteShape: modifying the shape at runtime -- the sprite does not show

Discussion in '2D Experimental Preview' started by DerickTP, Nov 21, 2018.

  1. DerickTP

    DerickTP

    Joined:
    Jul 28, 2014
    Posts:
    8
    EDIT: By setting spline quality to medium in the spriteshapecontroller inspector, it seems to work... But i still have to go to the scene window to show the mesh the first time. However the collider is there and my character is floating in thin air...

    Hi there,

    I have beed trying to use the Sprite shape package to make some kind of platformer like the sort of Alto. My idea was to build a few sprite shape controllers ahead of time and repurpose these as needed. So here is what I did:
    - at startup I instanciate 3-4 game objects with sprite shapes and colliders attached (one edge collider for the geometry and one box trigger collider for other purposes). I then modify the shapes as needed to fit my needs.
    - When the object becomes invisible, it is 'repurposed', i.e. I modify the spline in order to continue the path at the end of the currently generated path.

    Basically, I see the first repurposing instance for each object in the logs, but when I reach the end of the path, the path is empty. However the colliders are there, cause my object goes on. By going to the scene window and dezooming, I see the objects pop up on the screen and in my game window... I even tried to delete the objects and recreate them instead and I had no luck there... Here is a link to a gif showing the problem I hope :

    http://i.imgur.com/GB6nfx6.gifv

    And here is the code I use:
    Class that creates the objects and modify the spline
    Code (CSharp):
    1. public class WorldBuilding : MonoBehaviour
    2. {
    3.     public static WorldBuilding instance = null;
    4.     public SpriteShapeController prefab;
    5.  
    6.     [Header("World generic data")]
    7.     public float m_fSectionSize = 10f;
    8.     public float m_fSectionHeight = 100f;
    9.     [Range(3,10)]
    10.     public int m_iNumberOfPreloadedSections = 3;
    11.  
    12.     SpriteShapeController[] controllers;
    13.     int nextSection;
    14.  
    15.     Queue<int> repurposeList = new Queue<int>();
    16.  
    17.     // Use this for initialization
    18.     void Start ()
    19.     {
    20.         if(instance ==null)
    21.         {
    22.             instance = this;
    23.         }
    24.         else
    25.         {
    26.             DestroyImmediate(gameObject);
    27.             return;
    28.         }
    29.         nextSection = m_iNumberOfPreloadedSections;
    30.         CreateShapes();
    31.     }
    32.  
    33.     void CreateShapes()
    34.     {
    35.         controllers = new SpriteShapeController[m_iNumberOfPreloadedSections];
    36.         for (int i = 0; i < m_iNumberOfPreloadedSections; ++i)
    37.         {
    38.             CreateShape(i, i, i == 0);
    39.         }
    40.     }
    41.  
    42.     void CreateShape(int idx, int sectionNumber, bool isFirst = false)
    43.     {
    44.         controllers[idx] = GameObject.Instantiate<SpriteShapeController>(prefab, transform);
    45.         controllers[idx].splineDetail = 32;
    46.  
    47.         MakePath(idx, sectionNumber, isFirst);
    48.     }
    49.  
    50.     void MakePath(int idx, int sectionNumber, bool first = false)
    51.     {
    52.         Spline s = controllers[idx].spline;
    53.         s.Clear();
    54.  
    55.         float startPos = sectionNumber * m_fSectionSize;
    56.         float endPos = (sectionNumber + 1) * m_fSectionSize;
    57.  
    58.         int offset = 0;
    59.         s.InsertPointAt(offset++, new Vector3(endPos, -m_fSectionHeight, 0));
    60.         s.InsertPointAt(offset++, new Vector3(startPos, -m_fSectionHeight, 0));
    61.  
    62.  
    63.         s.InsertPointAt(offset++, new Vector3(startPos, 0, 0));
    64.         if (!first)
    65.         {
    66.             s.SetTangentMode(offset - 1, ShapeTangentMode.Continuous);
    67.             s.SetLeftTangent(offset - 1, new Vector3(-1, 0, 0));
    68.             s.SetRightTangent(offset - 1, new Vector3(1, 0, 0));
    69.         }
    70.  
    71.         s.InsertPointAt(offset++, new Vector3(0.5f * (startPos + endPos), 2f, 0));
    72.         s.SetTangentMode(offset - 1, ShapeTangentMode.Continuous);
    73.         s.SetLeftTangent(offset - 1, new Vector3(-1, 0, 0));
    74.         s.SetRightTangent(offset - 1, new Vector3(1, 0, 0));
    75.  
    76.         s.InsertPointAt(offset++, new Vector3(endPos, 0, 0));
    77.         s.SetTangentMode(offset - 1, ShapeTangentMode.Continuous);
    78.         s.SetLeftTangent(offset - 1, new Vector3(-1, 0, 0));
    79.         s.SetRightTangent(offset - 1, new Vector3(1, 0, 0));
    80.  
    81.         //controllers[idx].BakeMesh(); // Gives an error on splinedetails which sould be between 4 and 32. Setting it right before this call does not change the problem.
    82.         //controllers[idx].spriteShapeRenderer.bounds.SetMinMax(new Vector3(startPos, -m_fSectionHeight, 0), new Vector3(endPos, m_fSectionHeight, 0));
    83.         controllers[idx].BakeCollider();
    84.  
    85.         BoxCollider2D box = controllers[idx].GetComponent<BoxCollider2D>();
    86.         box.size = new Vector2(m_fSectionSize, m_fSectionHeight * 2);
    87.         box.offset = new Vector2(0.5f * (startPos + endPos), 0);
    88.  
    89.         WorldSection section = controllers[idx].GetComponent<WorldSection>();
    90.         section.Index = idx;
    91.         section.WasInside = false;
    92.  
    93.         controllers[idx].gameObject.SetActive(true);
    94.     }
    95.  
    96.     public void Repurpose(int idx)
    97.     {
    98.         Debug.Log("Repurposing " + idx);
    99.         repurposeList.Enqueue(idx);
    100.     }
    101.  
    102.     // Update is called once per frame
    103.     void Update ()
    104.     {
    105.         RebuildPathAhead();
    106.     }
    107.  
    108.  
    109.     void RebuildPathAhead()
    110.     {
    111.         while(repurposeList.Count > 0)
    112.         {
    113.             int idx = repurposeList.Dequeue();
    114.             Debug.Log("Rebuild " + idx);
    115.             DestroyImmediate(controllers[idx].gameObject);
    116.             CreateShape(idx, nextSection++);
    117.             //MakePath(idx, nextSection++, false);
    118.         }
    119.     }
    120. }
    121.  
    Class that handles the becameinvisible part and is attached to the object that has the sprite shape controller component attached to it:
    Code (CSharp):
    1. public class WorldSection : MonoBehaviour
    2. {
    3.     int index;
    4.     public int Index
    5.     {
    6.         get { return index; }
    7.         set { index = value; }
    8.     }
    9.  
    10.     bool wasInside = false;
    11.     public bool WasInside
    12.     {
    13.         get { return wasInside; }
    14.         set { wasInside = value; }
    15.     }
    16.  
    17.     // Use this for initialization
    18.     void Start ()
    19.     {
    20.  
    21.     }
    22.  
    23.     // Update is called once per frame
    24.     void Update ()
    25.     {
    26.  
    27.     }
    28.  
    29.     private void OnTriggerStay2D(Collider2D collision)
    30.     {
    31.         //Debug.Log("Inside section");
    32.         wasInside = true;
    33.     }
    34.  
    35.     public void OnBecameInvisible()
    36.     {
    37.         Debug.Log("BecameInvisible");
    38.         if (!wasInside) return;
    39.         WorldBuilding.instance?.Repurpose(index);
    40.         gameObject.SetActive(false);
    41.     }
    42. }
    43.  
    Thanks for any help that you could give and ask me if you need more infos!.
     
    Last edited: Nov 22, 2018
  2. Venkify

    Venkify

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    470
    @DerickTP Could you please file a bug report with a simple repro case ? We will take a look asap as it does look like a bug.
     
  3. DerickTP

    DerickTP

    Joined:
    Jul 28, 2014
    Posts:
    8
    Thanks, done it. Bug number is 1103327.
     
  4. Venkify

    Venkify

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    470
    @DerickTP Thanks for submitting the bug report. While we investigate the issue (is most likely related to regarding Bounds), as a workaround, please try to modify the SpriteShape in the Prefab to be of much larger size. This should fix the issue. Please do let us know if this works.
     
    DerickTP likes this.
  5. DerickTP

    DerickTP

    Joined:
    Jul 28, 2014
    Posts:
    8
    Hi, thanks it seems to work by increasing the size of the sprite shape for now. Thanks for the responsivenes!
     
  6. squarelover

    squarelover

    Joined:
    Nov 14, 2012
    Posts:
    31
    still not resolved. i dont get what do you both mean by using much bigger size SpriteShape ?
     

    Attached Files:

  7. danBourquin

    danBourquin

    Joined:
    Nov 16, 2016
    Posts:
    17
    I have the same issue
     
  8. Npicouet

    Npicouet

    Joined:
    May 17, 2018
    Posts:
    20
    This issue still exists when instantiating a sprite shape controller from prefab.
    There should be an option to "Always Render" like on animator.
     
  9. Venkify

    Venkify

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    470
    This issue has been fixed and will be available soon. Will post an update here.
    However please do help us reporting it as a bug with a simple repro project. Will take a look asap to see if its something unrelated. Thanks.
     
  10. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    I think I have the same problem, is this issue been fixed and released?

    Also, is there any way to force update mesh building and adjusting its bounds during runtime?
     
  11. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    Any news with this? Is this fixed? My spriteshape sometimes does not render and then when I move camera a bit , suddenly it starts to render. I think this may got to do with the bounds, but I am not sure how to properly set the bound after calling RefreshMesh or BakeMesh. I thought that the bounds are supposed to be calculated properly upon generating the mesh for it?
     
  12. UnityIco

    UnityIco

    Joined:
    Jan 5, 2017
    Posts:
    16
    We got the same issue here. Was the fix updated to some Unity version?
    Our prefab with spriteshape doesn't show up, until we zoom in on it in scene view.
     
    castor76 likes this.
  13. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    Is there public issue tracker for this?
     
  14. UnityIco

    UnityIco

    Joined:
    Jan 5, 2017
    Posts:
    16
    If I call SpriteShapeController ForceBakeMesh it will start working. But I don't know if that is the way to go. For now, I will use it.
     
  15. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    I will try this as well...
     
  16. itsonh2610

    itsonh2610

    Joined:
    Jul 15, 2017
    Posts:
    8
    I have the same issue right now with newest version :(
    Any news with this?
     
  17. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    where is ForceBakeMesh API?
     
  18. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    "Available Soon" ? That was 3 months ago? Is this even implemented yet? Any news?
     
  19. UnityIco

    UnityIco

    Joined:
    Jan 5, 2017
    Posts:
    16
    It's in SpriteShapeController script but it isn't easily accessible because it is in the package. So I took what I needed for my SpriteShape to show up, and put it into my script. I call this only once when I need the spriteshape toappear :

    Code (CSharp):
    1. if (spriteShapeRenderer != null)
    2.         {
    3.  
    4.             controller.BakeMesh();  //this is the SpriteShapeController
    5.  
    6.             UnityEngine.Rendering.CommandBuffer rc = new UnityEngine.Rendering.CommandBuffer();
    7.             rc.GetTemporaryRT(0, 256, 256, 0);
    8.             rc.SetRenderTarget(0);
    9.             rc.DrawRenderer(spriteShapeRenderer, spriteShapeRenderer.sharedMaterial);
    10.             rc.ReleaseTemporaryRT(0);
    11.             Graphics.ExecuteCommandBuffer(rc);
    12.  
    13.         }
     
  20. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    I am already doing .BakeMesh command. I was wondering if there was another one called "ForceBakeMesh" API :D

    However, I am interested to find out the rendering part... using command buffer. I am assuming that this is only for your specific project need?

    For me, I do call BakeMesh, but the renderer still does not render them right. I have to move my camera around a bit to probably trigger the rendering. Possibly to do with bounds. So I am assuming that this is still not fixed or fix is still not in the 2021.1.6f1 at least. ?

    @Venkify can you confirm please?
     
  21. UnityIco

    UnityIco

    Joined:
    Jan 5, 2017
    Posts:
    16
    Yeah I know about the BakeMesh but it didn't do the trick for me.

    That's why I am using ForceBakeMesh, it's where I got the rendering part from. But you can't just call it from your code even if you extend the function to be public it will reset on Unity Restart because it is inside the Packages\2D SpriteShape\Runtime\SpriteShapeController.

    So I took the rendering code out and placed it in my class, and It works for me. We got a vine that we spawn from player to position, and this vine is a sprite shape so we can customize it. Each time I spawn a new vine I force it to render with that piece of code. Hope it helps.
     
  22. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    Are you calling it per every frame? I am asking because the rendering code seems like it needs to be doing per frame and with 256 x 256 fixed buffer size, how do you deal with different sized sprite shape?
     
  23. UnityIco

    UnityIco

    Joined:
    Jan 5, 2017
    Posts:
    16
    No, I am actually calling it only once when we fire the vine from the player to the target point.
    And you don't need to call it every frame cause from that point on it's drawn just fine on the screen. I am just using it to get it to render for the first time.

    I am not sure about huge sprite shapes, but our vine is kinda flexible and it seems to work fine on different sized vines.
     
  24. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    Right... but I still think the size somehow should matter, so I will hold on to the official fix. This should really be fixed and 2Drenderer team should communicate more often about what is going on.
     
  25. Venkify

    Venkify

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    470
    @castor76 Agreed, we have added a new API to set custom Bounds in 2021.2 to support fixing the above.

    https://docs.unity3d.com/2021.2/Doc...nce/U2D.SpriteShapeRenderer.SetLocalAABB.html

    We are fixing the above issue in an upcoming release. Until then, please use the Render Mesh workaround or set custom Bounds to reflect any changes made to SpriteShape object on Runtime.
     
  26. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    Please let us know which version of Unity is going to fix the issue, or which SpritShape package version number.
     
  27. Kothered

    Kothered

    Joined:
    Mar 5, 2019
    Posts:
    7
    I have the same issue.. And BakeMesh() doesn't work for me :(
     
  28. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,175
    Also, how do you set custom bounds? How do you calculate it?...
     
    Last edited: May 21, 2021
unityunity