• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Azmodii · Aug 27, 2013 at 10:58 PM · c#gameobjectproceduraldrawcalls

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);
 
         }
Comment
Add comment · Show 11
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Azmodii · Sep 10, 2013 at 02:04 AM 0
Share

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.

avatar image dorpeleg · Sep 10, 2013 at 10:40 AM 0
Share

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.

avatar image ArkaneX · Sep 10, 2013 at 10:56 AM 0
Share

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.

avatar image Azmodii · Sep 10, 2013 at 12:00 PM 0
Share

1 prefab, the prefab has 1 mesh, 1 material (Using 1 texture), 1 shader.

There are 100-300 draw calls due to the sheer amount of these "tiles". Last count on an average map was well above 10,000 tiles.

I actually think I see the issue... The code will modify the material by changing alpha and such. Will unity then ignore this object during batching operations?

avatar image ArkaneX · Sep 10, 2013 at 12:17 PM 0
Share

Up to my knowledge, different material = unable to batch. But I might be wrong.

Do you need completely different "alpha and such" values for each hex? If not, then maybe it would be good to create an array of materials with modified properties, and then assign one of these materials to each hex.

avatar image dorpeleg · Sep 10, 2013 at 05:19 PM 1
Share

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.

avatar image Azmodii · Sep 11, 2013 at 02:23 AM 0
Share

Thanks for all the tips guys, its appreciated.

I'll overview what is happening here a little more;

The "SpawnGame" script reads information from a stored class instance (the simulation) and then decides what objects to make where.

When it creates the tile, it accesses the script attached to it, and sets a variable to the instance of the tile in the simulation (so the simulation and the "game objects" can talk with each other, think an abstract $$anonymous$$VV$$anonymous$$).

Even if I have no code modifying the material attributes of the "tile instance", it refuses to batch these with a script attached. I have tried both static and dynamic batching and this occurs regardless.

Remove the script and voila! It batches as expected. Attach a script that doesn't inherit mono behaviour and it also works as expected, but this is impractical as to play animations, check positions etc it must inherit this.

I can get around this by attaching a script to the camera and using raycasthit to return the position, then check the simulation for the "tile instance" with that position, but that results in extra CPU time for both the raycasts and the for/foreach loop. It should be noted that this method does not increase the draw calls.

I can achieve the same alpha modification by using an animation (To be honest I dont know why I didn't, I'm just trying some fast prototyping and completely overlooked that), but there is no way to play this animation without using either of these methods.

In a typical game, the $$anonymous$$imum amount of tiles present would be 1000-10000 depending on performance profiling once its at a further stage.

And to clarify dorpeleg, it batches fine without the script, so I dont think the upper vertex limit is an issue here.

avatar image robertbu · Sep 11, 2013 at 05:52 AM 1
Share

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?

avatar image Azmodii · Sep 11, 2013 at 06:28 AM 0
Share

It occurs with an empty mono behaviour script.

And as a matter of curiosity, wouldn't unity batch these until said material was modified? Not simply refuse to batch them on the premise that it may?

avatar image robertbu · Sep 11, 2013 at 06:39 AM 0
Share

I would have expected them to batch until the material is modified.

avatar image Azmodii · Sep 11, 2013 at 07:12 AM 0
Share

As would have I, hence the if statement. I can deal with it acting this way, I'm just baffled why a script attached with no code would cause this behaviour.

The script is attached in the prefab, think it will make any difference if I attached it in code behind at runtime?

1 Reply

· Add your reply
  • Sort: 
avatar image
2
Best Answer

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.

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image whydoidoit · Sep 11, 2013 at 06:51 AM 0
Share

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"
   }
avatar image whydoidoit · Sep 11, 2013 at 06:52 AM 0
Share

You would need to set the vertex colour of all of the vertices of the hex to the tinted color. See mesh.colours

avatar image Azmodii · Sep 11, 2013 at 07:10 AM 0
Share

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.

avatar image whydoidoit · Sep 11, 2013 at 07:15 AM 0
Share

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.

avatar image Azmodii · Sep 11, 2013 at 07:29 AM 0
Share

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

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

18 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Combine objects instantiated at runtime 2 Answers

C# Check If Gameobject is within Collider 1 Answer

Refering to gameobject script is attached to 1 Answer

C# Preserving GameObjects' Previous Meshes 1 Answer

press e to speek -1 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges