- Изменено
[Discussion] Mutable physics colliders in Unity 2021.2
A physics update in Unity 2021.2 includes the ability to modify the physics shape at runtime without much/any overhead, using the new PhysicsShapeGroup2D/CustomCollider2D.
I am wondering if this could be used with Spine Bounding Boxes, allowing us to animate the vertices on a boundingbox in Spine, and then at runtime having it update the corresponding physics collider to match the bounding box every frame. If so, it would let us animate hitboxes/hurtboxes which would be awesome!
I posted on the Unity forums, and Melvyn from Unity answered a lot of my initial questions: https://forum.unity.com/threads/2d-physics-in-unity-2021-2.1187764/#post-7631779
From his responses, I think this would be possible and I'm intending to test it out as soon as I can, which may be next week or the week after. I wanted to post here in case anyone had any info or suggestions to add, or would be interested in the code after I test it out.
I'm close to having a working 'proof of concept' for this, but I am having an issue with getting the "live" deformed vertex positions for the Bounding Box.
I am referencing the BoundingBoxFollower for the code to get the list of vertices, which uses the Skeleton Extension:
boundingBoxAttachment.GetLocalVertices(slot, buffer);
When I use this, I appear to be getting the vertex positions for the bounding box as it would be in Setup Pose, and not the currently deformed vertex positions (which are deformed in the animation that is currently playing).
Is the boundingBoxAttachment.GetLocalVertices(slot, buffer) the correct way of getting the live deformed vertices? If so, is there a certain time that I need to call it (maybe with a callback)?
Thanks for any help!
Edit: Figured I'd just add my bit of relevant test code (mostly copied from BoundingBoxFollower) in case it helps -
//Have tried calling this in Update() and in LateUpdate()
currentAttachment = slot.Attachment as BoundingBoxAttachment;
Vector2[] boundingBoxVerts = GetBoundingBoxVerticesLocal(slot, currentAttachment);
public static Vector2[] GetBoundingBoxVerticesLocal(Slot slot, BoundingBoxAttachment box, float scale = 1.0f) {
if (box == null) return null;
var verts = box.GetLocalVertices(slot, null);
if (scale != 1.0f) {
for (int i = 0, n = verts.Length; i < n; ++i)
verts[i] *= scale;
}
return verts;
}
Poking around in the code a bit, and maybe GetLocalVertices isn't intended to include the deform?
I tried out GetWorldVertices and it looks to be including the deform. One thing I noticed is that the boundingBoxAttachment.WorldVerticesLength value seems to be twice the number of vertices? The bounding box I'm testing this with has 5 vertices, and the WorldVerticesLength is 10.
Thanks for reporting and sorry for the troubles, you discovered a bug with VertexAttachment.GetLocalVertices
here.
A bugfix has just been commited to both 4.0 and 4.1-beta branches, new spine-unity 4.0 and 4.1 are available for download here as usual:
Spine Unity Download
Issue ticket URL for later reference:
https://github.com/EsotericSoftware/spine-runtimes/issues/1990
Regarding WorldVerticesLength
: it returns the number of floats
in the vertices array (with two floats per vertex), not the number of vertices. Admittedly this is a bit misleading, sorry about that. You can thus see the following line multiple times in MeshGenerator.cs
, dividing the float count by two:
attachmentVertexCount = meshAttachment.WorldVerticesLength >> 1;
Harald написалThanks for reporting and sorry for the troubles, you discovered a bug with
VertexAttachment.GetLocalVertices
here.A bugfix has just been commited to both 4.0 and 4.1-beta branches, new spine-unity 4.0 and 4.1 are available for download here as usual:
Spine Unity DownloadIssue ticket URL for later reference:
https://github.com/EsotericSoftware/spine-runtimes/issues/1990Regarding
WorldVerticesLength
: it returns the number offloats
in the vertices array (with two floats per vertex), not the number of vertices. Admittedly this is a bit misleading, sorry about that. You can thus see the following line multiple times inMeshGenerator.cs
, dividing the float count by two:attachmentVertexCount = meshAttachment.WorldVerticesLength >> 1;
Thanks Harald!
I have a working proof of concept for this, but haven't tested how long the LibTess function actually takes to process (aka whether or not it would be realistic to use this for a bunch of colliders, or how sparingly it would need to be used). Melvyn on the Unity forum post had also mentioned trying the Ear Clipping algorithm as a method, and also the direct method that if you know your boundingbox polygon is <= 8 sides and is convex that you could just make the PolygonShape2D directly from the boundingbox vertices (without doing any tessellation stuff). Thinking I might just make a drop-down selection box where you can choose which method to use, and then can test out each one's efficiency.
Probably will get to test this out some more this weekend :yes:
Cool! 8) Looking forward to your results!
Well, I just spent about half an hour typing an update to this, and then when I went to Upload Attachment to upload a script and clicked "Add the file", it took me back to the forum login screen since I had timed out due to inactivity. I've had the same issue happen when typing up a long forum post, so I've gotten used to copying all of my text before hitting Submit (so I can then Paste it back in after re-logging in), but I didn't realize uploading the attachment would also have caused that. I've lost multiple hours worth of typing/organizing posts on this forum in the past - I'm not sure if the inactivity timeout duration should be extended, or if there is some way to detect that you're actively still creating/typing the post while you're creating it (so you don't timeout), but it would be really good if something was done to alleviate that issue. Maybe auto-saving drafts?
Anyway, on to the topic:
I've been wanting to update this post for a while, but there are some kinks/issues that I haven't sorted out yet, and my code has some project-specific stuff in it and isn't very presentable. But I saw that someone else posted asking about doing a similar thing, so I figured I could at least post what I have in case anyone wants to look through it and try it out.
Definitely check out the info in the Unity forum posts that I linked when originally posting this.
I've attached DeformableBoundingBoxFollower.cs which is based on BoundingBoxFollower.cs.
You will need to set up the Ear Clipping algorithm -
I created it from info from this website: https://www.codeproject.com/Articles/8238/Polygon-Triangulation-in-C
Here is a UnityPackage for my scripts for this algorithm: https://drive.google.com/file/d/1bxO_GP_sCESk15pbyuXnRg6CfePc8jm3/view?usp=sharing
Tessellation algorithm was from here: https://github.com/speps/LibTessDotNet
You will need to download it and add it to your project (if you want to use Tessellation).
Important note: If you just want to use the "Max 8-Sided Convex Polygon" option, then you could probably just use the DeformableBoundingBoxFollower.cs script and strip out anything related to the Ear Clipping / Tessellation algorithms. Might be pretty straightforward if you only needed that.
What works:
-I am only using the "Max 8-Sided Convex Polygon" (what I call "Direct From Convex Polygon" in the script). It seems to be working well, except for one thing (noted below).
Issues:
-I believe there is an issue where OnTriggerEnter2D is called every frame that these collider-triggers are overlapping another collider. My usage of this (hitboxes) handles it fine, but it could definitely be a problem for other implementations. I had specifically asked MelvMay on the Unity forum posts about this (making sure that OnEnter/OnExit would be called correctly), and he said that it should act the same way as any other collider would work. So there may be something wrong with my usage, or maybe there is a bug. Haven't had the time to look into it.
-When I try to use the Ear Clipping and the Tessellation algorithms have an issue where, when I call customCollider.SetCustomShapes(shapeGroup); it has an error where it thinks that the number of Vertices has changed. I am not sure why - if I print the number of vertices for the ShapeGroup before and after the error, it is the same number. The number of shapes also are the same. The algorithms themselves seem to work fine - they generate the polygon correctly.
-The first time you use Tessellation there is a big lag-spike (anywhere from 0.5s to 1.5s for me). After that it is much faster. I'm guessing there is some initialization done the first time you use it, so if anyone ends up using Tessellation you could probably initialize it somehow when you first start up the game.
First of all, terribly sorry that the timeout caused you to lose your text! :wounded:
Strangely I have not yet encountered this behaviour - when any error occurs upon submitting a forum post and I go back to the page and hit "Post Reply" again, I always had the previous text still being there. :think:
I'll see what we can do about it.
Thanks very much for sharing your code and taking the time to write everything down! :nerd: :cooldoge: I'm sure it will be helpful! In case I find out anything in regards to your mentioned issues, I'll of course let you know.
The spine-csharp runtime comes with a battle tested triangulator, that ensures no garbage is created and works as fast as it can in C#: https://github.com/EsotericSoftware/spine-runtimes/blob/4.0/spine-csharp/src/Triangulator.cs
I can guarantee you that there is no startup time :p
The Triangulator.Decompose()
method actually provides you with a list of convex polygons.
Thanks guys! I'm hoping to have some time next month to work on this some more.
Mario написалThe spine-csharp runtime comes with a battle tested triangulator, that ensures no garbage is created and works as fast as it can in C#: https://github.com/EsotericSoftware/spine-runtimes/blob/4.0/spine-csharp/src/Triangulator.cs
I can guarantee you that there is no startup time :p
The
Triangulator.Decompose()
method actually provides you with a list of convex polygons.
Oooo thats awesome to hear, definitely going to check that out - if I can get that working (instead of the Ear Clipping I'm using) then the component could offer that method straight out of the box without having to add any extra libraries / 3rd party stuff. That would be ideal 8)
Note the Spine Runtimes triangulator also uses ear clipping, but at least we can be sure it is efficient, doesn't allocate, doesn't have any bugs, and you don't need another library.
Nate написалNote the Spine Runtimes triangulator also uses ear clipping, but at least we can be sure it is efficient, doesn't allocate, doesn't have any bugs, and you don't need another library.
Nice, yeah I am thinking I will switch it over to use that - but will still need to figure out and fix the error that I am getting (when using the current ear clipping algorithm). I think the error might be a corner-case where something happens like the polygon is scaled down to zero size, or something along those lines. When I originally was testing it standalone, all 3 algorithms were working. So it is something in my actual usage that is causing the error. Hope to check it out next month!