suntabu

Hello,

My spine animation mesh only has 2700+ vertices
企业微信截图_16209801418762.png



But when rendering, the submesh takes all the vertex array to do rendering, just like the image shows:
企业微信截图_16209801785727.png

企业微信截图_20210514163337.png



I did lots of attachments replacement for the dress-changing game.

So how could I reduce the count of vertices?
Bu mesaja eklenen dosyaları görüntülemek için gerekli yetkilere sahip değilsiniz.
suntabu
  • Mesajlar: 9

Harald

I'm afraid I don't understand your question. Especially this part is not clear to me:
suntabu yazdı:But when rendering, the submesh takes all the vertex array to do rendering, just like the image shows:
Could you please describe in different words and in more detail what your current situation is, what you want it to be instead, and what problem you are having?

Do you mean that parts are missing when rendering, that only one submesh of multiple submeshes is rendered? Or that all of your submeshes are combined to one mesh?
Kullanıcı avatarı
Harald

Harri
  • Mesajlar: 4341

suntabu

Sorry for the omitted description.

The problem I encountered is all of the submeshes rendered with the full-size vertices array.
Imagine a submesh only has 4 vertices in the shared vertexBuffer, when rendering it will use all the vertices in shared vertexBuffer.
It leads to 20k+ vertices used when rendering a total of 2700+ vertices mesh.
suntabu
  • Mesajlar: 9

Harald

Thanks for the additional information, now I understand what you mean.

Unity's Mesh class allows for only a single vertex buffer for all submeshes, all submeshes' index buffers have to index this same shared vertex buffer:
https://docs.unity3d.com/ScriptReference/Mesh.html
https://docs.unity3d.com/ScriptReference/Mesh.SetTriangles.html

Even if we could separate the vertex buffers for each submesh, we would not want to do that. In general the vertex buffer should not pose a performance problem, and it would get much worse if 1000 x 4 vertex buffers need to be uploaded vs. a single one with 4000 vertices.

The main question is: do you really need 37 material or texture switches?
Please have a look at the documentation section here on how to save draw calls, most likely you can pack your atlas pages grouped in a better way:
spine-unity Runtime Documentation: Material Switching and Draw Calls
Kullanıcı avatarı
Harald

Harri
  • Mesajlar: 4341

suntabu

Harald yazdı: The main question is: do you really need 37 material or texture switches?
Please have a look at the documentation section here on how to save draw calls, most likely you can pack your atlas pages grouped in a better way:
spine-unity Runtime Documentation: Material Switching and Draw Calls
Yes, our game character has many parts to be replaced and I know material block overriding would break the batching.
Creating atlases for these parts is not a good way in actual practise because of large scale of images.

All DC count is OK for us, the only problem is the vertices count.

According to the phenomena in-game, a DC would send all vertices in shared vertex buffer to GPU separately.

So is there any way to optimize the count?
suntabu
  • Mesajlar: 9

Harald

suntabu yazdı:But when rendering, the submesh takes all the vertex array to do rendering, just like the image shows:

I just had a look at your screenshot in the first posting again which states 1210 vertices, 306 indices. I assume this screenshot is captured from the frame debugger, is this correct? Strangely we could not reproduce this behaviour in the frame debugger in either Unity 2017 or Unity 2021, it always shows only the submeshes vertex and index count of a single quad on our local setup. How did you create this screenshot? Which target platform did you take this screenshot from, or is this from the Editor on PC? Is this from a single active skeleton, or perhaps already multiple skeletons being batched?
suntabu yazdı:All DC count is OK for us, the only problem is the vertices count.
How did you get to this conclusion? Did you measure two versions with reduced vertex count vs. reduced draw calls, or are you guessing based on statistics displayed?
suntabu yazdı:So is there any way to optimize the count?
You could use SkeletonGraphic if you want to test performance of multiple separate meshes instead of a single Mesh with submeshes. Just add a SkeletonGraphic object under a canvas and enable Multiple Canvas Renderers. Then you can compare it to the performance of a single MeshRenderer on SkeletonAnimation.

If you still think this will be beneficial, you could create e.g. your own SkeletonAnimation subclass which overrides LateUpdate and creates and fills separate meshes instead of a single mesh, as can be seen here.
Kullanıcı avatarı
Harald

Harri
  • Mesajlar: 4341

suntabu

Harald yazdı:I assume this screenshot is captured from the frame debugger, is this correct?
Yes, it's from Frame Debugger
Harald yazdı:Strangely we could not reprocduce this behaviour in the frame debugger in either Unity 2017 or Unity 2021, it always shows only the submeshes vertex and index count of a single quad on our local setup. How did you create this screenshot? Which target platform did you take this screenshot from, or is this from the Editor on PC? Is this from a single active skeleton, or perhaps already multiple skeletons being batched?
Maybe you could use these codes
TestSpine.cs
which implemented the dress-switching feature to reproduce this problem and these codes coming from this forum.

