Unity - renderer.material issue
Hi Guys. For my comp E entry i've been messing around with materials on objects. My game is having performance issues and I now read that it could be because of renderer.material which is creating clones but not destroying them, so they are left as assets in my game (or something like that). I basically have the following script attached to objects, I do a raycast and then send a message activatePower/deactivatePower to the object which changes the material on the object from 1 material to another, and then back again:
Could this be what is causing the performance issue? Can someone explain to me in "Noob speak" what the issue with this is, and a possible solution.
public Material activatedMaterial; private Material deactivatedMaterial; void Start() { deactivatedMaterial = renderer.material; } void activatePower() { renderer.material = activatedMaterial; } void deactivatePower() { renderer.material = deactivatedMaterial; }
Could this be what is causing the performance issue? Can someone explain to me in "Noob speak" what the issue with this is, and a possible solution.
Comments
deactivatedMaterial = renderer.sharedMaterial;
renderer.sharedMaterial = activatedMaterial;
This will just assign the material as a reference, rather than creating a local instance.
http://docs.unity3d.com/Documentation/ScriptReference/Renderer-material.html
As far as I know, it's only when you change properties on a renderer.material (as opposed to renderer.sharedMaterial) that you bleed instances into your scene, and wreak havoc on your draw calls. It doesn't happen if you're assigning existing materials to your renderers.
This could indeed happen if you're getting instanced materials all over the place, so definitely check for that. (While the game is playing in the editor, go over your objects to see if any of them are using materials with the "(Instance)" suffix to them. You could write a handy script to check for this.) Otherwise, try and get as many of your objects in your scene to use the same materials. If they're using the same shader, you can look at combining several of your smaller textures into one larger texture, and assigning your meshes' UVs to the new texture, so that they can share materials. Even without static batching (which is a Pro feature), dynamic batching could lower your draw calls quite a bit.
--
I'll try and explain in "noob speak" what's happening, bearing in mind that I'm no graphics programmer, so my analogy could be kind of wrong. :P
Imagine that a draw call is like a school bus, taking kids to work (work being your graphics card). The bus can only take kids who're wearing the same school uniform. Whether the bus is full, or whether the bus only has a couple of students, it still takes a lot of time to get to school. So, one of the ways that you could make the overall trip faster, is if you try and group your students so that students who're going to the same school are on the bus at the same time, so that you're getting as many kids to the same place as possible. This is batching. You're effectively combining a whole bunch of smaller meshes that use the same material (the same "school uniform") into one larger mesh, so that they can be transported all at once.
(And, in reality, there are things in addition to materials that can require more draw calls, like whether you're using real-time lights, or if you're using transparency, or some other things I've probably forgotten.)
https://www.dropbox.com/s/ys8lw2tgm99812d/Screenshot 2013-10-24 22.39.15.png
main thread is 76.3ms and renderer is 0.6ms - so I take it is a computation issue
But it fluctuates greatly. Did you have a lag issue when you ran my comp E entry? I know you are judging the comp, so if you do not want to check now I would totally understand. Can someone else maybe check too?
I dont think this is the cause of your performance issues, but what was the reason for drawing out all the letters on your signposts with cubes, instead of just putting the message in a texture?
Oh and another thing @FanieG, it doesnt look like your walls are prefabs. Make sure all the often-repeated and non-moving stuff in your game are made into Prefabs and Marked as Static. This will help Unity batch your geometry more efficiently. I'm no Unity expert - so someone please correct me if this advice wrong.
https://dl.dropboxusercontent.com/u/187819585/Compe E 5.4/Compe E 5.4.html
It didn't do much to my main thread and renderer stats, but my draw calls did come down significantly. Would you mind terribly to give this build a try and see if there is any improvement in the lag?
Raycasts are pretty cheap, afaik.
Dijkstra's alg is exhaustive, so you end up traversing every single node in order to find a path. That's why it doesn't seem to matter where the things are that you're trying to use pathfinding for - they have to calculate the same amount no matter what. Try reading up on related pathfinding algorithms like A* (which is similar to Dijkstra's alg) except is all about early solutions and avoiding redundant computation. Or do your pathfinding beforehand and just store route data in your nodes "When this looks like this, go here" instead of re-calculating that every frame.
Also, try distributing your pathfinding out across multiple frames, once you know which node you want to go to, you shouldn't have to keep running the main pathfinding logic until you either get to that node or don't reach it for X seconds or whatever.
It sounds like you're recalculating the pathfinding every single frame - there's a whole bunch of optimisations you can do: only recalulating when you need to, only recalculating the last bit of the solution that has changed, to spreading the pathfinding out over several frames or switching to a new algorithm like @dislekcia suggested.
Pitty it only improved your framerate marginally though.
Firstly only recalculate which nodes the player and monster belong to when you need to do pathfinding.
Secondly I would use a state machine for the Ai. When the Ai is moving between two nodes, you dont need to run the pathfinding algo, he just has to get to the next node. Once there he can make a decission as to which node to get to next - find which node the player is nearest, find where it is, and find a path between. Once this has been done once, the Ai should have the next node he needs to move to, and should not pathfind again until reaching it.
So you have a "moving" state and a "searching" state. 99% of the time, the Ai is just moving slowly to the next node in the "moving" state. When he reaches it, you switch to the "searching" state for 1 frame and do a single pathfinding run. When pathfinding is complete and he has a destination you switch back to "moving" to the next node.
Thats how I'd approach the problem. That way you only run the pathfinding once when the Ai reaches a node.