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

Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 16:56
Sef
Это кусок из справки:
http://docs.unity3d.ru/Manual/Optimizin ... mance.html

А как это делать и где? Просто у меня уровень собирается из разных кубиков и будет много Draw Call.
Надо бы вот как на скрине с форума:
Изображение
http://forum.unity3d.com/viewtopic.php? ... es&start=0

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 17:07
eureka3D
в Максе (max_sm) выделяется один Editable Mesh и кнопкой attach - привязываются другие Мешы. По крайней мере я так делал, только с материалами не напутайте. Я присваивал Multi-Sub материал для всего окончательного меша и назначал по полигонам разные материалы.

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 17:17
Sef
В макс не то... планируется что уровни будут собираться в едиторе юнити.
Дали ссылку, пока пробую:
http://unity3d.com/support/documentatio ... eshes.html

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 21:54
Sef
Пока не получается, может ещё что-то посоветуете, или направите? ;)

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 22:06
Kann
Ссылку правильно дали, что не получается ?
вот почитайте эту тему.
viewtopic.php?f=65&t=703

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 22:26
Sef
Kann писал(а):Ссылку правильно дали, что не получается ?
вот почитайте эту тему.
viewtopic.php?f=65&t=703

Тот код глючит как на джаве, так и на шарп перевести ума не хватило :)
А по той ссылки увидел:
3. использовать скрипт из острова демки(что с проектом) combinechildrens.

Пошёл смотреть что там...

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 22:51
Sef
Получилось. А здоровенький такой скрипт(ы) :)
Кстати, а можно как-то в один DC сотню не статических 3Д объектов засунуть?

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 15 дек 2009, 23:26
Neodrop
Кстати, у меня тоже не вышло с первого подхода. Справка в этом месте хуже худшего.
Если есть рабочий скрипт, буду признателен. То, что по ссылкам - палево нерабочее. :-?

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 16 дек 2009, 00:13
Sef
Это из острова:

CombineChildren.cs
Код: Выделить всё
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.
*/

[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 bool generateTriangleStrips = true;
   
   /// This option has a far longer preprocessing time at startup but leads to better runtime performance.
   void Start () {
      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);
               }
            }
            
            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");
            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));
            filter.mesh = MeshCombineUtility.Combine(instances, generateTriangleStrips);
         }
      }   
   }   
}


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

public class MeshCombineUtility {
   
   public struct MeshInstance
   {
      public Mesh      mesh;
      public int       subMeshIndex;           
      public Matrix4x4 transform;
   }
   
   public static Mesh Combine (MeshInstance[] combines, bool generateStrips)
   {
      int vertexCount = 0;
      int triangleCount = 0;
      int stripCount = 0;
      foreach( MeshInstance combine in combines )
      {
         if (combine.mesh)
         {
            vertexCount += combine.mesh.vertexCount;
            
            if (generateStrips)
            {
               // SUBOPTIMAL FOR PERFORMANCE
               int curStripCount = combine.mesh.GetTriangleStrip(combine.subMeshIndex).Length;
               if (curStripCount != 0)
               {
                  if( stripCount != 0 )
                  {
                     if ((stripCount & 1) == 1 )
                        stripCount += 3;
                     else
                        stripCount += 2;
                  }
                  stripCount += curStripCount;
               }
               else
               {
                  generateStrips = false;
               }
            }
         }
      }
      
      // Precomputed how many triangles we need instead
      if (!generateStrips)
      {
         foreach( MeshInstance combine in combines )
         {
            if (combine.mesh)
            {
               triangleCount += combine.mesh.GetTriangles(combine.subMeshIndex).Length;
            }
         }
      }
      
      Vector3[] vertices = new Vector3[vertexCount] ;
      Vector3[] normals = new Vector3[vertexCount] ;
      Vector4[] tangents = new Vector4[vertexCount] ;
      Vector2[] uv = new Vector2[vertexCount];
      Vector2[] uv1 = new Vector2[vertexCount];
      int[] triangles = new int[triangleCount];
      int[] strip = new int[stripCount];
      
      int offset;
      
      offset=0;
      foreach( MeshInstance combine in combines )
      {
         if (combine.mesh)
            Copy(combine.mesh.vertexCount, combine.mesh.vertices, vertices, ref offset, combine.transform);
      }

      offset=0;
      foreach( MeshInstance combine in combines )
      {
         if (combine.mesh)
         {
            Matrix4x4 invTranspose = combine.transform;
            invTranspose = invTranspose.inverse.transpose;
            CopyNormal(combine.mesh.vertexCount, combine.mesh.normals, normals, ref offset, invTranspose);
         }
            
      }
      offset=0;
      foreach( MeshInstance combine in combines )
      {
         if (combine.mesh)
         {
            Matrix4x4 invTranspose = combine.transform;
            invTranspose = invTranspose.inverse.transpose;
            CopyTangents(combine.mesh.vertexCount, combine.mesh.tangents, tangents, ref offset, invTranspose);
         }
            
      }
      offset=0;
      foreach( MeshInstance combine in combines )
      {
         if (combine.mesh)
            Copy(combine.mesh.vertexCount, combine.mesh.uv, uv, ref offset);
      }
      
      offset=0;
      foreach( MeshInstance combine in combines )
      {
         if (combine.mesh)
            Copy(combine.mesh.vertexCount, combine.mesh.uv1, uv1, ref offset);
      }
      
      int triangleOffset=0;
      int stripOffset=0;
      int vertexOffset=0;
      foreach( MeshInstance combine in combines )
      {
         if (combine.mesh)
         {
            if (generateStrips)
            {
               int[] inputstrip = combine.mesh.GetTriangleStrip(combine.subMeshIndex);
               if (stripOffset != 0)
               {
                  if ((stripOffset & 1) == 1)
                  {
                     strip[stripOffset+0] = strip[stripOffset-1];
                     strip[stripOffset+1] = inputstrip[0] + vertexOffset;
                     strip[stripOffset+2] = inputstrip[0] + vertexOffset;
                     stripOffset+=3;
                  }
                  else
                  {
                     strip[stripOffset+0] = strip[stripOffset-1];
                     strip[stripOffset+1] = inputstrip[0] + vertexOffset;
                     stripOffset+=2;
                  }
               }
               
               for (int i=0;i<inputstrip.Length;i++)
               {
                  strip[i+stripOffset] = inputstrip[i] + vertexOffset;
               }
               stripOffset += inputstrip.Length;
            }
            else
            {
               int[]  inputtriangles = combine.mesh.GetTriangles(combine.subMeshIndex);
               for (int i=0;i<inputtriangles.Length;i++)
               {
                  triangles[i+triangleOffset] = inputtriangles[i] + vertexOffset;
               }
               triangleOffset += inputtriangles.Length;
            }
            
            vertexOffset += combine.mesh.vertexCount;
         }
      }
      
      Mesh mesh = new Mesh();
      mesh.name = "Combined Mesh";
      mesh.vertices = vertices;
      mesh.normals = normals;
      mesh.tangents = tangents;
      mesh.uv = uv;
      mesh.uv1 = uv1;
      if (generateStrips)
         mesh.SetTriangleStrip(strip, 0);
      else
         mesh.triangles = triangles;
      
      return mesh;
   }
   
