Страница 1 из 3

Combine Children Extented (расширенный)

СообщениеДобавлено: 25 дек 2009, 18:45
Neodrop
Как известно, объединение объектов, использующих один материал в группу, сильно повышает производительность. Для этого в стандартной поставке Unity существует скрипт Combine Children (далее : Комбайн)
В процессе работы, накопились некоторые добавки к стандартному скрипту Комбайна. Делюсь :

Изображение

[V] Frame To Wait : сколько кадров на старте скрипта, ждать, прежде чем произвести объединение.
К примеру, у вас есть объект, содержащий ещё сотню объектов, которые в свою очередь содержат чилдов. Префаб внутренних объектов, оборудован Комбайном с собственными настройками. На старте, все они скомбайнятся и мы получим поменьше мешей, но всё равно кучу. Почему бы не скомбайнить их снова?
Ставим циферку 1 и в следующем кадре, после завершения комбайнинга чилдов, слепляем полученные меши вновь и получаем 5 - 10 мешей вместо старых сотен.
[V] Combine On Start - скрипт сработает на старте композиции (если он активирован, конечно).
[V] Destroy After Optimized - убить все исходные объекты. Осторожно! Если на этих объектах коллайдеры, они тоже будут уничтожены.
[V] Cast Shadow - конечная меш будет отбрасывать тени.
[V] Receive Shadow - конечная меш будет принимать тени.
[V] Keep Layer - созданный объект сохранит тот же слой, что и у исходного объекта (на котором висит скрипт)

Ну и, замечательный бонус! :ymparty:
[V] Под правой кнопкой живёт команда Combine Now. Она позволяет провести всё комбинирование прямо в Редакторе, оценить изминения и, или отменить их (созданные меши нужно будет удалить руками) или сохранить. То есть - избежать необходимости комбайнить на старте приложения.

Изображение

Мне он очень сильно помог и помогает в оптимизации сцен. Надеюсь и вам пригодиться.
З.Ы. Для его работы нужен стандартный скрипт MeshCombineUtility.cs из Standart Assets

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 25 дек 2009, 19:12
Serge
Спасибо. (3A4OT)

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 25 дек 2009, 19:32
iqubik
Neo спасибо за проделанную работу!
Я думаю скрипт будет действительно ценен. По крайней мере для себя я уже вижу очевидные выгоды его применения.
Но вот всё таки у меня остался один важный вопрос.
Если я зохочу приатачить 2 объекта с разными матами, то видимо скрипт мне объяснит как я не прав.
Но чисто теоретически, можно ли сделать так, чтобы комбайнер при атаче разнородных материалов раздавал бы новообразовавшемуся объекту айдишники и присваивал мультимат?
И опять же, чисто теоретически - насколько трудоёмко дописать такой модуль?

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 25 дек 2009, 19:44
Neodrop
На каждый мат создаётся свой меш.
Мультиматы страшное зло для [unity 3D] Unity и для оптимизации программы. Вот для таких экспериментов я и добавил возможность комбайнить в Редакторе. Эксперементируйте.

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 27 дек 2009, 16:22
Neodrop
Ещё маленько расширил функционал, добавив возможность вызвать комбайн на всех чилдах, исключая объект, с которого команда вызвана.

Качаем тут :

http://forum.unity3d.com/viewtopic.php?p=247996#247996

[ftp]http://forum.unity3d.com/viewtopic.php?p=247996#247996[/ftp]

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 07 янв 2010, 21:27
iqubik
Спасибо Нео за компайнер!
И спасибо romeo_ftv за доработку комбайнера под юнити 2.6 (там всего одна строка, но без неё на 2.6 не работает).
Вот тот же комбайнер, но для 2.6.


Код: Выделить всё
using UnityEngine;
using System.Collections;


/*
Attach this script as a parent to some game objects. The script will then combine the meshes at startup.
This is useful as a performance optimization since it is faster to render one big mesh than many small meshes. See the docs on graphics performance optimization for more info.

Different materials will cause multiple meshes to be created, thus it is useful to share as many textures/material as you can.
*/
//[ExecuteInEditMode()]
[AddComponentMenu("Mesh/Combine Children")]
public class CombineChildren : MonoBehaviour {
   
   /// Usually rendering with triangle strips is faster.
   /// However when combining objects with very low triangle counts, it can be faster to use triangles.
   /// Best is to try out which value is faster in practice.
    public int frameToWait = 0;
   public bool generateTriangleStrips = true, combineOnStart = true, destroyAfterOptimized = false, castShadow = true, receiveShadow = true, keepLayer = true;
   
    void Start()
    {
        if (combineOnStart && frameToWait == 0) Combine();
        else StartCoroutine(CombineLate());
    }

    IEnumerator CombineLate()
    {
        for (int i = 0; i < frameToWait; i++ ) yield return 0;
        Combine();
    }

    [ContextMenu("Combine Now on Childs")]
    public void CallCombineOnAllChilds()
    {
        //CombineChildren[] c = gameObject.GetComponentsInChildren<CombineChildren>();
      CombineChildren[] c = (CombineChildren[])GetComponentsInChildren( typeof(CombineChildren) );
        int count = c.Length;
        for (int i = 0; i < count; i++) if(c[i] != this)c[i].Combine();
        combineOnStart = enabled = false;
    }