The results show below, after we changed most of slots' attachments, the vertices count is 35k+.
test2.png
test1.png

Harald yazdı:You could use SkeletonGraphic if you want to test performance of multiple separate meshes instead of a single Mesh with submeshes. Just add a SkeletonGraphic object under a canvas and enable Multiple Canvas Renderers. Then you can compare it to the performance of a single MeshRenderer on SkeletonAnimation.
I did not find an option named Multiple Canvas Renderers, where is it?
And I don't want to use SkeletonGraphic to develop my game main contents, but willing to use it for UI.
Harald yazdı:If you still think this will be beneficial, you could create e.g. your own SkeletonAnimation subclass which overrides LateUpdate and creates and fills separate meshes instead of a single mesh, as can be seen here.
I checked the source code of how to fill separate meshes, but the question is how could I set multiple meshes for only one MeshFilter ?
Bu mesaja eklenen dosyaları görüntülemek için gerekli yetkilere sahip değilsiniz.
suntabu
  • Mesajlar: 9

Harald

suntabu yazdı:I did not find an option named Multiple Canvas Renderers, where is it?
You should see it in the SkeletonGraphic Inspector under the Advanced section, as described on the documentation pages here:
spine-unity Runtime Documentation: Parameters
In general, please always consult the documentation pages first before asking questions. We wrote them in order to save both you and us the time to repeatedly answer the same questions.

If you don't see this parameter, then you must be using a very old spine-unity runtime.
suntabu yazdı:And I don't want to use SkeletonGraphic to develop my game main contents, but willing to use it for UI.
I did not suggest to switch your workflow to SkeletonGraphic. I said that you can use SkeletonGraphic to test if performance would be improved or made worse. Otherwise you might likely waste time adjusting code to split meshes just to find out that you have to discard the solution again.
suntabu yazdı:I checked the source code of how to fill separate meshes, but the question is how could I set multiple meshes for only one MeshFilter ?
Unity does not allow to assign multiple meshes or vertex buffers at a single MeshFilter or Mesh, neither in the Editor, nor via the API. Please see the text as written in a posting above:
Harald yazdı:Unity's Mesh class allows for only a single vertex buffer for all submeshes, all submeshes' index buffers have to index this same shared vertex buffer:
https://docs.unity3d.com/ScriptReference/Mesh.html
https://docs.unity3d.com/ScriptReference/Mesh.SetTriangles.html
Kullanıcı avatarı
Harald

Harri
  • Mesajlar: 4341

suntabu

Harald yazdı:You should see it in the SkeletonGraphic Inspector under the Advanced section, as described on the documentation pages here:
spine-unity Runtime Documentation: Parameters
In general, please always consult the documentation pages first before asking questions. We wrote them in order to save both you and us the time to repeatedly answer the same questions.
If you don't see this parameter, then you must be using a very old spine-unity runtime.
Yes and sorry about my lazy behaviour, I'm using an old version of Spine supporting v3.8 data and corresponding with 3.8 spine editor.
Harald yazdı:I did not suggest to switch your workflow to SkeletonGraphic. I said that you can use SkeletonGraphic to test if performance would be improved or made worse. Otherwise you might likely waste time adjusting code to split meshes just to find out that you have to discard the solution again.
We are using SkeletonAnimation and the problem happens in SkeletonAnimation, besides SkeletonGraphic and SkeletonAnimation's mesh rendering are not same, so I don't want to dig SkeletonGraphic performance results in wasting time. The only thing is I wanna reduce the count of vertices when spine rendering.
Harald yazdı:Unity does not allow to assign multiple meshes or vertex buffers at a single MeshFilter or Mesh, neither in the Editor, nor via the API. Please see the text as written in a posting above:
I'm not a newbie in unity, I know how unity mesh filter works, how submesh works and why this issue happens. Why I ask you about how to set multiple meshes to mesh filter is just because I don't understand your suggestion and why you suggest this.

At last, did you test the codes I upload in last post?

---

