Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Optimizing an asset for performance

Discussion in 'General Discussion' started by Grimwolf, Dec 11, 2014.

  1. Grimwolf

    Grimwolf

    Joined:
    Oct 12, 2013
    Posts:
    296
    There's a few basic facts about how a model is rendered that I'm fuzzy on when trying to optimize performance, and I'm hoping to get some clarification.
    Say I have a rock. I make it into a prefab with the model divided into 8 even pieces so that the areas not being rendered, say because they're in the ground or behind a wall, can be removed or occluded.
    The number of faces would be the same whether it is divided or not, but when divided the number of edges and vertices would increase. Somewhat significantly when divided into so many pieces.
    If cases where most or all of the stone is being rendered anyway, how much of an impact would these extra edges/vertices have on performance, if at all? People normally only consider the poly/triangle count of a model, but I doubt that is truly the only important factor, at least in this case.
    If it actually is significant, then I could just use a second merged model as well for such cases, but otherwise it might not be worth the hassle.
    Another issue I'm not sure on is how the texture would be handled in such a case.
    If half the model is not being rendered, then half the texture is not actually in use. But I'm assuming the texture has an equal hit on performance regardless.
    In this case, I think it would be best to actually use 8 separate and much lower resolution textures (a single 1024x1024 instead becomes 8 128x128 textures). One assigned to each piece of the model. Would this be correct?

    Finally, I have a more general question. Say I have two separate rock assets. If I had two different models/textures, all with equal triangles and resolution between them, would it actually have a lower impact on performance if each stone were actually duplicates/instances, rather than each using a separate model/texture?
    I've been told that with 2D assets, instantiated sprites actually hit performance less than multiple sprites of the same size. I'm just unsure if this logic applies in any way to 3D as well.
    If it does apply in this case as well, then that also creates a bit of gray area as to whether I should use a second merged model or not for cases when every piece is being rendered.
     
  2. Jaimi

    Jaimi

    Joined:
    Jan 10, 2009
    Posts:
    6,177
    I would think it would be the opposite in most cases. What you are fighting against is "talking to the video card/GPU". One material/texture means that it does setup one time (both on CPU and GPU) - this can include transferring the texture(s) across the bus to gfx memory, any prep the gpu must do for textures, etc.

    instancing meshes will of course be much faster than not being instanced. Try to keep the number of materials and meshes to a minimum.
     
    angrypenguin likes this.
  3. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    No, that would actually be far worse in almost all cases. A new texture means a new draw call, so your rock is taking 8 draw calls to draw the same thing. All 8 textures are probably also going to be loaded anyway, so you're also not likely to be making a saving there. It could also mess with stuff like mesh topography.

    I personally wouldn't split up a rock at all. That is assuming you mean a boulder or stone or something. It it's planet sized then that's different. The thing is that rendering pipelines are already set up to do a pretty good job of minimising the work that they have to do. By splitting it up into more objects you're increasing the number of separate things it potentially has to consider (there are now 8 items instead of 1, even though to a player it's the same rock either way) without necessarily giving it a more effective way of culling those pieces out than it would have had anyway.

    You're also introducing more opportunities for errors. For instance, splitting up the rock means that someone could accidentally move a bit of it, creating an art bug that wouldn't otherwise be possible.

    Basically, make your art as clean and orderly as possible, in ways that make sense for other artists to work with it. Keep resource usage to reasonable minimums, and re-use resources like textures, shaders and materials over multiple objects wherever possible. Past that, let the import and rendering pipelines take care of themselves.

    As a rule of thumb, I wouldn't start considering splitting a mesh up unless it was going to take up significantly more than a screen the majority of the time. So you're really talking about level geometry, massive vehicles, stuff like that.
     
    zombiegorilla likes this.
  4. N1warhead

    N1warhead

    Joined:
    Mar 12, 2014
    Posts:
    3,884


    Just do like me, do not go beyond what's absolutely required, if you know a polygon is going to be unseen, then delete that polygon.

    Pretty much don't go beyond your means.

    Stick to decent texture sizes (512 x 512) - is what I use almost all the time for PC, but when needed, I'll do a 1024 x 1024.

    A lot of it really comes down to experience knowing when and when not to use a higher quality thing (Texture, Model, etc).
    That all comes in time, you'll get it eventually.

    There is no set way anything should be done, if you have a 12 core processor with a 50 gig graphics card and 64 gig of ram, well then, guess what, you can build something better than Xbox One and PS4 then go for going above and beyond the next 2 generations of consoles LOL.
     
  5. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Make source textures as big as you want. The import pipeline handles that too. If someone wants to use it at a particular size they can tell the importer that and it'll handle it for them.

    Learn the pipeline, and don't do any work that it'll do for you. It's better for everyone that way.
     
  6. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    If you're unsure of something, open up an empty Unity scene, drop it in there, and have a play with it. The Stats button will tell you what's happening. Have a play with import settings for both meshes and textures, different materials and their settings, textures, different types (and numbers of) lights, forward/deferred rendering modes, etc. etc. and see what impact it has. You'll learn far more from playing with it than reading about it.

    Also, what a human thinks can be seen and what a computer thinks can be seen are often different. Fastest way to learn that is to play with it, too.
     
  7. Grimwolf

    Grimwolf

    Joined:
    Oct 12, 2013
    Posts:
    296
    That's interesting. So simply being an additional object, independent of anything like polys/resolution, has a significant impact on performance. That explains why instantiating an object would be so useful for performance.
    That means it would also be better to have a single rock with a complete and well defined shape that can be flipped around, as opposed to a few differently shaped rocks with the bottom carved out to save polys.

    The entire idea here was based on the impression that occlusion culling only worked on separate meshes. Such that a bush behind a building would not be rendered, but the backside of the building still would.
    Does it actually not render individual faces within a single mesh?

    All that combined would also mean that, if I wanted to create a larger, more detailed rock formation in a scene, it would actually be better to mash together a bunch of instantiated rocks than to create a separate model and texture all together. Performance-wise, at least.
     
    angrypenguin likes this.
  8. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Careful with "instantiating" and "instancing", they are very different.
     
  9. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Different levels of culling are performed at different stages of the rendering pipeline. Occlusion culling is done early to decide what meshes should be submitted for (potential) rendering. Later tests are performed to see which faces should be drawn. When drawing faces, tests are performed to see what pixels should be drawn.
     
  10. N1warhead

    N1warhead

    Joined:
    Mar 12, 2014
    Posts:
    3,884
    That is true, I just do it still though. I'm not sure if Unity adds the actual texture file into the build (to save space) I just go ahead and make it the size I like.

    Like example (random numbers)
    I have a 4096 x 4096 texture, lets say it saves at 64 megs.

    Well, if it's going to add 64 megs extra to the build then I'll just make it a 1024 x 1024 and make it 1.5 megs to have the build smaller.

    (Or does Unity go ahead and compress it when it's built?)
     
  11. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    For an individual object, not so much. For many objects, definitely.

    One draw call isn't a big deal. But imagine your rock is used 3,000 times in a scene, and 500 of them are visible at once... If you split it up, how much extra work are you making the batching system do, vs what (if any) benefit is it giving you?
    Don't ask. Experiment.
     
    zombiegorilla likes this.
  12. Grimwolf

    Grimwolf

    Joined:
    Oct 12, 2013
    Posts:
    296
    Whoa, so when you say that it tests to see which pixels should be drawn, you mean that, if I had a 2048x2048 texture, but the UV only covered one quarter of the surface, it would have a comparable performance hit to that of a 1024x1024 texture in which the UV covered all of it?
    So then if I had 4 rocks all being used in a scene, it would be better for performance to double the texture size and place each of their UVs on a separate section of the texture, instead of using 4 separate textures.
    Or am I completely misunderstanding, and you mean that it divides the rendered faces into the pixels they occupy on screen? That would much less interesting :/
     
    Last edited: Dec 11, 2014
  13. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    No, textures effect the pipeline later again, and not in a manner where size matters (for the sake of this conversation). When a triangle on your model is being drawn it is mapped to some pixels on the screen. For each of those pixels, if the shader needs to read from one or more textures that's when it looks them up.

    When I said "pixel" above, I mean pixels of a triangle being rasterized to the screen, before it's decided what colour to make them.
     
  14. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Yep, this is called "atlassing", and it's a common way to reduce draw calls. It lets the batching part of the pipeline potentially treat a bunch of meshes all as the same thing, and/or at least put things in an order that minimises costly state changes.
     
  15. MrTiger

    MrTiger

    Joined:
    Jan 9, 2014
    Posts:
    29
    And one thing i find out after long time is ..if u scale is not in 1,1,1 then ..even you copy a same object it give u another Draw call .. (at least for me )
     
  16. Grimwolf

    Grimwolf

    Joined:
    Oct 12, 2013
    Posts:
    296
    So resizing an instance within the scene creates another draw call? That doesn't seem right. In that case I would think it'd create extra draw calls just as easily from moving it around in the scene or rotating it.

    On another note, after finding out about atlasing, it seems to be relatively common to generate atlases dynamically by mashing existing textures together into one giant texture. So it isn't even necessary to create one myself like that.
    Very good stuff...
     
    Last edited: Dec 11, 2014
  17. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Again, it comes down to the rendering pipeline. When stuff is instanced it has to be exactly the same for each instance. As in, it draws the same set of verts in different locations. If you scale the object the verts aren't exactly the same, so they can't be batched.

    Static batching is a bit different, I think, in that all of the verts are combined at build or load time (not sure which) into a single combined mesh.
     
  18. Grimwolf

    Grimwolf

    Joined:
    Oct 12, 2013
    Posts:
    296
    Going by this, it does look like the automatically applied "dynamic batching" does not work if you change the scale on an object, among other things.
    Like @angrypenguin said, that would require Static Batching, which is an optional setting that requires Unity Pro.
    Apparently it can still work if they have non-uniform scale, which is very confusing. I would assume it'd be the other way around.
     
    Last edited: Dec 11, 2014
  19. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    I think if you scale the object uniformly it still dynamically batches. For example if you have many instances of the same object at a 1,1,1 scale and one that is 2,2,2 they will all batch together. Please correct me if I'm wrong.
     
  20. MrTiger

    MrTiger

    Joined:
    Jan 9, 2014
    Posts:
    29
    Not really... the instances at Scale 1,1,1 will batch with other instances of the same object with scale 1,1,1 but if it is re-Scaled like 2,2,2 or 3,3,3 .. or something and if it is duplicated .. this scaled instances will batches with there respected Scaled instances ..
     
  21. Grimwolf

    Grimwolf

    Joined:
    Oct 12, 2013
    Posts:
    296
    Here's something that confuses me. This is a video on the art workflow used in Diablo 3.
    If you skip down to "The Game Canvas: 2.5D Geometry" he talks about how they cut out the back half of many objects to improve performance, since they wouldn't be seen anyway.
    Based on what I've read here though, it would have been better to create full models for performance, since they could just be rotated around for more variation without increasing draw calls, and the backside would get culled anyway.
     
  22. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    It also depends on the engine. I'm not sure but you can test it. Make two different versions of a rock. One with the unseen bottom and one without. Then play the scene with each and see which scene is faster, takes up less vram, etc.
     
  23. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Well, they don't rotate things and they are only ever seen from one direction, so it makes sense. Triangle culling is super cheap, but it isn't entirely free, and in that specific use case they had nothing to gain from having the extra triangles there. The only thing that would ever happen to those triangles is that they'd get culled out, every frame for every object on every computer ever. So why have them?

    As for why they don't rotate things... those guys are very deliberate with their art. To them, for a fixed-perspective game the idea of "just rotate things for more variation" would probably be considered ultra sloppy. I suspect that if they need more variation, they'll go to the concept stage and make more variations in a very deliberate and methodical manner.
     
    Grimwolf likes this.