using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using System.Text;
using LunarCatsStudio.SuperCombiner;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace LunarCatsStudio.SuperCombiner
{
///
/// Main class of Super Combiner asset.
///
public class SuperCombiner : MonoBehaviour
{
public string versionNumber { get { return "1.6.6"; } }
public enum CombineStatesList
{
Uncombined,
Combining,
CombinedMaterials,
Combined
}
public CombineStatesList _combiningState = CombineStatesList.Uncombined;
public List _texturePackers = new List();
public LunarCatsStudio.SuperCombiner.MeshCombiner _meshCombiner = new LunarCatsStudio.SuperCombiner.MeshCombiner();
// Editable Parameters
// General settings
public string _sessionName = "combinedSession";
public bool _combineAtRuntime = false;
// Texture Atlas settings
public int _textureAtlasSize = 2048;
public List _customTextureProperies = new List();
public float _tilingFactor = 1f;
public int _atlasPadding = 0;
public bool _combineMaterials = true;
public bool _forceUVTo0_1 = false;
// Multiple materials
public bool _multipleMaterialsMode = false;
public bool _combineEachGroupAsSubmesh = false;
public List multiMaterials0 = new List();
public List multiMaterials1 = new List();
public List multiMaterials2 = new List();
public List multiMaterials3 = new List();
public List multiMaterials4 = new List();
public List multiMaterials5 = new List();
public List multiMaterials6 = new List();
public List multiMaterials7 = new List();
public List multiMaterials8 = new List();
public List multiMaterials9 = new List();
public List multiMaterials10 = new List();
public List multiMaterialsAllOthers = new List();
// Meshes settings
public bool _combineMeshes = false;
public bool _manageLodLevel = false;
public int _managedLodLevel = 0;
public bool _generateUv2 = true;
public int _meshOutput;
public bool _manageColliders = false;
public GameObject _targetGameObject;
///
/// The list of multi _material list defined by user
///
public List> _multiMaterialsList = new List>();
public int _multiMaterialsCount;
///
/// The list of _material list to combine
///
List> _materialsToCombine = new List>();
// Saving options
public bool _savePrefabs = true;
public bool _saveMeshObj = false;
public bool _saveMeshFbx = false;
public bool _saveMaterials = true;
public bool _saveTextures = true;
public string _folderDestination = "Assets/SuperCombiner/Combined";
// Internal combine process variables
///
/// List of all original MeshRenderer in children to combine
///
public List> _meshList = new List>();
///
/// List of all original SkinnedMeshRenderer in children to combine
///
public List> _skinnedMeshList = new List>();
///
/// List of copied meshes instancesId associated with their original sharedMesh and sharedMaterial instanceId.
/// This is usefull not to save duplicated mesh when exporting
/// Key=Mesh instanceID
/// Value=Concatenation of sharedMeshName + sharedMaterialName + GameObjectName
///
public Dictionary _uniqueCombinedMeshId = new Dictionary();
///
/// Links original shared meshes with the copy created
/// Key=original shared mesh instanceID
/// Value=The value of _uniqueCombinedMeshId[Key]
///
public Dictionary _copyMeshId = new Dictionary();
///
/// List of transformed game objects for prefab saving
///
public List _toSavePrefabList = new List();
///
/// List of transformed game objects for saving purpose
///
public List _toSaveObjectList = new List();
///
/// List of meshes to save
///
public List _toSaveMeshList = new List();
///
/// List of transformed skinned game objects for saving purpose
///
public List _toSaveSkinnedObjectList = new List();
//
// CombinedGameObjects[i] will use uvs[combinedTextureIndex[i]]
//
//public List combinedTextureIndex = new List();
///
/// The parent GameObject for every combined object
///
public GameObject _targetParentForCombinedGameObjects;
private DateTime _timeStart; // The date time when starting the process
///
/// The result of the combine process is stored in this class. It is instanciated the first time combine process is executed
///
public CombinedResult _combinedResult;
///
/// input setting of supper combiner
///
public SuperCombinerSettings _scSettings;
private SuperCombiner()
{
// Nothing to do here
}
void Start()
{
if (_combineAtRuntime)
{
CombineChildren();
}
}
///
/// Find and fill the list of enabled meshes to combine
///
public void FindMeshesToCombine()
{
_meshList = FindEnabledMeshes(transform);
_skinnedMeshList = FindEnabledSkinnedMeshes(transform);
}
///
/// Combine process
///
public void CombineChildren()
{
Logger.Instance.ClearLogs();
_timeStart = DateTime.Now;
_combiningState = CombineStatesList.Combining;
// Getting the list of meshes ...
FindMeshesToCombine();
Combine(_meshList, _skinnedMeshList);
}
///
/// Combine Materials and Create Atlas texture
///
///
///
/// True if process has been successfull
public bool CombineMaterials(List> meshesToCombine, List> skinnedMeshesToCombine)
{
#if UNITY_EDITOR
// UI Progress bar display in Editor
EditorUtility.DisplayProgressBar("Super Combiner", "Materials and textures listing...", 0.1f);
#endif
// Initialize multi _material parameters
InitializeMultipleMaterialElements();
// If _combinedResult has not been created yet, create it
if (_combinedResult == null)
{
_combinedResult = (CombinedResult)ScriptableObject.CreateInstance(typeof(CombinedResult));
}
// Getting list of materials
List enabledMaterials = FindEnabledMaterials(meshesToCombine, skinnedMeshesToCombine);
_combinedResult._materialCombinedCount = enabledMaterials.Count;
foreach (MaterialToCombine mat in enabledMaterials)
{
bool found = false;
for (int i = 0; i < _multiMaterialsList.Count; i++)
{
if (_multiMaterialsList[i].Contains(mat._material))
{
// This _material was listed in the multi _material list by user, we add it to it's right _index in '_materialsToCombine' list
_materialsToCombine[i].Add(mat);
found = true;
}
}
if (!found)
{
// This _material was not listed in the multi _material list, so we add it to the last element
_materialsToCombine[_materialsToCombine.Count - 1].Add(mat);
}
}
// List all texture from enabled materials to be combined
int progressCount = 0;
for (int i = 0; i < _materialsToCombine.Count; i++)
{
_combinedResult._originalMaterialList.Add(new Dictionary());
_combinedResult.AddNewCombinedMaterial();
if (i == _multiMaterialsList.Count && _materialsToCombine[i].Count > 0 || i < _multiMaterialsList.Count && _multiMaterialsList[i].Count > 0)
{
// Instanciate a new texture Packer
TexturePacker texturePacker = new TexturePacker
{
// Assign the _combinedResult reference to texturePacker
CombinedResult = _combinedResult,
CombinedIndex = i
};
// Setting up the custom shader property _names
texturePacker.SetCustomPropertyNames(_customTextureProperies);
// Add this texture packer to the list
_texturePackers.Add(texturePacker);
foreach (MaterialToCombine mat in _materialsToCombine[i])
{
_combinedResult.AddMaterialToCombine(mat, i);
#if UNITY_EDITOR
// Cancelable UI Progress bar display in Editor
bool cancel = false;
EditorUtility.DisplayProgressBar("Super Combiner", "Processing _material " + mat._material.name, progressCount / (float)enabledMaterials.Count);
if (cancel)
{
UnCombine();
return false;
}
#endif
/*Rect materialUVBoundToUse = mat.GetScaledAndOffsetedUVBounds();
if(_forceUVTo0_1)
{
materialUVBoundToUse = new Rect(0, 0, 1, 1);
}*/
// Add all textures from this material on the list of textures
texturePacker.SetTextures(mat._material, _combineMaterials, mat, _tilingFactor);
/*if (!mat.HasProperty ("_MainTex") || mat.mainTexture == null) {
// Correction of uv for mesh without diffuse texture
uvBound.size = Vector2.Scale (uvBound.size, new Vector2 (1.2f, 1.2f));
uvBound.position -= new Vector2 (0.1f, 0.1f);
}*/
progressCount++;
}
if (_materialsToCombine[i].Count == 0)
{
if (_multiMaterialsList[i].Count == 0)
{
Logger.Instance.AddLog("SuperCombiner", "Source materials group " + i + " is empty. Skipping this combine process", Logger.LogLevel.LOG_WARNING);
}
else
{
Logger.Instance.AddLog("SuperCombiner", "Cannot combined materials for group " + i + " because none of the _material were found in the list of game objects to combine", Logger.LogLevel.LOG_WARNING);
}
}
else if (_materialsToCombine[i].Count == 1)
{
if (_materialsToCombine.Count == 1)
{
Logger.Instance.AddLog("SuperCombiner", "Only one material found, skipping combine material process and keep this material (" + _materialsToCombine[i][0]._material.name + ") for the combined mesh.");
}
else
{
Logger.Instance.AddLog("SuperCombiner", "Only one material found for multi material group " + i + ", skipping combine material process and keep this material (" + _materialsToCombine[i][0]._material.name + ") for the combined mesh.");
}
_combinedResult.SetCombinedMaterial(_materialsToCombine[i][0]._material, i, true);
_combinedResult._combinedMaterials[i].uvs = new Rect[1];
_combinedResult._combinedMaterials[i].uvs[0] = new Rect(0, 0, 1, 1);
texturePacker.SetCopiedMaterial(_materialsToCombine[i][0]._material);
}
else
{
#if UNITY_EDITOR
// UI Progress bar display in Editor
EditorUtility.DisplayProgressBar("Super Combiner", "Packing textures...", 0f);
#endif
// Pack the textures
texturePacker.PackTextures(_textureAtlasSize, _atlasPadding, _combineMaterials, _sessionName);
}
}
else
{
// There are no materials to combine in this _combinedIndex
_texturePackers.Add(null);
}
}
_combiningState = CombineStatesList.CombinedMaterials;
#if UNITY_EDITOR
EditorUtility.ClearProgressBar();
#endif
return false;
}
public void SetTargetParentForCombinedGameObject()
{
if (_targetGameObject == null)
{
// Create the parent Game object
_targetParentForCombinedGameObjects = new GameObject(_sessionName);
_targetParentForCombinedGameObjects.transform.parent = this.transform;
_targetParentForCombinedGameObjects.transform.localPosition = Vector3.zero;
}
else
{
_targetParentForCombinedGameObjects = _targetGameObject;
}
}
///
/// Combines the meshes
///
/// Meshes to combine.
/// Skinned meshes to combine.
public void CombineMeshes(List> meshesToCombine, List> skinnedMeshesToCombine, Transform parent)
{
// Assign the _combinedResult reference to texturePacker and MeshCombiner
_meshCombiner.CombinedResult = _combinedResult;
_combinedResult._meshesCombinedCount = meshesToCombine.Count;
_combinedResult._skinnedMeshesCombinedCount = skinnedMeshesToCombine.Count;
// Check if there is at least 2 meshes in the current combine session
if (_combineMeshes)
{
// Careful here we do not take into account renderers that will not be combined from the list
if (meshesToCombine.Count + skinnedMeshesToCombine.Count < 1)
{
if (meshesToCombine.Count == 0)
{
#if UNITY_EDITOR
EditorUtility.DisplayDialog("Super Combiner", "Zero meshes found.\nUnable to proceed without at least 1 mesh.", "Ok");
#endif
UnCombine();
}
return;
}
}
// Parametrize MeshCombiner
_meshCombiner.SetParameters(_sessionName, _generateUv2);
#if UNITY_EDITOR
// UI Progress bar display in Editor
EditorUtility.DisplayProgressBar("Super Combiner", "Combining meshes", 0.5f);
#endif
// Combine process
if (_combineMeshes)
{
// Get the ordered by _combinedIndex list of meshes to combine
List meshIndexedList = GetMeshRenderersByCombineIndex(meshesToCombine, skinnedMeshesToCombine, _targetParentForCombinedGameObjects.transform);
for (int i = 0; i < _combinedResult.GetCombinedIndexCount(); i++)
{
_combinedResult._combinedGameObjectFromMeshList.Add(new List());
_combinedResult._combinedGameObjectFromSkinnedMeshList.Add(new List());
if (_combinedResult._originalMaterialList[i].Count > 0)
{
if ((LunarCatsStudio.SuperCombiner.MeshOutput)_meshOutput == LunarCatsStudio.SuperCombiner.MeshOutput.Mesh)
{
// Combine the meshes together
_combinedResult._combinedGameObjectFromMeshList[i] = _meshCombiner.CombineToMeshes(meshIndexedList[i]._meshRenderers, meshIndexedList[i]._skinnedMeshRenderers, parent, i);
// Add the copy mesh instanceId with its original sharedMesh and sharedMaterial instanceId
if (!_combineEachGroupAsSubmesh)
{
foreach (GameObject go in _combinedResult._combinedGameObjectFromMeshList[i])
{
_uniqueCombinedMeshId.Add(go.GetComponent().sharedMesh.GetInstanceID(), go.name);
}
}
}
else
{
_combinedResult._combinedGameObjectFromSkinnedMeshList[i] = _meshCombiner.CombineToSkinnedMeshes(meshIndexedList[i]._meshRenderers, meshIndexedList[i]._skinnedMeshRenderers, parent, i);
if (!_combineEachGroupAsSubmesh)
{
// Add the copy mesh instanceId with its original sharedMesh and sharedMaterial instanceId
foreach (GameObject go in _combinedResult._combinedGameObjectFromSkinnedMeshList[i])
{
_uniqueCombinedMeshId.Add(go.GetComponent().sharedMesh.GetInstanceID(), go.name);
}
}
}
if (_combinedResult._combinedGameObjectFromMeshList.Count + _combinedResult._combinedGameObjectFromSkinnedMeshList.Count == 0)
{
Logger.Instance.AddLog("SuperCombiner", "No mesh could be combined", Logger.LogLevel.LOG_ERROR);
// Error, Nothing could be combined
//UnCombine();
//return;
}
}
// Remove all temporary splitted GameObjects created
for (int j = 0; j < meshIndexedList[i]._splittedGameObject.Count; j++)
{
DestroyImmediate(meshIndexedList[i]._splittedGameObject[j]);
}
}
// Combine each material group to a submesh to a unique combined mesh
if (_multipleMaterialsMode && _combineEachGroupAsSubmesh)
{
List meshes = new List();
for (int i = 0; i < _combinedResult._combinedGameObjectFromMeshList.Count; i++)
{
if (_combinedResult._combinedGameObjectFromMeshList[i].Count > 0)
{
if ((LunarCatsStudio.SuperCombiner.MeshOutput)_meshOutput == LunarCatsStudio.SuperCombiner.MeshOutput.Mesh)
{
MeshFilter mf = _combinedResult._combinedGameObjectFromMeshList[i][0].GetComponent();
meshes.Add(mf.sharedMesh);
// Destroy the combined GameObject as we do not need it anymore
DestroyImmediate(_combinedResult._combinedGameObjectFromMeshList[i][0]);
}
else
{
SkinnedMeshRenderer mf = _combinedResult._combinedGameObjectFromSkinnedMeshList[i][0].GetComponent();
meshes.Add(mf.sharedMesh);
// Destroy the combined GameObject as we do not need it anymore
DestroyImmediate(_combinedResult._combinedGameObjectFromSkinnedMeshList[i][0]);
}
}
}
// Get the combined mesh with submeshes
GameObject go = _meshCombiner.CombineMeshToSubmeshes(meshes, (LunarCatsStudio.SuperCombiner.MeshOutput)_meshOutput);
go.transform.SetParent(parent);
go.transform.localPosition = Vector3.zero;
// Add the copy mesh instanceId with its original sharedMesh and sharedMaterial instanceId
if ((LunarCatsStudio.SuperCombiner.MeshOutput)_meshOutput == LunarCatsStudio.SuperCombiner.MeshOutput.Mesh)
{
_combinedResult._combinedGameObjectFromMeshList[0][0] = go;
_uniqueCombinedMeshId.Add(go.GetComponent().sharedMesh.GetInstanceID(), go.name);
}
else
{
_combinedResult._combinedGameObjectFromSkinnedMeshList[0][0] = go;
_uniqueCombinedMeshId.Add(go.GetComponent().sharedMesh.GetInstanceID(), go.name);
}
}
// Manage Colliders if needed
if (_manageColliders)
{
// Create new parent GameObject for all colliders
GameObject collidersParent = new GameObject("colliders");
collidersParent.transform.parent = parent;
Collider[] colliders = transform.GetComponentsInChildren();
foreach (Collider collider in colliders)
{
if (collider != null && collider.enabled)
{
CollidersHandler.CreateNewCollider(collidersParent.transform, collider);
}
}
}
}
else
{
// Create a copy of all game objects children of this one
CopyGameObjectsHierarchy(parent);
List> copyMeshList = FindEnabledMeshes(parent);
List> copySkinnedMeshList = FindEnabledSkinnedMeshes(parent);
// Get the ordered by _combinedIndex list of meshes to combine
List copyMeshIndexedList = GetMeshRenderersByCombineIndex(copyMeshList, copySkinnedMeshList, null);
for (int i = 0; i < _combinedResult.GetCombinedIndexCount(); i++)
{
_combinedResult._combinedGameObjectFromMeshList.Add(new List());
_combinedResult._combinedGameObjectFromSkinnedMeshList.Add(new List());
// Generate the new GameObjects and assign combined materials to renderers
if (copyMeshIndexedList[i]._meshRenderers.Count > 0)
{
_combinedResult._combinedGameObjectFromMeshList[i].AddRange(GenerateTransformedGameObjects(parent, copyMeshIndexedList[i]._meshRenderers));
}
if (copyMeshIndexedList[i]._skinnedMeshRenderers.Count > 0)
{
_combinedResult._combinedGameObjectFromSkinnedMeshList[i].AddRange(GenerateTransformedGameObjects(parent, copyMeshIndexedList[i]._skinnedMeshRenderers));
}
// Generate new UVs only if there are more than 1 _material combined
if (_combinedResult._originalMaterialList[i].Count > 1)
{
for (int j = 0; j < copyMeshIndexedList[i]._meshRenderers.Count; j++)
{
GenerateUVs(copyMeshIndexedList[i]._meshRenderers[j].GetComponent().sharedMesh, copyMeshIndexedList[i]._originalMaterials[j], copyMeshIndexedList[i]._meshRenderers[j].name, i);
}
for (int j = 0; j < copyMeshIndexedList[i]._skinnedMeshRenderers.Count; j++)
{
GenerateUVs(copyMeshIndexedList[i]._skinnedMeshRenderers[j].sharedMesh, copyMeshIndexedList[i]._originalskinnedMeshMaterials[j], copyMeshIndexedList[i]._skinnedMeshRenderers[j].name, i);
}
}
}
}
_combiningState = CombineStatesList.Combined;
// Deactivate original renderers
DisableRenderers(_meshList, _skinnedMeshList);
#if UNITY_EDITOR
EditorUtility.ClearProgressBar();
#endif
}
///
/// Return the list of MeshRendererAndOriginalMaterials for a given list of MeshRenderer and SkinnedMeshRenderer to combine.
/// The returned list also contains the list of splitted submeshes if this was necessary
///
///
///
///
///
private List GetMeshRenderersByCombineIndex(List> meshRenderers, List> skinnedMeshRenderers, Transform parent)
{
// The list to be returned
List meshRenderersByCombineIndex = new List();
// A temporary list of list of submeshes indexes to be splitted
List> submeshToCombinedIndex = new List>();
if (_combinedResult._originalMaterialList.Count == 0)
{
Logger.Instance.AddLog("SuperCombiner", "List of materials to combine has been lost. Try to uncombine and combine again.", Logger.LogLevel.LOG_ERROR);
return meshRenderersByCombineIndex;
}
// Initialize lists
for (int i = 0; i < _combinedResult._originalMaterialList.Count; i++)
{
meshRenderersByCombineIndex.Add(new MeshRendererAndOriginalMaterials());
submeshToCombinedIndex.Add(new List());
}
foreach (RendererObject meshRenderer in meshRenderers)
{
if (meshRenderer.WillBeCombined)
{
Material[] materials = meshRenderer.Renderer.sharedMaterials;
// We assume here the number of sharedMaterials is equal to the number of submeshes
_combinedResult._subMeshCount += materials.Length - 1;
// List all _combinedIndex for each _material in this meshRenderer
for (int i = 0; i < materials.Length; i++)
{
if (materials[i] != null)
{
int index = _combinedResult.GetCombinedIndex(materials[i]);
submeshToCombinedIndex[index].Add(i);
}
else
{
Logger.Instance.AddLog("SuperCombiner", "MeshRenderer of '" + meshRenderer.Renderer.name + "' has some missing _material references.", Logger.LogLevel.LOG_WARNING);
}
}
// If needed, split the submeshes
bool hasSplitSubmeshes = false;
for (int i = 0; i < _combinedResult._originalMaterialList.Count; i++)
{
if (submeshToCombinedIndex[i].Count > 0)
{
if (submeshToCombinedIndex[i].Count < materials.Length)
{
// Some materials in this meshRenderer correspond to different combined _index, split submesh accordingly
MeshRenderer newMesh = SubmeshSplitter.SplitSubmeshes(meshRenderer.Renderer.GetComponent(), submeshToCombinedIndex[i].ToArray(), i);
meshRenderersByCombineIndex[i]._meshRenderers.Add(newMesh);
meshRenderersByCombineIndex[i]._originalMaterials.Add(newMesh.sharedMaterials);
meshRenderersByCombineIndex[i]._splittedGameObject.Add(newMesh.gameObject);
Logger.Instance.AddLog("SuperCombiner", "Splitting submeshes for " + meshRenderer, Logger.LogLevel.LOG_DEBUG, false);
hasSplitSubmeshes = true;
}
else
{
// All materials in this meshRenderer correspond to the same combined _index, no need to split submesh
meshRenderersByCombineIndex[i]._meshRenderers.Add(meshRenderer.Renderer);
meshRenderersByCombineIndex[i]._originalMaterials.Add(meshRenderer.Renderer.sharedMaterials);
}
}
}
// If mesh has been splitted we don't combine mesh, destroy the old meshRenderer and MeshFilter component because there are copies that won't be used anymore
if (hasSplitSubmeshes && parent == null)
{
DestroyImmediate(meshRenderer.Renderer.GetComponent());
DestroyImmediate(meshRenderer.Renderer);
}
// Clear the combined _index list
for (int i = 0; i < _combinedResult._originalMaterialList.Count; i++)
{
submeshToCombinedIndex[i].Clear();
}
}
}
foreach (RendererObject skinnedMeshRenderer in skinnedMeshRenderers)
{
if (skinnedMeshRenderer.WillBeCombined)
{
Material[] materials = skinnedMeshRenderer.Renderer.sharedMaterials;
_combinedResult._subMeshCount += materials.Length - 1;
// List all _combinedIndex for each _material in this meshRenderer
for (int i = 0; i < materials.Length; i++)
{
if (materials[i] != null)
{
int index = _combinedResult.GetCombinedIndex(materials[i]);
submeshToCombinedIndex[index].Add(i);
}
else
{
Logger.Instance.AddLog("SuperCombiner", "SkinnedMeshRenderer of '" + skinnedMeshRenderer.Renderer.name + "' has some missing _material references.", Logger.LogLevel.LOG_WARNING);
}
}
// If needed, split the submeshes
bool hasSplitSubmeshes = false;
for (int i = 0; i < _combinedResult._originalMaterialList.Count; i++)
{
if (submeshToCombinedIndex[i].Count > 0)
{
if (submeshToCombinedIndex[i].Count < materials.Length)
{
// Some materials in this meshRenderer correspond to different combined _index, split submesh accordingly
SkinnedMeshRenderer newMesh = SubmeshSplitter.SplitSubmeshes(skinnedMeshRenderer.Renderer, submeshToCombinedIndex[i].ToArray(), i);
meshRenderersByCombineIndex[i]._skinnedMeshRenderers.Add(newMesh);
meshRenderersByCombineIndex[i]._originalskinnedMeshMaterials.Add(newMesh.sharedMaterials);
meshRenderersByCombineIndex[i]._splittedGameObject.Add(newMesh.gameObject);
Logger.Instance.AddLog("SuperCombiner", "Splitting submeshes for " + skinnedMeshRenderer, Logger.LogLevel.LOG_DEBUG, false);
hasSplitSubmeshes = true;
}
else
{
// All materials in this meshRenderer correspond to the same combined _index, no need to split submesh
meshRenderersByCombineIndex[i]._skinnedMeshRenderers.Add(skinnedMeshRenderer.Renderer);
meshRenderersByCombineIndex[i]._originalskinnedMeshMaterials.Add(skinnedMeshRenderer.Renderer.sharedMaterials);
}
}
}
// If mesh has been splitted we don't combine mesh, destroy the old meshRenderer and MeshFilter component because there are copies that won't be used anymore
if (hasSplitSubmeshes && parent == null)
{
DestroyImmediate(skinnedMeshRenderer.Renderer.GetComponent());
DestroyImmediate(skinnedMeshRenderer.Renderer);
}
// Clear the combined _index list
for (int i = 0; i < _combinedResult._originalMaterialList.Count; i++)
{
submeshToCombinedIndex[i].Clear();
}
}
}
return meshRenderersByCombineIndex;
}
public void Combine(List meshesToCombine, List skinnedMeshesToCombine)
{
List> rendererObjectsToCombine = new List>();
List> skinnedRendererObjectsToCombine = new List>();
foreach (MeshRenderer mr in meshesToCombine)
{
rendererObjectsToCombine.Add(new RendererObject(mr));
}
foreach (SkinnedMeshRenderer mr in skinnedMeshesToCombine)
{
skinnedRendererObjectsToCombine.Add(new RendererObject(mr));
}
Combine(rendererObjectsToCombine, skinnedRendererObjectsToCombine);
}
///
/// Combine the specified MeshRenderers and SkinnedMeshRenderers
///
/// Meshes to combine.
/// Skinned meshes to combine.
public void Combine(List> meshesToCombine, List> skinnedMeshesToCombine)
{
// Start timer if necessary
if (_combiningState == CombineStatesList.Uncombined)
{
_timeStart = DateTime.Now;
_combiningState = CombineStatesList.Combining;
}
Logger.Instance.AddLog("SuperCombiner", "Start processing...");
#if UNITY_EDITOR
// UI Progress bar display in Editor
EditorUtility.DisplayProgressBar("Super Combiner", "Meshes listing...", 0.1f);
#endif
// Combine Materials
bool cancel = CombineMaterials(meshesToCombine, skinnedMeshesToCombine);
if (cancel)
{
#if UNITY_EDITOR
EditorUtility.ClearProgressBar();
#endif
return;
}
// Initialte target parent gameObject
SetTargetParentForCombinedGameObject();
// Combine Meshes
CombineMeshes(meshesToCombine, skinnedMeshesToCombine, _targetParentForCombinedGameObjects.transform);
#if UNITY_EDITOR
// Combine process is finished
EditorUtility.ClearProgressBar();
#endif
// Process is finished
_combiningState = CombineStatesList.Combined;
_combinedResult._duration = DateTime.Now - _timeStart;
Logger.Instance.AddLog("SuperCombiner", "Successfully combined game objects!\nExecution time is " + _combinedResult._duration);
}
///
/// Initialize multiple _material elements
///
public void InitializeMultipleMaterialElements()
{
if (_multipleMaterialsMode)
{
_multiMaterialsList.Add(multiMaterials0);
_multiMaterialsList.Add(multiMaterials1);
_multiMaterialsList.Add(multiMaterials2);
_multiMaterialsList.Add(multiMaterials3);
_multiMaterialsList.Add(multiMaterials4);
_multiMaterialsList.Add(multiMaterials5);
_multiMaterialsList.Add(multiMaterials6);
_multiMaterialsList.Add(multiMaterials7);
_multiMaterialsList.Add(multiMaterials8);
_multiMaterialsList.Add(multiMaterials9);
_multiMaterialsList.Add(multiMaterials10);
}
// Fill the materials to combine list
for (int i = 0; i < _multiMaterialsList.Count + 1; i++)
{
// The last one in this list correspond to all other materials
_materialsToCombine.Add(new List());
}
}
///
/// Copy all GameObjects children
///
///
private void CopyGameObjectsHierarchy(Transform parent)
{
Transform[] children = this.transform.GetComponentsInChildren();
foreach (Transform child in children)
{
if (child.parent == this.transform && child != parent)
{
GameObject go = InstantiateCopy(child.gameObject, false);
go.transform.SetParent(parent);
}
}
}
///
/// Generate the new uvs of the mesh in texture atlas
///
///
///
///
///
private void GenerateUVs(Mesh mesh, Material[] originalMaterials, string objectName, int combinedIndex)
{
int[] textureIndexes = new int[originalMaterials.Length];
for (int j = 0; j < originalMaterials.Length; j++)
{
Material mat = originalMaterials[j];
textureIndexes[j] = _combinedResult.FindCorrespondingMaterialIndex(mat, combinedIndex);
}
if (!_meshCombiner.GenerateUV(mesh, textureIndexes, _combinedResult._combinedMaterials[combinedIndex].scaleFactors.ToArray(), objectName, combinedIndex))
{
UnCombine();
return;
}
}
///
/// Reactivate original GameObjects
///
///
///
private void EnableRenderers(List> meshes, List> skinnedMeshes)
{
foreach (RendererObject go in meshes)
{
if (go != null)
{
go.Renderer.gameObject.SetActive(true);
}
}
foreach (RendererObject go in skinnedMeshes)
{
if (go != null)
{
go.Renderer.gameObject.SetActive(true);
}
}
}
///
/// Deactivate original GameObjects
///
///
///
private void DisableRenderers(List> meshes, List> skinnedMeshes)
{
foreach (RendererObject go in meshes)
{
if (go != null && go.Renderer.gameObject != _targetGameObject)
{
go.Renderer.gameObject.SetActive(false);
}
}
foreach (RendererObject go in skinnedMeshes)
{
if (go != null && go.Renderer.gameObject != _targetGameObject)
{
go.Renderer.gameObject.SetActive(false);
}
}
}
///
/// Generate the new transformed gameobjects and apply new materials to them, when no combining meshes
///
///
///
///
private List GenerateTransformedGameObjects(Transform parent, List originalMeshRenderer)
{
List copyList = new List();
for (int i = 0; i < originalMeshRenderer.Count; i++)
{
// Copy the new mesh to the created GameObject copy
Mesh copyOfMesh = _meshCombiner.copyMesh(originalMeshRenderer[i].GetComponent().sharedMesh);
// Add the copy mesh instanceId with its original sharedMesh and sharedMaterial instanceId
if (originalMeshRenderer[i].GetComponent().sharedMaterial != null)
{
_uniqueCombinedMeshId.Add(copyOfMesh.GetInstanceID(), originalMeshRenderer[i].GetComponent().sharedMesh.GetInstanceID().ToString() + originalMeshRenderer[i].GetComponent().sharedMaterial.GetInstanceID().ToString() + copyOfMesh.name);
}
else
{
_uniqueCombinedMeshId.Add(copyOfMesh.GetInstanceID(), originalMeshRenderer[i].GetComponent().sharedMesh.GetInstanceID().ToString() + copyOfMesh.name);
}
_copyMeshId[originalMeshRenderer[i].GetComponent().sharedMesh.GetInstanceID()] = _uniqueCombinedMeshId[copyOfMesh.GetInstanceID()];
originalMeshRenderer[i].GetComponent().sharedMesh = copyOfMesh;
#if UNITY_EDITOR
// Unwrap UV2 for lightmap
Unwrapping.GenerateSecondaryUVSet(originalMeshRenderer[i].GetComponent().sharedMesh);
#endif
// Assign new materials
if (_combineMaterials)
{
Material[] originalMaterials = originalMeshRenderer[i].GetComponent().sharedMaterials;
Material[] newMats = new Material[originalMaterials.Length];
for (int k = 0; k < newMats.Length; k++)
{
newMats[k] = _combinedResult.GetCombinedMaterial(originalMaterials[k]);
}
originalMeshRenderer[i].GetComponent().sharedMaterials = newMats;
}
else
{
// If materials are not combined
/*Material[] mat = objects [i].GetComponent ().sharedMaterials;
Material[] newMats = new Material[mat.Length];
for (int a = 0; a < mat.Length; a++) {
newMats [a] = _texturePackers[0].getTransformedMaterialValue (objects [i].GetComponent ().sharedMaterials [a].name);
// Find corresponding _material
combinedTextureIndex.Add (_combinedResult.FindCorrespondingMaterialIndex(mat[a], 0));
}
objects[i].GetComponent ().sharedMaterials = newMats;*/
}
copyList.Add(originalMeshRenderer[i].gameObject);
}
return copyList;
}
///
/// Generate the new transformed gameobjects and apply new materials to them, when no combining meshes
/// For Skinned Mesh renderers, when no combining meshes
///
///
///
///
private List GenerateTransformedGameObjects(Transform parent, List originalSkinnedMeshRenderer)
{
List copyList = new List();
for (int i = 0; i < originalSkinnedMeshRenderer.Count; i++)
{
// Copy the new mesh to the created GameObject copy
Mesh copyOfMesh = _meshCombiner.copyMesh(originalSkinnedMeshRenderer[i].GetComponent().sharedMesh);
// Add the copy mesh instanceId with its original sharedMesh and sharedMaterial instanceId
if (originalSkinnedMeshRenderer[i].GetComponent().sharedMaterial != null)
{
_uniqueCombinedMeshId.Add(copyOfMesh.GetInstanceID(), originalSkinnedMeshRenderer[i].GetComponent().sharedMesh.GetInstanceID().ToString() + originalSkinnedMeshRenderer[i].GetComponent().sharedMaterial.GetInstanceID().ToString() + copyOfMesh.name);
}
else
{
_uniqueCombinedMeshId.Add(copyOfMesh.GetInstanceID(), originalSkinnedMeshRenderer[i].GetComponent().sharedMesh.GetInstanceID().ToString() + copyOfMesh.name);
}
_copyMeshId[originalSkinnedMeshRenderer[i].GetComponent().sharedMesh.GetInstanceID()] = _uniqueCombinedMeshId[copyOfMesh.GetInstanceID()];
originalSkinnedMeshRenderer[i].GetComponent().sharedMesh = copyOfMesh;
#if UNITY_EDITOR
// Unwrap UV2 for lightmap
//Unwrapping.GenerateSecondaryUVSet(skinnedObjects[i].GetComponent().sharedMesh);
#endif
// Assign new materials
if (_combineMaterials)
{
Material[] originalMaterials = originalSkinnedMeshRenderer[i].GetComponent().sharedMaterials;
Material[] newMats = new Material[originalMaterials.Length];
for (int k = 0; k < newMats.Length; k++)
{
newMats[k] = _combinedResult.GetCombinedMaterial(originalMaterials[k]);
}
originalSkinnedMeshRenderer[i].GetComponent().sharedMaterials = newMats;
}
else
{
// If materials are not combined
/*Material[] mat = skinnedObjects [i].sharedMaterials;
Material[] newMats = new Material[mat.Length];
for (int a = 0; a < mat.Length; a++) {
newMats [a] = _texturePackers[0].getTransformedMaterialValue (skinnedObjects [i].sharedMaterials [a].name);
// Find corresponding _material
combinedTextureIndex.Add (_combinedResult.FindCorrespondingMaterialIndex(mat[a], 0));
}
skinnedObjects[i].GetComponent ().sharedMaterials = newMats;*/
}
copyList.Add(originalSkinnedMeshRenderer[i].gameObject);
}
return copyList;
}
// Instantiate a copy of the GameObject, keeping it's transform values identical
private GameObject InstantiateCopy(GameObject original, bool deleteChidren = true)
{
GameObject copy = Instantiate(original) as GameObject;
copy.transform.parent = original.transform.parent;
copy.transform.localPosition = original.transform.localPosition;
copy.transform.localRotation = original.transform.localRotation;
copy.transform.localScale = original.transform.localScale;
copy.name = original.name;
if (deleteChidren)
{
// Delete all children
foreach (Transform child in copy.transform)
{
DestroyImmediate(child.gameObject);
}
}
return copy;
}
// Find all enabled mesh colliders
private List FindEnabledMeshColliders(Transform parent)
{
MeshCollider[] colliders;
colliders = parent.GetComponentsInChildren();
List meshColliders = new List();
foreach (MeshCollider collider in colliders)
{
if (collider.sharedMesh != null)
{
meshColliders.Add(collider);
}
}
return meshColliders;
}
// Find and store all enabled meshes
private List> FindEnabledMeshes(Transform parent)
{
MeshFilter[] filters;
LODGroup[] lodGroups;
Dictionary> meshToRendererObject = new Dictionary>();
filters = parent.GetComponentsInChildren();
List> meshRendererList = new List>();
// Get all valid meshFilter
foreach (MeshFilter filter in filters)
{
if (filter.sharedMesh != null)
{
MeshRenderer renderer = filter.GetComponent();
if (renderer != null && renderer.enabled && renderer.sharedMaterials.Length > 0)
{
RendererObject rendererObject = new RendererObject(renderer);
meshToRendererObject.Add(renderer, rendererObject);
meshRendererList.Add(rendererObject);
}
}
}
// Remove all non-desired Lods level
if (_manageLodLevel)
{
lodGroups = parent.GetComponentsInChildren();
foreach (LODGroup lodGroup in lodGroups)
{
LOD[] lods = lodGroup.GetLODs();
for (int i = 0; i < lods.Length; i++)
{
if (i != _managedLodLevel)
{
Renderer[] renderers = lods[i].renderers;
foreach (Renderer rd in renderers)
{
MeshRenderer meshrd = rd.GetComponent();
if (meshrd != null)
{
meshToRendererObject[meshrd].WillBeCombined = false;
}
}
}
}
if (_managedLodLevel > lods.Length)
{
Logger.Instance.AddLog("SuperCombiner", "Selected lod level " + _managedLodLevel + " is higher than LODs available in " + lodGroup.name, Logger.LogLevel.LOG_WARNING);
}
}
}
return meshRendererList;
}
// Find and store all enabled skin meshes
private List> FindEnabledSkinnedMeshes(Transform parent)
{
// Skinned meshes
SkinnedMeshRenderer[] skinnedMeshes = parent.GetComponentsInChildren();
List> skinnedMeshRendererList = new List>();
foreach (SkinnedMeshRenderer skin in skinnedMeshes)
{
if (skin.sharedMesh != null)
{
if (skin.enabled && skin.sharedMaterials.Length > 0)
{
RendererObject rendererObject = new RendererObject(skin);
skinnedMeshRendererList.Add(rendererObject);
}
}
}
return skinnedMeshRendererList;
}
///
/// Find and return all enabled materials in given meshes and skinnedMeshes
///
///
///
///
private List FindEnabledMaterials(List> meshes, List> skinnedMeshes)
{
// List of materials linked with their instanceID
Dictionary matList = new Dictionary();
// Meshes renderer
foreach (RendererObject mesh in meshes)
{
Mesh sharedMesh = mesh.Renderer.GetComponent().sharedMesh;
Rect uvBound = getUVBounds(sharedMesh.uv);
foreach (Material material in mesh.Renderer.sharedMaterials)
{
if (material != null)
{
int instanceId = material.GetInstanceID();
if (!matList.ContainsKey(instanceId))
{
// Material has not been listed yet, add it to the list
MaterialToCombine matToCombine = new MaterialToCombine();
matToCombine._material = material;
matToCombine._uvBounds = uvBound;
matToCombine._meshHavingBiggestUVBounds = sharedMesh;
matList.Add(instanceId, matToCombine);
}
else
{
// This _material has already been found, check if the uv bounds is bigger
Rect maxRect = getMaxRect(matList[instanceId]._uvBounds, uvBound);
MaterialToCombine matToCombine = matList[instanceId];
matToCombine._uvBounds = maxRect;
matToCombine._meshHavingBiggestUVBounds = sharedMesh;
matList[instanceId] = matToCombine;
}
}
else
{
// The _material is null
}
}
}
// SkinnedMeshes renderer
foreach (RendererObject skinnedMesh in skinnedMeshes)
{
Rect uvBound = getUVBounds(skinnedMesh.Renderer.sharedMesh.uv);
foreach (Material material in skinnedMesh.Renderer.sharedMaterials)
{
if (material != null)
{
int instanceId = material.GetInstanceID();
if (!matList.ContainsKey(instanceId))
{
// Material has not been listed yet, add it to the list
MaterialToCombine matToCombine = new MaterialToCombine();
matToCombine._material = material;
matToCombine._uvBounds = uvBound;
matList.Add(instanceId, matToCombine);
}
else
{
// This _material has already been found, check if the uv bounds is bigger
Rect maxRect = getMaxRect(matList[instanceId]._uvBounds, uvBound);
MaterialToCombine matToCombine = matList[instanceId];
matToCombine._uvBounds = maxRect;
matList[instanceId] = matToCombine;
}
}
else
{
// The _material is null
}
}
}
return new List(matList.Values);
}
// Return the bound of the uv list (min, max for x and y axis)
private Rect getUVBounds(Vector2[] uvs)
{
if (uvs.Length > 0)
{
float[] x = new float[uvs.Length];
float[] y = new float[uvs.Length];
for (int i = 0; i < uvs.Length; i++)
{
x[i] = uvs[i].x;
y[i] = uvs[i].y;
}
return new Rect(x.Min(), y.Min(), x.Max() - x.Min(), y.Max() - y.Min());
}
else
{
return new Rect(0, 0, 1, 1);
}
}
// Return the maximum rect based on the two rect parameters
private Rect getMaxRect(Rect uv1, Rect uv2)
{
Rect newRect = new Rect();
newRect.xMin = Math.Min(uv1.xMin, uv2.xMin);
newRect.yMin = Math.Min(uv1.yMin, uv2.yMin);
newRect.xMax = Math.Max(uv1.xMax, uv2.xMax);
newRect.yMax = Math.Max(uv1.yMax, uv2.yMax);
return newRect;
}
///
/// Reverse combine process, destroy all created objects and reactivate original mesh renderers
///
public void UnCombine()
{
#if UNITY_EDITOR
// Hide progressbar
EditorUtility.ClearProgressBar();
#endif
// Reactivate original renderers
EnableRenderers(_meshList, _skinnedMeshList);
if (_targetParentForCombinedGameObjects == _targetGameObject && _combinedResult != null)
{
for (int i = 0; i < _combinedResult.GetCombinedIndexCount(); i++)
{
if (_combinedResult._combinedGameObjectFromMeshList.Count > i)
{
foreach (GameObject go in _combinedResult._combinedGameObjectFromMeshList[i])
{
DestroyImmediate(go);
}
foreach (GameObject go in _combinedResult._combinedGameObjectFromSkinnedMeshList[i])
{
DestroyImmediate(go);
}
}
}
}
else
{
DestroyImmediate(_targetParentForCombinedGameObjects);
}
// Clear the packed textures
_texturePackers.Clear();
_materialsToCombine.Clear();
_multiMaterialsList.Clear();
_meshCombiner.Clear();
_meshList.Clear();
_skinnedMeshList.Clear();
_uniqueCombinedMeshId.Clear();
_copyMeshId.Clear();
_toSavePrefabList.Clear();
_toSaveObjectList.Clear();
_toSaveMeshList.Clear();
_toSaveSkinnedObjectList.Clear();
if (_combinedResult != null)
{
_combinedResult.Clear();
}
_combiningState = CombineStatesList.Uncombined;
Logger.Instance.AddLog("SuperCombiner", "Successfully uncombined game objects.");
}
///
/// Get the first level children list of the parents
///
///
///
private List GetFirstLevelChildren(Transform parent)
{
List children = new List();
for (int i = 0; i < parent.transform.childCount; i++)
{
children.Add(parent.transform.GetChild(i));
}
return children;
}
///
/// Save combined objects
///
public void Save()
{
#if UNITY_EDITOR
// Combine process is finished
EditorUtility.ClearProgressBar();
if (_folderDestination == "")
{
// Default export folder destination
_folderDestination = "Assets/SuperCombiner/Combined";
}
// Check if destination folder exists
if (!Directory.Exists(_folderDestination))
{
Directory.CreateDirectory(_folderDestination);
}
// Generate new instances (copy from modifiedObjectList) to be saved, so that objects in modifiedObjectList won't be affected by user's modification/deletion
_toSavePrefabList.Clear();
_toSaveObjectList.Clear();
_toSaveMeshList.Clear();
_toSaveSkinnedObjectList.Clear();
Material[] savedMaterial = new Material[_combinedResult.GetCombinedIndexCount()];
for (int i = 0; i < _combinedResult.GetCombinedIndexCount(); i++)
{
if (_combinedResult._combinedMaterials[i].material != null)
{
_texturePackers[i].GenerateCopyedMaterialToSave();
if (_texturePackers[i].GetCombinedMaterialToSave() == null)
{
Logger.Instance.AddLog("SuperCombiner", "Instance of combined _material has been lost, try to combine again before saving.", Logger.LogLevel.LOG_ERROR);
}
else
{
// We need to know if the combined _material has already been saved
savedMaterial[i] = AssetDatabase.LoadAssetAtPath(_folderDestination + "/Materials/" + _texturePackers[i]._copyedMaterials.name + ".mat");
}
}
}
if (_combiningState == CombineStatesList.Combined)
{
// List of all different meshes found on every game objects to save, with no duplication
Dictionary meshMaterialId = new Dictionary();
bool outputSkinnedMesh = false;
List children = new List();
if (_combineMeshes && (LunarCatsStudio.SuperCombiner.MeshOutput)_meshOutput == LunarCatsStudio.SuperCombiner.MeshOutput.SkinnedMesh)
{
// If output is skinnedMesh, we save a copy of modifiedParent as prefab
GameObject copy = InstantiateCopy(_targetParentForCombinedGameObjects, false);
_toSavePrefabList.Add(copy);
outputSkinnedMesh = true;
children = GetFirstLevelChildren(copy.transform);
}
else
{
children = GetFirstLevelChildren(_targetParentForCombinedGameObjects.transform);
}
// Generate copy of game objects to be saved
foreach (Transform child in children)
{
GameObject copy;
if (outputSkinnedMesh)
{
copy = child.gameObject;
}
else
{
copy = InstantiateCopy(child.gameObject, false);
}
List> meshes = FindEnabledMeshes(copy.transform);
List> skinnedMeshes = FindEnabledSkinnedMeshes(copy.transform);
List meshColliders = FindEnabledMeshColliders(copy.transform);
// Create a copy of mesh
foreach (RendererObject mesh in meshes)
{
int instanceId = mesh.Renderer.GetComponent().sharedMesh.GetInstanceID();
if (_uniqueCombinedMeshId.ContainsKey(instanceId))
{
if (meshMaterialId.ContainsKey(_uniqueCombinedMeshId[instanceId]))
{
// This mesh is shared with other game objects, so we reuse the first instance to avoid duplication
mesh.Renderer.GetComponent().sharedMesh = meshMaterialId[_uniqueCombinedMeshId[instanceId]];
}
else
{
Mesh copyOfMesh = _meshCombiner.copyMesh(mesh.Renderer.GetComponent().sharedMesh);
mesh.Renderer.GetComponent().sharedMesh = copyOfMesh;
meshMaterialId.Add(_uniqueCombinedMeshId[instanceId], copyOfMesh);
_toSaveMeshList.Add(copyOfMesh);
}
// Apply a copy of the _material to save
Material[] newMat = new Material[mesh.Renderer.sharedMaterials.Length];
for (int j = 0; j < mesh.Renderer.sharedMaterials.Length; j++)
{
if (_combineMaterials)
{
// Get the _index of this combined _material
int index = 0;
for (int k = 0; k < _combinedResult._combinedMaterials.Count; k++)
{
if (mesh.Renderer.sharedMaterials[j] == _combinedResult._combinedMaterials[k].material)
{
index = k;
}
}
if (savedMaterial[index] != null)
{
// If the combined _material already exists, assign it
newMat[j] = savedMaterial[index];
}
else
{
newMat[j] = _texturePackers[index].GetCombinedMaterialToSave();
}
}
else
{
//newMat[j] = _texturePackers[i].GetTransformedMaterialToSave(mesh.sharedMaterials[j].name);
}
}
mesh.Renderer.sharedMaterials = newMat;
_toSaveObjectList.Add(mesh.Renderer);
}
else
{
Logger.Instance.AddLog("SuperCombiner", "Could not find " + mesh.Renderer.name + " in _uniqueCombinedMeshId, data may has been lost, try to combine again before saving.", Logger.LogLevel.LOG_ERROR);
}
}
foreach (RendererObject skinnedmesh in skinnedMeshes)
{
int instanceId = skinnedmesh.Renderer.sharedMesh.GetInstanceID();
if (_uniqueCombinedMeshId.ContainsKey(instanceId))
{
if (meshMaterialId.ContainsKey(_uniqueCombinedMeshId[instanceId]))
{
// This mesh is shared with other game objects, so we reuse the first instance to avoid duplication
skinnedmesh.Renderer.sharedMesh = meshMaterialId[_uniqueCombinedMeshId[instanceId]];
}
else
{
Mesh copyOfMesh = _meshCombiner.copyMesh(skinnedmesh.Renderer.sharedMesh);
skinnedmesh.Renderer.sharedMesh = copyOfMesh;
meshMaterialId.Add(_uniqueCombinedMeshId[instanceId], copyOfMesh);
_toSaveMeshList.Add(copyOfMesh);
}
// Apply a copy of the _material to save
Material[] newMat = new Material[skinnedmesh.Renderer.sharedMaterials.Length];
for (int j = 0; j < skinnedmesh.Renderer.sharedMaterials.Length; j++)
{
if (_combineMaterials)
{
// Get the _index of this combined _material
int index = 0;
for (int k = 0; k < _combinedResult._combinedMaterials.Count; k++)
{
if (skinnedmesh.Renderer.sharedMaterials[j] == _combinedResult._combinedMaterials[k].material)
{
index = k;
}
}
if (savedMaterial[index] != null)
{
// If the combined _material already exists, assign it
newMat[j] = savedMaterial[index];
}
else
{
newMat[j] = _texturePackers[index].GetCombinedMaterialToSave();
}
}
else
{
//newMat[j] = _texturePackers[i].GetTransformedMaterialToSave(skinnedmesh.sharedMaterials[j].name);
}
}
skinnedmesh.Renderer.sharedMaterials = newMat;
_toSaveSkinnedObjectList.Add(skinnedmesh.Renderer);
}
else
{
Logger.Instance.AddLog("SuperCombiner", "Could not find " + skinnedmesh.Renderer.name + " in _uniqueCombinedMeshId, data may has been lost, try to combine again before saving.", Logger.LogLevel.LOG_ERROR);
}
}
// Assign to mesh colliders the mesh that will be saved
foreach (MeshCollider collider in meshColliders)
{
int instanceId = collider.sharedMesh.GetInstanceID();
string id = null;
_copyMeshId.TryGetValue(instanceId, out id);
if (id != null)
{
if (meshMaterialId.ContainsKey(id))
{
collider.sharedMesh = meshMaterialId[id];
}
}
else
{
// This means the collider has a mesh that is not present in the combine list
// In this case, keep the meshCollider component intact
}
}
// Add this GameObject to the list of prefab to save
if (!outputSkinnedMesh)
{
_toSavePrefabList.Add(copy);
}
}
}
// Saving process
if (_saveTextures)
{
for (int i = 0; i < _combinedResult.GetCombinedIndexCount(); i++)
{
if (_combinedResult._combinedMaterials[i].material != null)
{
Saver.SaveTextures(i, _folderDestination, _sessionName, _texturePackers[i]);
}
}
}
if (_saveMaterials)
{
for (int i = 0; i < _combinedResult.GetCombinedIndexCount(); i++)
{
if (_combinedResult._combinedMaterials[i].material != null)
{
Saver.SaveMaterial(i, _folderDestination, _sessionName, _texturePackers[i]);
}
}
}
if (_savePrefabs)
{
Saver.SavePrefabs(_toSavePrefabList, _toSaveMeshList, _folderDestination, _sessionName);
for (int n = 0; n < _toSavePrefabList.Count; n++)
{
DestroyImmediate(_toSavePrefabList[n]);
}
_toSavePrefabList.Clear();
_toSaveMeshList.Clear();
}
if (_saveMeshObj)
{
for (int i = 0; i < _combinedResult.GetCombinedIndexCount(); i++)
{
if (_combinedResult._combinedMaterials[i].material != null)
{
Saver.SaveMeshesObj(_combinedResult._combinedGameObjectFromMeshList[i], _combinedResult._combinedGameObjectFromSkinnedMeshList[i], _folderDestination);
for (int n = 0; n < _toSaveObjectList.Count; n++)
{
DestroyImmediate(_toSaveObjectList[n]);
}
for (int n = 0; n < _toSaveSkinnedObjectList.Count; n++)
{
DestroyImmediate(_toSaveSkinnedObjectList[n]);
}
_toSaveObjectList.Clear();
_toSaveSkinnedObjectList.Clear();
}
}
}
if (_saveMeshFbx)
{
//SaveMeshesFbx();
}
//Save the combine settings
createSuperCombinerSettings();
Saver.SaveCombinedSettings(_scSettings, _folderDestination, _sessionName);
// Saves the combined result asset
_combinedResult._logs = Logger.Instance.GetLogs();
Saver.SaveCombinedResults(_combinedResult, _folderDestination, _sessionName);
EditorUtility.DisplayDialog("Super Combiner", "Objects saved in '" + _folderDestination + "/' \n\nThanks for using Super Combiner.", "Ok");
// Hide progressbar
EditorUtility.ClearProgressBar();
#endif
}
///
/// create and set the super combiner settings scriptable object
///
private void createSuperCombinerSettings()
{
// If _scSettings has not been created yet, create it
if (_scSettings == null)
{
_scSettings = (SuperCombinerSettings)ScriptableObject.CreateInstance(typeof(SuperCombinerSettings));
}
// General settings
_scSettings.generalSettings.versionNumber = versionNumber;
_scSettings.generalSettings.combineAtRuntime = _combineAtRuntime;
_scSettings.generalSettings.sessionName = _sessionName;
_scSettings.generalSettings.targetGameObject = _targetGameObject;
// Textures settings
_scSettings.textureSettings.atlasSize = _textureAtlasSize;
_scSettings.textureSettings.padding = _atlasPadding;
_scSettings.textureSettings.tilingFactor = _tilingFactor;
// Materials settings
_scSettings.materialSettings.multipleMaterialsCount = _multiMaterialsCount;
_scSettings.materialSettings.multipleMaterialsMode = _multipleMaterialsMode;
_scSettings.materialSettings.multiMaterials0 = multiMaterials0;
_scSettings.materialSettings.multiMaterials1 = multiMaterials1;
_scSettings.materialSettings.multiMaterials2 = multiMaterials2;
_scSettings.materialSettings.multiMaterials3 = multiMaterials3;
_scSettings.materialSettings.multiMaterials4 = multiMaterials4;
_scSettings.materialSettings.multiMaterials5 = multiMaterials5;
_scSettings.materialSettings.multiMaterials6 = multiMaterials6;
_scSettings.materialSettings.multiMaterials7 = multiMaterials7;
_scSettings.materialSettings.multiMaterials8 = multiMaterials8;
_scSettings.materialSettings.multiMaterials9 = multiMaterials9;
_scSettings.materialSettings.multiMaterials10 = multiMaterials10;
_scSettings.materialSettings.customShaderProperties = _customTextureProperies;
// Meshs settings
_scSettings.meshSettings.manageLODs = _manageLodLevel;
_scSettings.meshSettings.managedLODLevel = _managedLodLevel;
_scSettings.meshSettings.manageColliders = _manageColliders;
_scSettings.meshSettings.targetGameObject = _targetGameObject;
_scSettings.meshSettings.combineMeshs = _combineMeshes;
_scSettings.meshSettings.generateUv2 = _generateUv2;
_scSettings.meshSettings.meshOutputType = (MeshSettings.MeshOutputType)_meshOutput;
}
}
}