   static void Copy (int vertexcount, Vector3[] src, Vector3[] dst, ref int offset, Matrix4x4 transform)
   {
      for (int i=0;i<src.Length;i++)
         dst[i+offset] = transform.MultiplyPoint(src[i]);
      offset += vertexcount;
   }

   static void CopyNormal (int vertexcount, Vector3[] src, Vector3[] dst, ref int offset, Matrix4x4 transform)
   {
      for (int i=0;i<src.Length;i++)
         dst[i+offset] = transform.MultiplyVector(src[i]).normalized;
      offset += vertexcount;
   }

   static void Copy (int vertexcount, Vector2[] src, Vector2[] dst, ref int offset)
   {
      for (int i=0;i<src.Length;i++)
         dst[i+offset] = src[i];
      offset += vertexcount;
   }

   static void CopyTangents (int vertexcount, Vector4[] src, Vector4[] dst, ref int offset, Matrix4x4 transform)
   {
      for (int i=0;i<src.Length;i++)
      {
         Vector4 p4 = src[i];
         Vector3 p = new Vector3(p4.x, p4.y, p4.z);
         p = transform.MultiplyVector(p);
         dst[i+offset] = new Vector4(p.x, p.y, p.z, p4.w);
      }
         
      offset += vertexcount;
   }
}


Тут лишнего много?

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 16 дек 2009, 01:19
Kann
мдя... не думал что в документации могет быть не рабочее.... 8()
вот накопал на форуме....
Код: Выделить всё
// This script should be put on an empty GameObject
// Objects to be combined should be children of the empty GameObject
@script RequireComponent(MeshFilter)
@script RequireComponent(MeshRenderer)

function Start () {
   for (var child in transform)
      child.position += transform.position;
   transform.position = Vector3.zero;
   transform.rotation = Quaternion.identity;
   
   var meshFilters = GetComponentsInChildren(MeshFilter);
   var combine : CombineInstance[] = new CombineInstance[meshFilters.Length-1];
   var index = 0;
   for (var i = 0; i < meshFilters.Length; i++)
   {
      if (meshFilters[i].sharedMesh == null) continue;
      combine[index].mesh = meshFilters[i].sharedMesh;
      combine[index++].transform = meshFilters[i].transform.localToWorldMatrix;
      meshFilters[i].renderer.enabled = false;
   }
   GetComponent(MeshFilter).mesh = new Mesh();
   GetComponent(MeshFilter).mesh.CombineMeshes (combine);
   renderer.material = meshFilters[0].renderer.sharedMaterial;
}

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 16 дек 2009, 01:32
Neodrop
Остров сильно устарел.
Вариант от Канна (не проверил) куда короче.
З. Ы. Старый вариант я сам использую успешно.

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 16 дек 2009, 14:49
Sef
Вариант от Канна не работает... если я его правильно применил...

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 16 дек 2009, 14:58
Kann
Он работает, но не так как скрипт из демки с островом, создайте пустой GameObject на него вешается скрипт, приатачте к GameObject несколько кубиков, и получите 1 DrawCalls. этот скрипт что я привел, как исправление багов в документации, но его нужно допиливать под себя.

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 16 дек 2009, 15:19
Neodrop
Родной скрипт из 2.1 работает точно так же. Так что это какие то яйца в профиль. :-?

Re: Если вы заботитесь о производительности, объединяйте меши

СообщениеДобавлено: 16 дек 2009, 15:30
Kann
ну я же не пишу что это новое решение ? я имел в виду что это то что народ выложил на офф форуме в замен на вопрос,(какого хрена не работает скрипт из документации ?) этот скрипт вполне себе может выполнять те функции которые требовались в первом посте и демонстрируются на скриншоте, все недостающее надо допиливать....