Harald yazdı: Otherwise you might likely waste time adjusting code to split meshes just to find out that you have to discard the solution again.
I fixed this bug by changing MeshGenerator.cs code:
ORIGINAL:
public void AddSubmesh (SubmeshInstruction instruction, bool updateTriangles = true) {
var settings = this.settings;

int newSubmeshCount = submeshIndex + 1;
if (submeshes.Items.Length < newSubmeshCount)
submeshes.Resize(newSubmeshCount);
submeshes.Count = newSubmeshCount;
var submesh = submeshes.Items[submeshIndex];
if (submesh == null)
submeshes.Items[submeshIndex] = submesh = new ExposedList<int>();
submesh.Clear(false);
FIXED:
public void AddSubmesh (SubmeshInstruction instruction, bool updateTriangles = true) {
var settings = this.settings;

int newSubmeshCount = submeshIndex + 1;
if (submeshes.Items.Length < newSubmeshCount)
submeshes.Resize(newSubmeshCount);
submeshes.Count = newSubmeshCount;
var submesh = submeshes.Items[submeshIndex];
if (submesh == null)
submeshes.Items[submeshIndex] = submesh = new ExposedList<int>();
// when list capacity is too large, clear it!
if (submesh.Count * 10 < submesh.Capacity)
{
submesh.Clear(false);
submesh.Items = new int[0];
}
else submesh.Clear(false);
Performance image shows below:
test3.png


Just needs to clear buffer's redundancy data, it may lead to GC collection periodically.
Is there a better way to do this?
Bu mesaja eklenen dosyaları görüntülemek için gerekli yetkilere sahip değilsiniz.
suntabu
  • Mesajlar: 9

Harald

suntabu yazdı:We are using SkeletonAnimation and the problem happens in SkeletonAnimation, besides SkeletonGraphic and SkeletonAnimation's mesh rendering are not same, so I don't want to dig SkeletonGraphic performance results in wasting time. The only thing is I wanna reduce the count of vertices when spine rendering.
While MeshRenderer and CanvasRenderer are different of course, I meant that similar changes (one Mesh with a shared vertex buffer, vs. multiple Meshes with separate vertex buffers) will very likely result in similar benefits or drawbacks.
suntabu yazdı:I'm not a newbie in unity, I know how unity mesh filter works, how submesh works and why this issue happens. Why I ask you about how to set multiple meshes to mesh filter is just because I don't understand your suggestion and why you suggest this.
I assume I misunderstood you there. I repeatedly understood that you wanted to know how to assign more than one vertex buffer per Mesh / MeshFilter (one vertex buffer per submesh), and I kept repeating that this is impossible, and that you need separate Meshes if you want separate non-shared vertex buffers. Therefore I suggested having a look at how SkeletonGraphic creates and fills separate meshes when Multiple Canvas Renderers is enabled.
So I assume we simply misunderstood each other.
suntabu yazdı:At last, did you test the codes I upload in last post?
I had a look at it, but as you appended only a single .cs file, we could not test anything. In general if you want us to test something in Unity, please send us a Unity project as a zip package to contact@esotericsoftware.com.
suntabu yazdı:I fixed this bug by changing MeshGenerator.cs code:
Now I understand what the problem was. Thanks very much for pointing that out, good catch! This must have slipped through for such a long time, as this problematic codepath is only executed when clipping is enabled and multiple submeshes are used.

I have fixed it a bit differently, using an overloaded Mesh.SetTriangles() method variant that allows to specify a length parameter in addition to the int[] array. You can see it in this commit. This method overload only exists on Unity 2019.3 and newer versions, which Unity version are you using?

If you need to use an older Unity version, you could use the Mesh.SetTriangles(List<int>) overload. Then you would change the line ExposedList<ExposedList<int>> submeshes to ExposedList<List<int>> and adjust the code similarly. This should then avoid some GC overhead.

A new 3.8 unitypackage has just been released, it can be downloaded here as usual:
Spine Unity Download
The bugfix will be merged to the 4.0-beta branch soon.
Please let us know if this resolves the problem for you as well.

For later reference: This issue has been tracked under this issue ticket:
https://github.com/EsotericSoftware/spine-runtimes/issues/1894
Kullanıcı avatarı
Harald

Harri
  • Mesajlar: 4341

suntabu

Harald yazdı:I have fixed it a bit differently, using an overloaded Mesh.SetTriangles() method variant that allows to specify a length parameter in addition to the int[] array. You can see it in this commit. This method overload only exists on Unity 2019.3 and newer versions, which Unity version are you using?

If you need to use an older Unity version, you could use the Mesh.SetTriangles(List<int>) overload. Then you would change the line ExposedList<ExposedList<int>> submeshes to ExposedList<List<int>> and adjust the code similarly. This should then avoid some GC overhead.

A new 3.8 unitypackage has just been released, it can be downloaded here as usual:
Spine Unity Download
The bugfix will be merged to the 4.0-beta branch soon.
Please let us know if this resolves the problem for you as well.

For later reference: This issue has been tracked under this issue ticket:
https://github.com/EsotericSoftware/spine-runtimes/issues/1894
We are using the Unity2019.4 LTS version. The new patch works perfectly and nothing wrong found for now, but we will still keep an eye on it for some time.

As this problem has been fixed, it's not necessary to upload a demo project for you to test.

In the end, thanks for your better solution.
suntabu
  • Mesajlar: 9

Harald

Thanks for the info, very glad to hear it's working for you as well, and sorry for the misunderstanding. Thanks again for finding and reporting the bug.
Kullanıcı avatarı
Harald

Harri
  • Mesajlar: 4341


Dön Runtimes