Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Skinned Meshes vs Animating transforms and batching

Discussion in 'iOS and tvOS' started by marjan, Dec 6, 2011.

  1. marjan

    marjan

    Joined:
    Jun 6, 2009
    Posts:
    563
    Hi,
    i am in the early stages of making a game which is supposed to have a lot of machinery/robotic dynamic objects/characters.

    Every machine has around 10 segments, which i animate with FK. Traditionally there is no need to skin those and use a rig of joints to animate. Animate the transforms would be just fine.
    But than i remembered that this results in several dynamic gameobjects, lets say also 10, and each would have one drawcall.

    So i made a test yesterday and after optimizing the meshes some more i had a result of 1 drawcall (10 batched). Great. Sort of. Because this only works under the following conditions:

    - Use a simple shader (Using any Shader with normalmaps will break the batching, resulting in 10 Drawcalls). Which is too bad, would like to use normalmaps.
    - Don´t scale anything (ok, don´t want to do that)
    - Lights affect the batching process severly. Especially having a Pixel Light will tripple the drawcalls it seems. So instead of 1 i have 30.
    - Meshes need to have less than 300 verts (In Unity, not what your modelling app shows(ok, got that done)). But this point is unclear to me. It could mean, that batching potentially would work with lights or bump shaders, but than the max verts count could be half or just a quarter. Anybody knows something about this?
    - a little weird: I duplicated the model 20 times, expecting still 1 drawcall. But now it became 3. So, after a certain vertscount Unity seems to break objects into several draws.


    The alternativ would be to skin everything. Than i would definatly have 1 drawcall and could use bump shaders. But are skinned meshes than batched together? I mean, if i would place 20 Machineobjects in the scene would that result in 1 or in 20 drawcalls? In my case i would expect 20 drawcalls, because the skinned mesh will have much more vertices than 300. This would compare then to 3 calls with not skinned characters but 20 calls with skinned characters. On the other hand, as soon as a pixel light is there it could potentially break batching and rise calls per object which would lead to this scenario: 600 drawcalls not skinned vs 60 skinned. :eek:

    And of course a skinned mesh should need more computations then a not skinned one.

    Anyways, if anybody has deeper insights or experiences i am eager to read!

    -
     
    Last edited: Feb 14, 2012
  2. MikaMobile

    MikaMobile

    Joined:
    Jan 29, 2009
    Posts:
    845
    Skinned meshes don't batch regardless of vert count, but 20 draw calls isn't an unreasonable number either. Draw calls aren't as big of a deal as they used to be, unless you're targeting Original iPhone's running OS 2.x. You still want them as low as possible, but when you're talking about less than 30 total, you really can't see much of a difference. A game consistently rocking 5 draw calls won't run appreciably faster than one with 29, all else being equal.
     
  3. marjan

    marjan

    Joined:
    Jun 6, 2009
    Posts:
    563
    i know, but the non skinned version can easylie jump into the hundreds as i wrote. That might be an issue than on iPad1.

    Skinned meshes also need all the extra work of, well, skinning and rigging. Thought it would be better without. Still not sure which approach i should follow.
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    dynamic batching won't jump into the hundreds and anything thats a problem on ipad1 will not run on anything but ipad1, ipad2 and iphone4s at all as any other device is 25-70% slower

    ipad performance problems are normally fillrate, not drawcalls as its 1ghz cpu is more than enough to push through quite some pile of geometry
     
  5. marjan

    marjan

    Joined:
    Jun 6, 2009
    Posts:
    563
    to be clear, i made a test with one of those, not skinned GameObjects. With one Pixellight on, the drawcalls jumped over 45. What if i have several different Gameobjects and all of them get affected by a pixellight? That woul easily be hundreds of calls.
    Thats what i meant.
     
  6. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Thats correct.
    But if you push in pixel lights you will have other problems along the line of fillrate too and depending on what you have you don't even need pixel lights but could just as well use vertex lights that don't cause redraws of the objects over and over.

    And using skinning indeed helps here on the drawcall number, but the fillrate problem is at least as large if not worse as the whole mesh gets redrawn if it is within light range, not just 3 meshes if you setup the light with reasonable ranges to ever run it on mobile at all. Keep that in mind when trying to seek a solution, that redraws due to pixel lights, projects, shadows are 'mesh based' not triangle based and that you need to find a balance thats not fillrate limited and not cpu limited at the same time.
     
  7. zombox

    zombox

    Joined:
    Aug 10, 2011
    Posts:
    119
    I had a similar dilemma, OP.

    In Zombox I have a fair number of zombies (around 10) continually trying to attack the player. Each zombie is fairly simple...it's composed of 6 boxes (head, torso, arms, legs).

    While testing performance, even though all the separate zombie meshes *do* batch, the game runs faster when all the zombies are skinned into a mesh, rather than separate entities.

    I don't mean each zombie is a separate skinned mesh, I mean all 10 are skinned into one skinnedmesh. This skinning is created on the fly when the game starts up. The zombies are loaded in as separate meshes and a script runs that combines them all into a single skin.

    I haven't benchmarked in a while, but I believe the difference was around 10 ms/frame on the 3GS....enough to justify keeping them all skinned up.

    I'd share the script but it's integrated fairly tightly into Zombox, and isn't modular enough to post without having to re-write many aspects of it. The general concept is not hard to re-create though...just scan through the meshes you want to combine into a skin, and create a new combined mesh using those individual meshes as bones.
     
    Last edited: Dec 7, 2011
  8. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    5,041
    Zombox: are you sure your issue is draw call related?

    marjan: If its of any help here are some heuristics for batching:

    -A mesh can only batch if the total number of "visible" attributes attached to the mesh is less than 900. Attributes include verts (3 attributes), texture coords(2), normals(3), tangents(4), etc. Also includes non-zero light mapping attributes even if mesh is not set to static. Verts that aren't sent for drawing don't count towards this.

    -Meshes with the same material are ordered by depth (and somewhat arbitrarily if at the same depth). If any of these meshes can't be batched then the batching stops at that point. i.e. If B is a 'batchable' mesh and U an 'unbatchable' mesh then if the depth sorted order of the meshes was BBUBB then only the first 2 B's would batch.

    -Transparent objects wont batch if there is anything between them.

    -Anything touched by a pixel light wont batch.

    I've found that it can be useful to give a new material to objects that are on the fringe of being 'batchable'. Although this means they will always be a separate draw call it also means they wont 'break the batch' for other objects that easily batch. Alternatively split the mesh (although this might cause other issues).

    PS Sorry if my terminology is a bit out; I'm not a 3D guy. This information discovered through discussions with Unity folks and my own experiments.
     
  9. zombox

    zombox

    Joined:
    Aug 10, 2011
    Posts:
    119
    Johnny: Well I'm not expert on these subjects, but when I did my tests the only difference between the two scenarios was that in one, the zombies were composed of individual meshes and were dynamically batched, and the other they were a single skinned mesh. There was a clear fps difference between the two tests.

    The performance difference may have been due to the fact that all 10 zombies do not get sent out in 1 single batch though, because their total number of visible verts/tris surpasses the limit for single batches....so they contribute a couple of draw calls instead of just one. So I guess the difference boiled down to 2-3 calls for a bunch of batchable meshes vs. 1 call for a skinned mesh. Skinned mesh seemed to win.
     
  10. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    5,041
    Firstly, I'm no expert either!

    I was curious because I haven't really seen much of a FPS hit when draw calls are only changing by a small amount. Obviously many factors but in the stuff that I have done I would expect 10ms on the 3GS to be the difference between (for example) 40 and 60 draw calls, not x and x+3.
     
  11. marjan

    marjan

    Joined:
    Jun 6, 2009
    Posts:
    563
    So i finally made a real comparsion test. Test setup:

    I have one robot consisting mainly of Head, body, Upperarms, lowerarms, hands, pelvis, Legs.

    A: Old Transformbased Setup.
    My Old setup was a transform hierarchy. Connected to the mentioned meshes were also Eyes, Mouth, Antennas, Weapon. The Transforms were animated in Maya. I used one Material on this, with a modified Version of Angry Bots Character Shader.

    I wrote a script that would instantiate this Robot 40 Times.

    B: New SkinnedMesh Setup.
    I combined all the meshes to one and made a simple Rig. 3 Joints for Legs and Arms. Hip, Body, Head Joints. Animated that a bit.
    extended Script to switch between those to models.

    With Unity 3.4 i build a test to ipad1. AND THE DIFFERENCE WAS BIG TIME!

    So here is a Profiler Output for Methode A:

    iPhone Unity internal profiler stats:

    cpu-player> min: 29.4 max: 33.5 avg: 31.6
    cpu-ogles-drv> min: 22.9 max: 61.5 avg: 45.2
    cpu-waits-gpu> min: 0.4 max: 34.8 avg: 13.6
    msaa-resolve> min: 0.0 max: 0.0 avg: 0.0
    frametime> min: 89.5 max: 95.2 avg: 92.3
    draw-call #> min: 8 max: 8 avg: 8 | batched: 1080
    tris #> min: 65784 max: 65784 avg: 65784 | batched: 166936

    verts #> min: 85308 max: 85308 avg: 85308 | batched: 85280
    player-detail> physx: 0.4 animation: 4.1 culling 0.0 skinning: 0.0 batching: 6.3 render: 6.3 fixed-update-count: 4 .. 5
    mono-scripts> update: 0.0 fixedUpdate: 0.0 coroutines: 0.0
    mono-memory> used heap: 270336 allocated heap: 356352 max number of collections: 0 collection total duration: 0.0

    As you can see, it batched nicely! 8 Drawcalls only for 40 Robots, 1080 Meshes batched dynamically! As you see the frametime is around 90, which is only 11 FPS. This was with GLES 2.0, no antialiasing.

    And now for the skinnedmesh:

    iPhone Unity internal profiler stats:

    cpu-player> min: 12.4 max: 15.5 avg: 13.8
    cpu-ogles-drv> min: 4.3 max: 5.8 avg: 4.7
    cpu-waits-gpu> min: 0.6 max: 31.3 avg: 17.1
    msaa-resolve> min: 0.0 max: 0.0 avg: 0.0
    frametime> min: 20.5 max: 50.7 avg: 37.2
    draw-call #> min: 42 max: 42 avg: 42 | batched: 0
    tris #> min: 59864 max: 59864 avg: 59864 | batched: 0

    verts #> min: 79468 max: 79468 avg: 79468 | batched: 0
    player-detail> physx: 0.2 animation: 0.7 culling 0.0 skinning: 9.4 batching: 0.0 render: -13.9 fixed-update-count: 1 .. 3
    mono-scripts> update: 0.0 fixedUpdate: 0.0 coroutines: 0.0
    mono-memory> used heap: 249856 allocated heap: 356352 max number of collections: 1 collection total duration: 1.9

    There are 5000 less verts, i think this is because i did not skinn the gun.
    So here you see we have 40 Drawcalls, 1 for each Robot (2 more for an OnGUI Button)
    But the Frametime dropped to 20! Which is 50 FPS. Thus: roughly 5 times faster.

    In Unity 3.5 this might be different, as there seams to be a lot of promised optimizations.

    So if i see this right, skinned Mesh is clearly the way to go.
     
  12. marjan

    marjan

    Joined:
    Jun 6, 2009
    Posts:
    563
    Hmm, actually building with unity 3.5 shows slower results

    frametime for A dropped to 97.8

    frametime for B dropped to 24


    So, both got slower by 20%.

    Well, this could be for whatever reason. But actually i was expecting the opposite...
     
  13. TrialByFun

    TrialByFun

    Joined:
    Jun 23, 2009
    Posts:
    97
    don't you mean faster? A lower frametime means a faster framerate.
     
  14. marjan

    marjan

    Joined:
    Jun 6, 2009
    Posts:
    563
    No, but my term dropped is missleading. in 3.4 it was 20, in 3.5 its 24. Actually higher. Thus slower. By dropped i rather meant speed.
     
  15. MrScary

    MrScary

    Joined:
    Dec 8, 2007
    Posts:
    94
    I know I'm late to the party here, but I have a question. If you combine 10 monsters or machines into one SkinnedMeshRenderer... How do you animate them separately? thanks