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. Dismiss Notice

Question Control the number of public variables from the structure of the gameObject in the script

Discussion in 'Scripting' started by yaroslav_rodionov, Jul 9, 2023.

  1. yaroslav_rodionov

    yaroslav_rodionov

    Joined:
    Nov 8, 2021
    Posts:
    5
    Dear Unity fellows,
    In my C# script I want to expose a control parameter for each child of the gameObject the script is attached to.
    As I understand, the control parameter is usually implemented as a public variable.
    In the ordinary situation public variables are declared before the start() function of the script and their number is fixed.
    How can I expose the necessary number of control parameters if this very number is equal to the number of children of the gameObject?
    Yaroslav.
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,140
    I don't really know what you mean by "control parameters". But, it almost sounds like you want an editor script which can help you edit how your script shows in the inspector.

    But, I would also question what you are actually attempting to do to see if it's even worth your time to go through all that.

    It's also possible you want a collection, like a list or array.
     
  3. yaroslav_rodionov

    yaroslav_rodionov

    Joined:
    Nov 8, 2021
    Posts:
    5
    Thanks for the immediate reply!
    I have a following task. My game object has many LOD groups. Say, you imported a cathedral from blender.
    The cathedral has many carefully placed columns, each one with a LOD group (of course, all identical columns have identical LOD groups). Then, it has many arches (and each arch has its own LOD group, and again, identical arches have identical LOD groups).

    At the moment, to my knowledge, the only solution in Unity to implemet all these LODs is to make a prefab with LOD group for a column and for an arch. Then we import the cathedral without columns and arches and place prefabs for all columns and arches in the right places. It is qute tedious.


    I'm writing a script to avoid this. We attach the script to the cathedral. Then it will create (in this particular example) two public variables: columns and arches. Each parameter is a float array (LOD0, LOD1 for columns), or (LOD0 for arches)... the number of LODs depends on how many LODs are attached to each object. Then the script implements correct LOD rendering for all the objects. The user simply enters correct number for each type of the mesh.

    For example, for all the columns the user enters just two floats: 0.5 and 0.3. For all the arches just single number: say 0.6. That is why I need to know how many LOD objects are there in my gameObject.

    (See the structure of the game object in the attached screen)
    Y.
     

    Attached Files:

    • Q2.png
      Q2.png
      File size:
      62.4 KB
      Views:
      34
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    What you want is a custom editor for your component, which changes how it's drawn in the inspector: https://docs.unity3d.com/Manual/editor-CustomEditors.html

    Definitely possible to write a custom inspector that can expose and control values of child game objects. Though if you're completely new to the subject there's a lot of learning ahead of you.
     
    angrypenguin likes this.
  5. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,503
    Doing that inside of Unity rather than in your DCC tool can have significant performance benefits, though. If your exporter is giving Unity a bunch of separate objects with separate data to draw identical items then there's a distinct possibility that it's preventing opportunities for instancing and/or batching. If you look at the MeshFilters on your objects, are identical objects referring to the same mesh data or to separate meshes?

    For this reason among others, a common content creation workflow in engines such as Unity is to create the unique objects in your 3D content creation software, and assemble them into scenes in your engine. This gives the engine more opportunity to identify where and what optimisations it can perform in cases where the exporter / importer isn't providing sufficient data.

    - - -

    Of course, if you're doing this because you're using off-the-shelf assets then they are what they are. You might be able to have scripts which replace all identical data with references to the first instance of that data, but this relies on other items not being messed up elsewhere (e.g. if all of the columns in your cathedral are identical but were exported with different pivot points then there's no simple automated fix).
     
  6. yaroslav_rodionov

    yaroslav_rodionov

    Joined:
    Nov 8, 2021
    Posts:
    5
    Thanks for warning me on this!
    I'm creating all the 3D models by myself, and the whole point to create LODS is to have optimization of the game. Therefore, if exporting many identical objects as separate meshes is not optimal, this is not an optimal solution for our project.

    Do I understand correctly, that I can loose significant part of optimization due to LODs to the fact that my identical meshes are taken as distinct ones?

    All 3D modeling is done on blender by me. As a result, I can make sure that all the identical objects have identical pivot points and so on. Saying this, my question is as follows:

    Is it possible to export my "cathedral" from blender in such a way, that unity substitutes identical objects with reference to the first instance of this object?
     
    angrypenguin likes this.
  7. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,503
    Yes, though it's not specific to LODs or even to Unity. It's about how GPUs work.

    Excellent, that means you can control every step. :)

    I can't see why not, but I don't know for sure, and couldn't tell you how to do it, because I've not had to worry about that detail for a long time. In my work we've either planned around everything being unique, or exported modular pieces which are configured and assembled in engine.

    If it functions as I'd expect then Unity wouldn't have to "substitute" anything, it would just know which objects use the same underlying data at import time. If Blender has a way to create "instances" (as opposed to copies) of objects, I'd start with that and just exporting it, then checking if it shares or copies data after it's imported.
     
  8. yaroslav_rodionov

    yaroslav_rodionov

    Joined:
    Nov 8, 2021
    Posts:
    5
    Thank you for all your advice!
    Now, I have a question about this script.
    It works, but due to my lack of expertise, I'm afraid I do things non optimally and would be glad to hear some critique from you.
    The idea was explained before.
    So I have the imported mesh (cathedral, see Fig. 1 for the hierarchy), it has a child "LOD". This child contains all the collections of identical columns, each of which has identical LOD group. I made those columns in blender and they are instances of a single mesh. Good thing is that Unity does recognize them as identical mesh in Mesh Filter.

    Now, the script works as follows. I expose a public array of transforms LODs: public Transform[]. The length of this array is equal to the number of different groups of identical LOD objects (columns, arches, doors). In my particular example I have only columns, hence the length of this array is 1. (see Fig. 2)

    I feed my prepared column prefab (with all tuned LOD settings and transfades) into this LODs field. This prefab is "LOD_prefab" in Fig.2
    Now, the script should create additional empty game object in the hierarchy, I name it Unity_LOD. And substitute all the instances of my identical columns with an instance of my prefab. The previous LOD groups should be made inactive.

    Now it is desirable, that this new object Unity_LOD with inserted prefabs stays in the hierarchy after the runtime of the game.

    But I noticed some strange things (kinda expected, but still).
    My prefabs keep accumulating after each runtime, so I have to destroy them with DestroyImmediate() function.
    My created object Unity_LOD equired some demonic little plus sign in a green circle.

    I suspect that I heavily abuse unity memory usage and kill all the performace benefits due to my lack of experience.
    Here is the code:
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Xml.Linq;
    5. using UnityEngine;
    6. [ExecuteInEditMode]
    7. public class mesh_parser : MonoBehaviour
    8. {
    9.     public Transform[] LODs =  new Transform[4]; // Since we don't now how may groups of identical objects are in the mesh, I instantiate
    10.                                                  // this prefab container with length 4, and resize it later in Start() function.
    11.     private GameObject Unity_LOD;
    12.     private Transform root;   // this refers to the initial container of all the LOD objects in the mesh (LOD container in the hierarchy)
    13.    void Start()
    14.     {
    15.         // Here I check if this empty game object Unity_LOD is already created. If yes, I reassign it to my private container Unity_LOD
    16.         for(int i = 0; i < gameObject.transform.childCount; i++)
    17.         {
    18.             if (gameObject.transform.GetChild(i).name == "Unity_LOD")
    19.             {
    20.                 Unity_LOD = gameObject.transform.GetChild(i).gameObject;
    21.             }
    22.         }
    23.        if(transform.Find("Unity_LOD") == false) {
    24.  
    25.             Unity_LOD = new GameObject("Unity_LOD");
    26.         }
    27.         // Put it in the cathedral:
    28.         Unity_LOD.transform.parent = gameObject.transform;
    29.  
    30.         // Found the child called LOD (the container with my columns)
    31.         root = transform.Find("LOD");
    32.         // resize the initial array of groups (in our case, size = 1)
    33.         Array.Resize(ref LODs, root.transform.childCount);// the num of LOD groups in the gameObject: "columns", "cubes"...
    34.  
    35.         // main loop. k loops over all groups of identical meshes: k = 0 (columns), k = 1(arches) and so on. In our case,
    36.         // the loop contains a single element k = 0 (coliumns)
    37.  
    38.         for (int k = 0; k < root.transform.childCount; k++)
    39.         {
    40.             GameObject[] children = new GameObject[root.transform.GetChild(k).childCount];
    41.             Transform[] insert = new Transform[root.transform.GetChild(k).childCount];
    42.      
    43.             // Here I check if I already added prefabs in the previous runtime. If yes, I'd like to destroy them.
    44.             // Otherwise the prefabs keep accumulating in the same positions!
    45.      
    46.             if (Unity_LOD.transform.childCount != 0)
    47.             {
    48.                 for (int i = 0; i < root.transform.GetChild(k).childCount; i++)
    49.                 {
    50.                     DestroyImmediate(Unity_LOD.transform.GetChild(0).gameObject);
    51.                 }
    52.             }
    53.      
    54.             // Here I run through all the children of the columns group: column_LOD, column_LOD.001
    55.             // and disable them in the game canvas.
    56.      
    57.             for (int i = 0; i < root.transform.GetChild(k).childCount; i++)
    58.             {
    59.                 children = root.transform.GetChild(k).gameObject.transform.GetChild(i).gameObject ;
    60.              
    61.                 if (LODs[k] != null) // <==Check if I added the prefab to LODs public array.
    62.                 {
    63.                     children.SetActive(false); // <== hide initial columns
    64.                  
    65.                     // insert prefabs:
    66.                     insert = Instantiate(LODs[k], children.transform.position, children.transform.rotation, Unity_LOD.transform);
    67.                 }
    68.             }
    69.         }
    70.    }
    71.    void Update()
    72.     {
    73.      
    74.     }
    75. }
     

    Attached Files:

    Last edited: Jul 10, 2023