   /// This option has a far longer preprocessing time at startup but leads to better runtime performance.
    [ContextMenu ("Combine Now")]
   public void Combine () {
      Component[] filters  = GetComponentsInChildren(typeof(MeshFilter));
      Matrix4x4 myTransform = transform.worldToLocalMatrix;
      Hashtable materialToMesh= new Hashtable();
      
      for (int i=0;i<filters.Length;i++) {
         MeshFilter filter = (MeshFilter)filters[i];
         Renderer curRenderer  = filters[i].renderer;
         MeshCombineUtility.MeshInstance instance = new MeshCombineUtility.MeshInstance ();
         instance.mesh = filter.sharedMesh;
         if (curRenderer != null && curRenderer.enabled && instance.mesh != null) {
            instance.transform = myTransform * filter.transform.localToWorldMatrix;
            
            Material[] materials = curRenderer.sharedMaterials;
            for (int m=0;m<materials.Length;m++) {
               instance.subMeshIndex = System.Math.Min(m, instance.mesh.subMeshCount - 1);
   
               ArrayList objects = (ArrayList)materialToMesh[materials[m]];
               if (objects != null) {
                  objects.Add(instance);
               }
               else
               {
                  objects = new ArrayList ();
                  objects.Add(instance);
                  materialToMesh.Add(materials[m], objects);
               }
            }
                if (Application.isPlaying && destroyAfterOptimized && combineOnStart) Destroy(curRenderer.gameObject);
                else if (destroyAfterOptimized) DestroyImmediate(curRenderer.gameObject);
            else curRenderer.enabled = false;
         }
      }
   
      foreach (DictionaryEntry de  in materialToMesh) {
         ArrayList elements = (ArrayList)de.Value;
         MeshCombineUtility.MeshInstance[] instances = (MeshCombineUtility.MeshInstance[])elements.ToArray(typeof(MeshCombineUtility.MeshInstance));

         // We have a maximum of one material, so just attach the mesh to our own game object
         if (materialToMesh.Count == 1)
         {
            // Make sure we have a mesh filter & renderer
            if (GetComponent(typeof(MeshFilter)) == null)
               gameObject.AddComponent(typeof(MeshFilter));
            if (!GetComponent("MeshRenderer"))
               gameObject.AddComponent("MeshRenderer");
   
            MeshFilter filter = (MeshFilter)GetComponent(typeof(MeshFilter));
            filter.mesh = MeshCombineUtility.Combine(instances, generateTriangleStrips);
            renderer.material = (Material)de.Key;
            renderer.enabled = true;
         }
         // We have multiple materials to take care of, build one mesh / gameobject for each material
         // and parent it to this object
         else
         {
            GameObject go = new GameObject("Combined mesh");
                if (keepLayer) go.layer = gameObject.layer;
            go.transform.parent = transform;
            go.transform.localScale = Vector3.one;
            go.transform.localRotation = Quaternion.identity;
            go.transform.localPosition = Vector3.zero;
            go.AddComponent(typeof(MeshFilter));
            go.AddComponent("MeshRenderer");
            go.renderer.material = (Material)de.Key;
            MeshFilter filter = (MeshFilter)go.GetComponent(typeof(MeshFilter));
            if(Application.isPlaying)filter.mesh = MeshCombineUtility.Combine(instances, generateTriangleStrips);
                else filter.sharedMesh = MeshCombineUtility.Combine(instances, generateTriangleStrips);
                go.renderer.castShadows = castShadow;
                go.renderer.receiveShadows = receiveShadow;
         }
      }   
   }   
}

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 08 янв 2010, 11:32
Neodrop
Я работаю на 2.6.1 Как это у вас не работает? :-?

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 08 янв 2010, 18:17
iqubik
Сорри, для 2.5.
И кстати эта правка не помогла. Вместо пункта меня "Combine childrens now" вижу чтото вроде "АПпапапап@43"...
А это как выходит блок памяти откуда-то преобразованный в стринговое значение.

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 08 янв 2010, 20:45
Neodrop
Это в 2.5 что ли? НА него я не ориентировался. Может там нет чего-то, использованного в коде.

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 09 янв 2010, 02:01
iqubik
Да, синтаксис 2,5 не позволил.
Но в любом случае, Нео, спасибо тебе за то что ты реализовал функции attach-а(по требованию) + задержка комбайна + слои!!!!
Огромное человеческое СПАСИБО!
А вторичная функция на то и вторичная - маст дизаблед))

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 01 фев 2010, 18:08
Neodrop
Малость подправил - не работало в Редакторе, когда материал только один. Перезалито на офф. форум (смотрим ссылку чуть выше.)

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 22 авг 2010, 19:27
jytu
Пасиб, Неодроп )

эта штука сэкономила кучу времени :)

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 10 окт 2010, 18:27
strelok
При добавлении скрипта (CombineChildren), все объекты, находящиеся в группе исчезают во время запуска. Что за хрень? Как бороться?

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 10 окт 2010, 18:29
Neodrop
Не все модели комбайнятся нормально. Видимо модели у вас кривоваты. Обычно помогает ResetX Form в Максе перед экспортом в двиг. Конечно, если вы работаете в Максе.

Re: Combine Children Extented (расширенный)

СообщениеДобавлено: 10 окт 2010, 18:56
strelok
Век живи - век учись! Изначально объекты были в формате .obj, теперь в .fbx и всё нормуль. Спасибо!