- Home /
Batch drawcalls of GameObjects with a script attached?
Hi all,
I have a hexagonal grid that is procedurally generated at runtime, and currently it has between 100-300 draw calls depending on the map size, and it batches most - if not all - of the related tiles.
I am using GameObject.Instantiate to create these.
My issue is that as soon as I attach a script to the hex tile prefab (for functionality like OnMouseEnter, Input.MouseButtonDown etc... ) it stops batching them and increases the draw calls well into the thousands.
Any clues how to get around this?
I thought of simply creating a script that interacted with the hex grids, but was attached to another game object - but this seems inelegant. Is this really the only solution?
Here is the code;
foreach (Object_System.shell.tile _tile in _shell.tileList) {
GameObject tile = (GameObject)Instantiate(_tilePrefab);
Interface _script = (Interface)tile.GetComponent("Interface");
Manager_Interface _interfaceManager = (Manager_Interface)this.GetComponent("Manager_Interface");
_script._tileInstance = _tile;
tile.tag = "SystemMap_Tile";
tile.transform.position = _tile.position;
tile.transform.parent = shell.transform;
And the a snippet of code from the script attached to the GameObject;
void Update () {
// When mouse enters, start highlighting the tile
if (OnEnter == true) {
colorEnd = colorOnEnter;
colorNow = renderer.material.color;
colorEnd.a = Opacity;
Duration = OnEnterDuration;
float lerp = Mathf.PingPong (Time.time, Duration) / Duration;
renderer.material.color = Color.Lerp (colorNow, colorEnd, lerp);
}
As far as solving this issue goes, I was unable to do that and it seems very unlikely that I will be able to. $$anonymous$$y research concluded with a simple answer. No. For functionality like that, each "Object" must be unique.
As a quick and dirty workaround, I resorted to raycasthit's on the camera script. Performance hit is negligible, certainly a lot less than the thousands of draw calls I was getting.
As far As I know, draw calls should not be effected by scripts (unless you have something inside the script that is effecting draw calls).
If you can tell us what you are doing in the script (or even better, show code) then maybe we can see why the draw calls increase.
And my question is - why it has 100-300 drawcalls without scripts? Are you using separate textures or texture atlas? If separate, you should consider atlasing them, but if you're already using atlas, then maybe there's some issue with materials. For example you might assigned separate material instance for each hex, during procedural generation.
Please read here: link.
from the tips:
Batching dynamic objects has certain overhead per vertex, so batching is applied only to meshes containing less than 900 vertex attributes in total.
Are you absolutely sure you are not modifying the material directly or indirectly with a script? That is, do you get the same behavior if you attach a script derived from $$anonymous$$onobehaviour that does absolutely nothing?
Answer by whydoidoit · Sep 11, 2013 at 06:48 AM
You need to write your own shader to shade your hexes. As I believe was pointed in the comments, as soon as you do renderer.material = anything you have broken batching.
What you need to do is shade the hexes based on "something else" apart from the material's color: probably the best thing would be the vertex colours of the model which you can change without breaking batching.
You could of course go the whole hog and guarantee 1 draw call by drawing all of the hexes as part of a single mesh. Your hex scripts could be used to add the necessary points to the mesh - but that is a bit more advanced but ideal in these cases.
Something like this would probably do it:
Shader "whydoidoit/Vertex Color Tinted" {
Properties {
_$$anonymous$$ainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRA$$anonymous$$
#pragma surface surf Lambert
struct Input {
float2 uv_$$anonymous$$ainTex;
float4 color;
};
sampler2D _$$anonymous$$ainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex).rgb * IN.color;
}
ENDCG
}
Fallback "Diffuse"
}
You would need to set the vertex colour of all of the vertices of the hex to the tinted color. See mesh.colours
Thanks for the custom shader! That will help me a great deal, I am still looking into coding shaders but I havent touched on that quite yet,
The issue is a little more complicated though, as any script attached to these objects - with or without modifying the material, results in Unity ignoring them during batch operations. Any script with $$anonymous$$onoBehaviour to be exact.
I am setting a public custom variable inside each "Instance" of this script, but surely that cant be resulting in the behaviour?
public Object_System.shell.tile _tileinstance;
This is set during the Awake function of my scene.
And I think I may have to resort to a single mesh solution. Early performance profiling suggests the draw calls will be an issue down the track.
I doubt that - the reason for not dynamically batching can be:
Not the same material
Not close enough together
Too many polygons
When you run the game, click on the hexes and ensure that the inspector doesn't show an "instance" after the material name - which is a dead giveaway that "something" has gone and fiddled with it.
So a script will only break batching if it manages to make the mesh more complicated or changes any property of the renderer.material.
Your dead right. It 100% says instance after the material name.
Just to throw a spanner in the works, if I attach the script in the code behind - it works like a charm. Attach the script to the prefab, same behaviour.
I can mark this as solved (as practically all the answers here have provided me with good alternatives - Thanks guys!) but its still rather curious why this is happening.
Beats me!
Your answer
Follow this Question
Related Questions
C# Adding Components From Other Gameobjects 3 Answers
How to handle a MASSIVE amount of game objects? 2 Answers
Camera to follow a target within a circle? 1 Answer
Assigning current color to a variable for fade out (C#) 0 Answers
Destroy + Score 1 Answer