This commit is contained in:
2025-11-14 18:44:06 +08:00
parent 10156da245
commit 22e867d077
7013 changed files with 2572882 additions and 1804 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b1c85afcb7cdfcd46b1bf4eb41ac8916
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace MeshCombineStudio
{
[CustomEditor(typeof(CombinedLODManager))]
public class CombinedLODManagerEditor : Editor
{
SerializedProperty drawGizmos, distances, lodMode, lodDistanceMode, showLod, lodCulled, lodCullDistance;
SerializedProperty[] distanceElements;
float editorSkinMulti;
private void OnEnable()
{
editorSkinMulti = EditorGUIUtility.isProSkin ? 1 : 0.35f;
drawGizmos = serializedObject.FindProperty("drawGizmos");
lodMode = serializedObject.FindProperty("lodMode");
lodDistanceMode = serializedObject.FindProperty("lodDistanceMode");
showLod = serializedObject.FindProperty("showLod");
distances = serializedObject.FindProperty("distances");
lodCulled = serializedObject.FindProperty("lodCulled");
lodCullDistance = serializedObject.FindProperty("lodCullDistance");
}
public override void OnInspectorGUI()
{
// DrawDefaultInspector();
CombinedLODManager combinedLODManager = (CombinedLODManager)target;
serializedObject.Update();
GUI.color = Color.yellow * editorSkinMulti;
EditorGUILayout.BeginVertical("Box");
GUI.color = Color.white;
GUIDraw.LabelWidthUnderline(new GUIContent("LOD Settings", ""), 14);
EditorGUILayout.PropertyField(drawGizmos);
EditorGUILayout.PropertyField(lodMode);
GUI.changed = false;
EditorGUILayout.PropertyField(lodDistanceMode);
if (GUI.changed)
{
MeshCombiner meshCombiner = combinedLODManager.GetComponent<MeshCombiner>();
if (meshCombiner != null)
{
serializedObject.ApplyModifiedProperties();
combinedLODManager.UpdateDistances(meshCombiner);
return;
}
}
EditorGUILayout.PropertyField(lodCulled);
if (lodCulled.boolValue)
{
EditorGUILayout.PropertyField(lodCullDistance);
if (lodCullDistance.floatValue < 0) lodCullDistance.floatValue = 0;
}
if (lodMode.enumValueIndex == 1)
{
EditorGUILayout.PropertyField(showLod);
if (showLod.intValue < 0) showLod.intValue = 0;
if (showLod.intValue >= distances.arraySize) showLod.intValue = distances.arraySize - 1;
}
else
{
GUI.changed = false;
GUIDraw.PropertyArray(distances, new GUIContent(""), false, false);
if (GUI.changed) lodDistanceMode.enumValueIndex = 1;
if (distanceElements == null || distanceElements.Length != distances.arraySize) distanceElements = new SerializedProperty[distances.arraySize];
for (int i = 0; i < distances.arraySize; i++)
{
distanceElements[i] = distances.GetArrayElementAtIndex(i);
if (i == 0) distanceElements[i].floatValue = 0;
else if (distanceElements[i].floatValue < distanceElements[i - 1].floatValue) distanceElements[i].floatValue = distanceElements[i - 1].floatValue + 0.1f;
}
}
EditorGUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7ef7cd9e299c4944eb153da2a7c31475
timeCreated: 1505285793
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace MeshCombineStudio
{
public class DetectMeshImportSettingsChange : AssetPostprocessor
{
void OnPreprocessModel()
{
// ModelImporter importer = (ModelImporter)assetImporter;
// List<MeshCombiner> instances = MeshCombiner.instances;
// Debug.Log("MeshCombiner instances " + instances.Count);
MeshCombineJobManager.ResetMeshCache();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7699aab1f48b4bf4bac9ecf5ceece31d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,81 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace MeshCombineStudio
{
static public class GUIDraw
{
static public void DrawSpacer(float spaceBegin = 5, float height = 5, float spaceEnd = 5)
{
GUILayout.Space(spaceBegin - 1);
EditorGUILayout.BeginHorizontal();
GUI.color = new Color(0.5f, 0.5f, 0.5f, 1);
GUILayout.Button("", GUILayout.Height(height));
EditorGUILayout.EndHorizontal();
GUILayout.Space(spaceEnd);
GUI.color = Color.white;
}
static public void Label(string label, int fontSize)
{
int fontSizeOld = EditorStyles.label.fontSize;
EditorStyles.boldLabel.fontSize = fontSize;
EditorGUILayout.LabelField(label, EditorStyles.boldLabel, GUILayout.Height(fontSize + 6));
EditorStyles.boldLabel.fontSize = fontSizeOld;
}
static public void LabelWidthUnderline(GUIContent guiContent, int fontSize, bool boldLabel = true)
{
int fontSizeOld = EditorStyles.label.fontSize;
EditorStyles.boldLabel.fontSize = fontSize;
EditorGUILayout.LabelField(guiContent, boldLabel ? EditorStyles.boldLabel : EditorStyles.label, GUILayout.Height(fontSize + 6));
EditorStyles.boldLabel.fontSize = fontSizeOld;
DrawUnderLine();
GUILayout.Space(5);
}
static public void DrawUnderLine(float offsetY = 0)
{
Rect rect = GUILayoutUtility.GetLastRect();
if (EditorGUIUtility.isProSkin) GUI.color = Color.grey; else GUI.color = Color.black;
GUI.DrawTexture(new Rect(rect.x, rect.yMax + offsetY, rect.width, 1), Texture2D.whiteTexture);
GUI.color = Color.white;
}
static public void PropertyArray(SerializedProperty property, GUIContent arrayName, bool drawUnderLine = true, bool editArrayLength = true)
{
EditorGUILayout.BeginHorizontal();
EditorGUI.indentLevel++;
GUILayout.Space(0);
Rect rect = GUILayoutUtility.GetLastRect();
property.isExpanded = EditorGUI.Foldout(new Rect(rect.x, rect.y + 3, 25, 18), property.isExpanded, "");
EditorGUILayout.PrefixLabel(new GUIContent(arrayName.text + " Size", arrayName.tooltip));
if (property.isExpanded)
{
if (editArrayLength)
{
EditorGUI.indentLevel -= 2;
property.arraySize = EditorGUILayout.IntField("", property.arraySize);
EditorGUI.indentLevel += 2;
}
EditorGUILayout.EndHorizontal();
EditorGUI.indentLevel++;
for (int i = 0; i < property.arraySize; i++)
{
SerializedProperty elementProperty = property.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(elementProperty);
}
EditorGUI.indentLevel--;
}
else EditorGUILayout.EndHorizontal();
EditorGUI.indentLevel--;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: adcd9501ac7d57d48bad76228fb8ec8c
timeCreated: 1505286253
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace MeshCombineStudio
{
[CustomEditor(typeof(LODGroupSetup))]
public class LODGroupSetupEditor : Editor
{
LODGroupSetup lodGroupSetup;
LOD[] oldLods;
void OnEnable()
{
lodGroupSetup = (LODGroupSetup)target;
oldLods = lodGroupSetup.lodGroup.GetLODs();
UnityEditor.EditorApplication.update += MyUpdate;
}
void OnDisable()
{
UnityEditor.EditorApplication.update -= MyUpdate;
}
void MyUpdate()
{
lodGroupSetup.lodGroup.size = lodGroupSetup.meshCombiner.cellSize;
LOD[] lods = lodGroupSetup.lodGroup.GetLODs();
if (lods.Length != oldLods.Length)
{
Debug.LogError("Mesh Combine Studio -> Please don't change the amount of LODs, this is just a dummy LOD Group to apply settings to the LOD Groups in all children.");
lodGroupSetup.lodGroup.SetLODs(oldLods);
return;
}
bool hasChanged = false;
for (int i = 0; i < lods.Length; i++)
{
if (lods[i].renderers.Length != 0)
{
Debug.LogError("Mesh Combine Studio -> Please don't add any renderes, this is just a dummy LOD Group to apply settings to the LOD Groups in all children.");
lods[i].renderers = null;
lodGroupSetup.lodGroup.SetLODs(lods);
return;
}
if (lods[i].screenRelativeTransitionHeight != oldLods[i].screenRelativeTransitionHeight) { hasChanged = true; break; }
}
if (hasChanged)
{
lodGroupSetup.ApplySetup();
oldLods = lods;
}
}
public override void OnInspectorGUI()
{
GUIDraw.DrawSpacer();
GUI.color = Color.red;
EditorGUILayout.BeginVertical("Box");
GUI.color = Color.white;
GUIDraw.Label("Modifications to this LOD Group will apply to all children", 12);
EditorGUILayout.EndVertical();
GUIDraw.DrawSpacer();
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 3ef171e414f62184eba74f7056cb8999
timeCreated: 1510472214
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace MeshCombineStudio
{
[CustomEditor(typeof(MeshCombineJobManager))]
public class MeshCombineJobManagerEditor : Editor
{
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a1741cca49091f8468bea22cf3e838a4
timeCreated: 1509644157
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 43b032503a6ec4e43a5ead762b8ff8b6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,167 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.IO;
using System.Text;
namespace MeshCombineStudio
{
public class ObjExporterScript
{
private static int StartIndex = 0;
public static void Start()
{
StartIndex = 0;
}
public static void End()
{
StartIndex = 0;
}
public static string MeshToString(MeshRenderer mr, MeshFilter mf, Transform t)
{
// Vector3 s = t.localScale;
// Vector3 p = t.localPosition;
Quaternion r = t.localRotation;
int numVertices = 0;
Mesh m = mf.sharedMesh;
if (m == null) return "####Error####";
Material[] mats = mr.sharedMaterials;
StringBuilder sb = new StringBuilder();
foreach (Vector3 vv in m.vertices)
{
Vector3 v = t.TransformPoint(vv);
numVertices++;
sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, -v.z));
}
sb.Append("\n");
foreach (Vector3 nn in m.normals)
{
Vector3 v = r * nn;
sb.Append(string.Format("vn {0} {1} {2}\n", -v.x, -v.y, v.z));
}
sb.Append("\n");
foreach (Vector3 v in m.uv)
{
sb.Append(string.Format("vt {0} {1}\n", v.x, v.y));
}
for (int material = 0; material < m.subMeshCount; material++)
{
sb.Append("\n");
sb.Append("usemtl ").Append(mats[material].name).Append("\n");
sb.Append("usemap ").Append(mats[material].name).Append("\n");
int[] triangles = m.GetTriangles(material);
for (int i = 0; i < triangles.Length; i += 3)
{
sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n",
triangles[i] + 1 + StartIndex, triangles[i + 1] + 1 + StartIndex, triangles[i + 2] + 1 + StartIndex));
}
}
StartIndex += numVertices;
return sb.ToString();
}
}
public class ObjExporter : ScriptableObject
{
[MenuItem("GameObject/Export/Wavefront OBJ")]
static void DoExportWSubmeshes()
{
DoExport(true);
}
[MenuItem("GameObject/Export/Wavefront OBJ (No Submeshes)")]
static void DoExportWOSubmeshes()
{
DoExport(false);
}
static void DoExport(bool makeSubmeshes)
{
if (Selection.gameObjects.Length == 0)
{
Debug.Log("Didn't Export Any Meshes; Nothing was selected!");
return;
}
string meshName = Selection.gameObjects[0].name;
string fileName = EditorUtility.SaveFilePanel("Export .obj file", "", meshName, "obj");
ObjExporterScript.Start();
StringBuilder meshString = new StringBuilder();
meshString.Append("#" + meshName + ".obj"
+ "\n#" + System.DateTime.Now.ToLongDateString()
+ "\n#" + System.DateTime.Now.ToLongTimeString()
+ "\n#-------"
+ "\n\n");
Transform t = Selection.gameObjects[0].transform;
Vector3 originalPosition = t.position;
t.position = Vector3.zero;
if (!makeSubmeshes)
{
meshString.Append("g ").Append(t.name).Append("\n");
}
meshString.Append(processTransform(t, makeSubmeshes));
WriteToFile(meshString.ToString(), fileName);
t.position = originalPosition;
ObjExporterScript.End();
Debug.Log("Exported Mesh: " + fileName);
}
static string processTransform(Transform t, bool makeSubmeshes)
{
StringBuilder meshString = new StringBuilder();
meshString.Append("#" + t.name
+ "\n#-------"
+ "\n");
if (makeSubmeshes)
{
meshString.Append("g ").Append(t.name).Append("\n");
}
MeshFilter mf = t.GetComponent<MeshFilter>();
if (mf)
{
MeshRenderer mr = t.GetComponent<MeshRenderer>();
if (mr != null)
{
meshString.Append(ObjExporterScript.MeshToString(mr, mf, t));
}
}
for (int i = 0; i < t.childCount; i++)
{
meshString.Append(processTransform(t.GetChild(i), makeSubmeshes));
}
return meshString.ToString();
}
static void WriteToFile(string s, string filename)
{
using (StreamWriter sw = new StreamWriter(filename))
{
sw.Write(s);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9a501084de9636c4b98254524aa63fc2
timeCreated: 1504780640
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace MeshCombineStudio
{
[CustomEditor (typeof(ReadMe))]
public class ReadMeEditor : Editor
{
public override void OnInspectorGUI()
{
ReadMe r = (ReadMe)target;
Event eventCurrent = Event.current;
GUI.changed = false;
if (eventCurrent.control && eventCurrent.shift && eventCurrent.keyCode == KeyCode.E && eventCurrent.type == EventType.KeyDown)
{
r.buttonEdit = !r.buttonEdit;
GUI.changed = true;
}
GUILayout.Space(5);
if (r.buttonEdit)
{
EditorGUILayout.LabelField("EDIT MODE");
r.readme = EditorGUILayout.TextArea(r.readme);
}
else
{
EditorGUILayout.TextArea(r.readme);
}
if (GUI.changed) EditorUtility.SetDirty(target);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 695a9de9c2be7154b8c6d6ea5065d7be
timeCreated: 1511099118
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 367244e76dd75ab4b8d86e67f93edeb3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,25 @@
fileFormatVersion: 2
guid: bcf366a06e782db4c943d6aa88c3fb11
timeCreated: 1509489607
licenseType: Store
PluginImporter:
serializedVersion: 1
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
Any:
enabled: 1
settings: {}
Editor:
enabled: 0
settings:
DefaultValueInitialized: true
WindowsStoreApps:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b2b1c73527348cd439c7e4157e189078
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2ab62df6639f22840a4305d62af40a72
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class DisabledLODGroup : MonoBehaviour
{
[HideInInspector] public MeshCombiner meshCombiner;
public LODGroup lodGroup;
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ec7640472ee37d84298be8f3769ced5f
timeCreated: 1510250774
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
[ExecuteInEditMode]
public class FindLodGroups : MonoBehaviour
{
public bool find;
void Start()
{
FindLods();
}
void Update()
{
if (find)
{
find = false;
FindLods();
}
}
void FindLods()
{
LODGroup[] lodGroups = GetComponentsInChildren<LODGroup>(true);
for (int i = 0; i < lodGroups.Length; i++)
{
Debug.Log(lodGroups[i].name);
}
Debug.Log("---------------------------------------------");
Debug.Log("LODGroups found " + lodGroups.Length);
Debug.Log("---------------------------------------------");
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b31f9c228d56bf043b5219a5ff58508b
timeCreated: 1508838518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,131 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class LODGroupSetup : MonoBehaviour {
public MeshCombiner meshCombiner;
public LODGroup lodGroup;
public int lodGroupParentIndex;
public int lodCount;
LODGroup[] lodGroups;
public void Init(MeshCombiner meshCombiner, int lodGroupParentIndex)
{
this.meshCombiner = meshCombiner;
this.lodGroupParentIndex = lodGroupParentIndex;
lodCount = lodGroupParentIndex + 1;
if (lodGroup == null) lodGroup = gameObject.AddComponent<LODGroup>();
GetSetup();
}
void GetSetup()
{
LOD[] lods = new LOD[lodGroupParentIndex + 1];
for (int i = 0; i < lods.Length; i++)
{
lods[i] = new LOD();
lods[i].screenRelativeTransitionHeight = meshCombiner.lodGroupsSettings[lodGroupParentIndex].lodSettings[i].screenRelativeTransitionHeight;
}
lodGroup.SetLODs(lods);
}
public void ApplySetup()
{
// Debug.Log("ApplySetup");
LOD[] lods = lodGroup.GetLODs();
if (lodGroups == null) lodGroups = GetComponentsInChildren<LODGroup>();
if (lods.Length != lodCount) return;
bool lodGroupsAreRemoved = false;
if (lodGroupParentIndex == 0)
{
// Debug.Log("Length " + lodGroups.Length +" " +lods[0].screenRelativeTransitionHeight);
if (lods[0].screenRelativeTransitionHeight != 0)
{
if (lodGroups == null || lodGroups.Length == 1) AddLODGroupsToChildren();
}
else
{
if (lodGroup != null && lodGroups.Length != 1) RemoveLODGroupFromChildren();
lodGroupsAreRemoved = true;
}
}
if (meshCombiner != null)
{
for (int i = 0; i < lods.Length; i++)
{
meshCombiner.lodGroupsSettings[lodGroupParentIndex].lodSettings[i].screenRelativeTransitionHeight = lods[i].screenRelativeTransitionHeight;
}
}
if (lodGroupsAreRemoved) return;
for (int i = 0; i < lodGroups.Length; i++)
{
LOD[] childLods = lodGroups[i].GetLODs();
for (int j = 0; j < childLods.Length; j++)
{
childLods[j].screenRelativeTransitionHeight = lods[j].screenRelativeTransitionHeight;
}
lodGroups[i].SetLODs(childLods);
}
if (meshCombiner != null) lodGroup.size = meshCombiner.cellSize;
}
public void AddLODGroupsToChildren()
{
// Debug.Log("Add Lod Groups");
Transform t = transform;
List<LODGroup> lodGroupList = new List<LODGroup>();
for (int i = 0; i < t.childCount; i++)
{
Transform child = t.GetChild(i);
Debug.Log(child.name);
LODGroup lodGroup = child.GetComponent<LODGroup>();
if (lodGroup == null)
{
lodGroup = child.gameObject.AddComponent<LODGroup>();
LOD[] lods = new LOD[1];
lods[0] = new LOD(0, child.GetComponentsInChildren<MeshRenderer>());
lodGroup.SetLODs(lods);
}
lodGroupList.Add(lodGroup);
}
lodGroups = lodGroupList.ToArray();
}
public void RemoveLODGroupFromChildren()
{
// Debug.Log("Remove Lod Groups");
Transform t = transform;
for (int i = 0; i < t.childCount; i++)
{
Transform child = t.GetChild(i);
LODGroup lodGroup = child.GetComponent<LODGroup>();
if (lodGroup != null) DestroyImmediate(lodGroup);
}
lodGroups = null;
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 3e72c6f397f46114ca26e357c0ff7e27
timeCreated: 1510423325
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 57218c459b70257439cddc01f02a89e0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,264 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class CamGeometryCapture : MonoBehaviour
{
public ComputeShader computeDepthToArray;
public Int2 resolution = new Int2(1024, 1024);
// public bool capture;
// public float radius = 0.5f;
public Camera cam;
public Transform t;
public RenderTexture rtCapture;
float[] heights;
Bounds bounds;
float maxSize;
public void Init()
{
if (t != null) return;
t = transform;
cam = GetComponent<Camera>();
cam.aspect = 1;
cam.orthographic = true;
}
void OnDestroy()
{
DisposeRTCapture();
}
//void Update()
//{
// if (capture)
// {
// capture = false;
// Capture(mr.bounds, collisionMask.value, direction, resolution);
// }
//}
void DisposeRenderTexture(ref RenderTexture rt)
{
if (rt == null) return;
rt.Release();
#if UNITY_EDITOR
DestroyImmediate(rt);
#else
Destroy(rt);
#endif
rt = null;
}
public void DisposeRTCapture()
{
cam.targetTexture = null;
DisposeRenderTexture(ref rtCapture);
}
public void RemoveTrianglesBelowSurface(Transform t, MeshCombineJobManager.MeshCombineJob meshCombineJob, MeshCache.SubMeshCache newMeshCache, ref byte[] vertexIsBelow)
{
if (vertexIsBelow == null) vertexIsBelow = new byte[65534];
Vector3 pos = Vector3.zero;
int layerMask = meshCombineJob.meshCombiner.surfaceLayerMask;
// float rayHeight = meshCombineJob.meshCombiner.maxSurfaceHeight;
Vector3[] newVertices = newMeshCache.vertices;
int[] newTriangles = newMeshCache.triangles;
List<MeshObject> meshObjects = meshCombineJob.meshObjectsHolder.meshObjects;
int startIndex = meshCombineJob.startIndex;
int endIndex = meshCombineJob.endIndex;
const byte belowSurface = 1, aboveSurface = 2;
for (int i = startIndex; i < endIndex; i++)
{
MeshObject meshObject = meshObjects[i];
Capture(meshObject.cachedGO.mr.bounds, layerMask, new Vector3(0, -1, 0), new Int2(1024, 1024));
int startTriangleIndex = meshObject.startNewTriangleIndex;
int endTriangleIndex = meshObject.newTriangleCount + startTriangleIndex;
// Debug.Log("startIndex " + startIndex + " triangle " + startTriangleIndex + " - " + endTriangleIndex);
for (int j = startTriangleIndex; j < endTriangleIndex; j += 3)
{
bool isAboveSurface = false;
for (int k = 0; k < 3; k++)
{
int vertexIndex = newTriangles[j + k];
if (vertexIndex == -1) continue;
byte isBelow = vertexIsBelow[vertexIndex];
if (isBelow == 0)
{
pos = t.TransformPoint(newVertices[vertexIndex]);
float height = GetHeight(pos);
isBelow = pos.y < height ? belowSurface : aboveSurface;
vertexIsBelow[vertexIndex] = isBelow;
if (pos.y < height)
{
vertexIsBelow[vertexIndex] = isBelow = belowSurface;
}
else
{
vertexIsBelow[vertexIndex] = isBelow = aboveSurface;
}
}
if (isBelow != belowSurface) { isAboveSurface = true; break; }
}
if (!isAboveSurface)
{
meshCombineJob.trianglesRemoved += 3;
newTriangles[j] = -1;
}
}
}
Array.Clear(vertexIsBelow, 0, newVertices.Length);
}
public void Capture(Bounds bounds, int collisionMask, Vector3 direction, Int2 resolution)
{
if (rtCapture == null || rtCapture.width != resolution.x || rtCapture.height != resolution.y)
{
if (rtCapture != null) DisposeRTCapture();
rtCapture = new RenderTexture(resolution.x, resolution.y, 16, RenderTextureFormat.Depth, RenderTextureReadWrite.Linear);
}
bounds.size *= 1.1f;
this.bounds = bounds;
cam.targetTexture = rtCapture;
cam.cullingMask = collisionMask;
SetCamera(direction);
cam.Render();
int heightsLength = resolution.x * resolution.y;
ComputeBuffer heightBuffer = new ComputeBuffer(heightsLength, 4);
computeDepthToArray.SetTexture(0, "rtDepth", rtCapture);
computeDepthToArray.SetBuffer(0, "heightBuffer", heightBuffer);
computeDepthToArray.SetInt("resolution", resolution.x);
computeDepthToArray.SetFloat("captureHeight", t.position.y);
computeDepthToArray.SetFloat("distance", bounds.size.y + 256);
computeDepthToArray.SetInt("direction", direction.y == 1 ? 1 : -1);
computeDepthToArray.Dispatch(0, Mathf.CeilToInt(resolution.x / 8), Mathf.CeilToInt(resolution.y / 8), 1);
if (heights == null || heights.Length != heightsLength) heights = new float[heightsLength];
heightBuffer.GetData(heights);
// Debug.Log(bounds.size.x + " " + bounds.size.y + " " + bounds.size.z);
heightBuffer.Dispose();
}
//private void OnDrawGizmos()
//{
// Gizmos.color = Color.red;
// Mesh m = mf.sharedMesh;
// Vector3[] vertices = m.vertices;
// // Vector3 startPos = new Vector3(t.position.x, 0, t.position.z) - new Vector3(maxSize / 2, 0, maxSize / 2);
// for (int i = 0; i < vertices.Length; i++)
// {
// Vector3 pos = mf.transform.TransformPoint(vertices[i]);
// pos.y = GetHeight(pos);
// Gizmos.DrawSphere(pos, radius);
// }
//}
public void SetCamera(Vector3 direction)
{
if (direction == new Vector3(0, 1, 0))
{
t.position = bounds.center - new Vector3(0, bounds.extents.y + 256, 0);
}
else if (direction == new Vector3(0, -1, 0))
{
t.position = bounds.center + new Vector3(0, bounds.extents.y + 256, 0);
}
t.forward = direction;
maxSize = bounds.size.x;
if (bounds.size.z > maxSize) maxSize = bounds.size.z;
cam.orthographicSize = maxSize / 2;
cam.nearClipPlane = 0;
cam.farClipPlane = (bounds.size.y + 256);
}
public float GetHeight(Vector3 pos)
{
pos -= bounds.min;
pos.x += (maxSize - bounds.size.x) / 2;
pos.z += (maxSize - bounds.size.z) / 2;
float xx = maxSize / (resolution.x);
float yy = maxSize / (resolution.y);
float x = (int)(pos.x / xx);
float y = (int)(pos.z / yy);
if (x > resolution.x - 2 || x < 0 || y > resolution.y - 2 || y < 0)
{
Debug.Log("Out of bounds " + x + " " + y);
return 0;
}
int intX = (int)x;
int intY = (int)y;
float lerpValue = x - intX;
float height0 = heights[intX + (intY * resolution.y)];
float height1 = heights[intX + 1 + (intY * resolution.y)];
float heightx1 = Mathf.Lerp(height0, height1, lerpValue);
height0 = heights[intX + ((intY + 1) * resolution.y)];
height1 = heights[intX + 1 + ((intY + 1) * resolution.y)];
float heightx2 = Mathf.Lerp(height0, height1, lerpValue);
lerpValue = y - intY;
return Mathf.Lerp(heightx1, heightx2, lerpValue);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5118f6ea05613d14b899e139ed9dcbff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,274 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class CombinedLODManager : MonoBehaviour
{
public enum LodMode { Automatic, DebugLod }
public enum LodDistanceMode { Automatic, Manual }
public bool drawGizmos = true;
public LOD[] lods;
public float[] distances;
public LodDistanceMode lodDistanceMode;
public LodMode lodMode;
public int showLod = 0;
public bool lodCulled;
public float lodCullDistance = 500;
public Vector3 octreeCenter = Vector3.zero;
public Vector3 octreeSize = new Vector3(256, 256, 256);
public int maxLevels = 4;
public bool search = true;
Cell octree;
Transform cameraMainT;
void Awake()
{
cameraMainT = Camera.main.transform;
}
void InitOctree()
{
octree = new Cell(octreeCenter, octreeSize, maxLevels);
}
private void Start()
{
if (search)
{
search = false;
InitOctree();
Search();
}
}
void Update()
{
if (octree.cellsUsed != null) Lod(lodMode);
}
public void UpdateLods(MeshCombiner meshCombiner, int lodAmount)
{
if (lods != null && lods.Length == lodAmount) return;
lods = new LOD[lodAmount];
float[] newDistances = new float[lodAmount];
for (int i = 0; i < lods.Length; i++)
{
lods[i] = new LOD();
if (lodDistanceMode == LodDistanceMode.Automatic) newDistances[i] = meshCombiner.cellSize * i;
else if (distances != null && i < distances.Length) newDistances[i] = distances[i];
}
distances = newDistances;
}
public void UpdateDistances(MeshCombiner meshCombiner)
{
if (lodDistanceMode != LodDistanceMode.Automatic) return;
for (int i = 0; i < distances.Length; i++) distances[i] = meshCombiner.cellSize * i;
}
public void Search()
{
for (int i = 0; i < lods.Length; i++)
{
lods[i].searchParent.gameObject.SetActive(true);
MeshRenderer[] mrs = lods[i].searchParent.GetComponentsInChildren<MeshRenderer>();
for (int j = 0; j < mrs.Length; j++) octree.AddMeshRenderer(mrs[j], mrs[j].transform.position, i, lods.Length);
}
}
public void ResetOctree()
{
if (octree == null) return;
octree.cells = null;
octree.cellsUsed = null;
for (int i = 0; i < lods.Length; i++)
{
if (lods[i].searchParent != null) Destroy(lods[i].searchParent.gameObject);
}
}
public void Lod(LodMode lodMode)
{
Vector3 cameraPosition = cameraMainT.position;
for (int i = 0; i < lods.Length - 1; i++)
{
lods[i].sphere.center = cameraPosition;
lods[i].sphere.radius = distances[i + 1];
}
// if (Benchmark.active) lodBenchmark.Start();
if (lodMode == LodMode.Automatic) octree.AutoLodInternal(lods, lodCulled ? lodCullDistance : -1);
else octree.LodInternal(lods, showLod);
// if (Benchmark.active) lodBenchmark.Stop();
}
private void OnDrawGizmosSelected()
{
if (drawGizmos && octree != null && octree.cells != null) octree.DrawGizmos(lods);
}
[System.Serializable]
public class LOD
{
public Transform searchParent;
public Sphere3 sphere = new Sphere3();
public LOD() { }
public LOD(Transform searchParent)
{
this.searchParent = searchParent;
}
}
public class Cell : BaseOctree.Cell
{
public Cell[] cells;
AABB3 box;
public Cell() { }
public Cell(Vector3 position, Vector3 size, int maxLevels) : base(position, size, maxLevels) { }
public void AddMeshRenderer(MeshRenderer mr, Vector3 position, int lodLevel, int lodLevels)
{
if (InsideBounds(position)) AddMeshRendererInternal(mr, position, lodLevel, lodLevels);
}
void AddMeshRendererInternal(MeshRenderer mr, Vector3 position, int lodLevel, int lodLevels)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.mrList == null) thisCell.mrList = new List<MeshRenderer>[lodLevels];
List<MeshRenderer>[] mrList = thisCell.mrList;
if (mrList[lodLevel] == null) mrList[lodLevel] = new List<MeshRenderer>();
mrList[lodLevel].Add(mr);
thisCell.currentLod = -1;
}
else
{
bool maxCellCreated;
int index = AddCell<Cell, MaxCell>(ref cells, position, out maxCellCreated);
cells[index].box = new AABB3(cells[index].bounds.min, cells[index].bounds.max);
cells[index].AddMeshRendererInternal(mr, position, lodLevel, lodLevels);
}
}
public void AutoLodInternal(LOD[] lods, float lodCulledDistance)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (lodCulledDistance != -1)
{
float squareDistance = (bounds.center - lods[0].sphere.center).sqrMagnitude;
if (squareDistance > lodCulledDistance * lodCulledDistance)
{
if (thisCell.currentLod != -1)
{
for (int i = 0; i < lods.Length; i++)
{
for (int j = 0; j < thisCell.mrList[i].Count; j++) thisCell.mrList[i][j].enabled = false;
}
thisCell.currentLod = -1;
}
return;
}
}
for (int lodIndex = 0; lodIndex < lods.Length; lodIndex++)
{
bool intersect;
if (lodIndex < lods.Length - 1) intersect = Mathw.IntersectAABB3Sphere3(box, lods[lodIndex].sphere);
else intersect = true;
if (intersect)
{
if (thisCell.currentLod != lodIndex)
{
for (int i = 0; i < lods.Length; i++)
{
bool active = (i == lodIndex);
for (int j = 0; j < thisCell.mrList[i].Count; j++) thisCell.mrList[i][j].enabled = active;
}
thisCell.currentLod = lodIndex;
}
break;
}
}
}
else for (int i = 0; i < 8; ++i) if (cellsUsed[i]) cells[i].AutoLodInternal(lods, lodCulledDistance);
}
public void LodInternal(LOD[] lods, int lodLevel)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.currentLod != lodLevel)
{
for (int i = 0; i < lods.Length; i++)
{
bool active = (i == lodLevel);
for (int j = 0; j < thisCell.mrList[i].Count; j++) thisCell.mrList[i][j].enabled = active;
}
thisCell.currentLod = lodLevel;
}
}
else for (int i = 0; i < 8; ++i) if (cellsUsed[i]) cells[i].LodInternal(lods, lodLevel);
} //===============================================================================================================================
public void DrawGizmos(LOD[] lods)
{
for (int i = 0; i < lods.Length; i++)
{
if (i == 0) Gizmos.color = Color.red;
else if (i == 1) Gizmos.color = Color.green;
else if (i == 2) Gizmos.color = Color.yellow;
else if (i == 3) Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(lods[i].sphere.center, lods[i].sphere.radius);
}
DrawGizmosInternal();
}
public void DrawGizmosInternal()
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.currentLod == 0) Gizmos.color = Color.red;
else if (thisCell.currentLod == 1) Gizmos.color = Color.green;
else if (thisCell.currentLod == 2) Gizmos.color = Color.yellow;
else if (thisCell.currentLod == 3) Gizmos.color = Color.blue;
Gizmos.DrawWireCube(bounds.center, bounds.size - new Vector3(0.25f, 0.25f, 0.25f));
Gizmos.color = Color.white;
}
else for (int i = 0; i < 8; ++i) if (cellsUsed[i]) cells[i].DrawGizmosInternal();
}
}
public class MaxCell : Cell
{
public List<MeshRenderer>[] mrList;
public int currentLod;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 01b543286c6d4484c9335dbf57a0b586
timeCreated: 1496162540
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class ListMeshVertCount : MonoBehaviour {
public bool includeInActive;
public bool listVertCount;
void Update()
{
if (listVertCount)
{
listVertCount = false;
ListVertCount();
}
}
void ListVertCount()
{
MeshFilter[] mfs = GetComponentsInChildren<MeshFilter>(includeInActive);
int vertCount = 0;
int triangleCount = 0;
for (int i = 0; i < mfs.Length; i++)
{
Mesh m = mfs[i].sharedMesh;
if (m == null) continue;
vertCount += m.vertexCount;
triangleCount += m.triangles.Length;
}
Debug.Log(gameObject.name + " Vertices " + vertCount + " Triangles " + triangleCount);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d9eaad923cc4fca4396a6e2ec092b9e9
timeCreated: 1507213037
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 409bc0be2fd0301499c7685349d5eef7
timeCreated: 1509346503
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c7fb52db265e28e4eb22d6300d01e030
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,111 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
[ExecuteInEditMode]
public class ObjectSpawner : MonoBehaviour
{
public GameObject[] objects;
public float density = 0.5f;
public Vector2 scaleRange = new Vector2(0.5f, 2f);
public Vector3 rotationRange = new Vector3(5, 360, 5);
public Vector2 heightRange = new Vector2(0, 1);
public float scaleMulti = 1;
public float resolutionPerMeter = 2;
public bool spawnInRuntime;
public bool spawn;
public bool deleteChildren;
Transform t;
private void Awake()
{
t = transform;
if (spawnInRuntime && Application.isPlaying)
{
Spawn();
}
}
private void Update()
{
if (spawn)
{
spawn = false;
Spawn();
}
if (deleteChildren)
{
deleteChildren = false;
DeleteChildren();
}
}
public void DeleteChildren()
{
Transform[] transforms = GetComponentsInChildren<Transform>();
for (int i = 0; i < transforms.Length; i++)
{
if (t != transforms[i] && transforms[i] != null) DestroyImmediate(transforms[i].gameObject);
}
}
public void Spawn()
{
Bounds bounds = new Bounds();
bounds.center = transform.position;
bounds.size = transform.lossyScale;
float xStart = bounds.min.x;
float xEnd = bounds.max.x;
float yStart = bounds.min.y;
float yEnd = bounds.max.y;
float zStart = bounds.min.z;
float zEnd = bounds.max.z;
int objectCount = objects.Length;
float halfRes = resolutionPerMeter * 0.5f;
float heightOffset = transform.lossyScale.y * 0.5f;
int count = 0;
for (float z = zStart; z < zEnd; z += resolutionPerMeter)
{
for (float x = xStart; x < xEnd; x += resolutionPerMeter)
{
for (float y = yStart; y < yEnd; y += resolutionPerMeter)
{
int index = Random.Range(0, objectCount);
float spawnValue = Random.value;
if (spawnValue < density)
{
Vector3 pos = new Vector3(x + Random.Range(-halfRes, halfRes), yStart + (Random.Range(0, bounds.size.y) * Random.Range(heightRange.x, heightRange.y)), z + Random.Range(-halfRes, halfRes));
if (pos.x < xStart || pos.x > xEnd || pos.y < yStart || pos.y > yEnd || pos.z < zStart || pos.z > zEnd) continue;
pos.y += heightOffset;
Vector3 eulerAngles = new Vector3(Random.Range(0, rotationRange.x), Random.Range(0, rotationRange.y), Random.Range(0, rotationRange.z));
GameObject go = (GameObject)Instantiate(objects[index], pos, Quaternion.Euler(eulerAngles));
float scale = Random.Range(scaleRange.x, scaleRange.y) * scaleMulti;
go.transform.localScale = new Vector3(scale, scale, scale);
go.transform.parent = t;
++count;
}
}
}
}
Debug.Log("Spawned " + count);
}
private void OnDrawGizmosSelected()
{
Gizmos.DrawWireCube(transform.position + new Vector3(0, transform.lossyScale.y * 0.5f, 0), transform.lossyScale);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 80e3d5613a0399b4b87617ecc61c7c94
timeCreated: 1505205806
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,276 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// This feature will be added in the next update
namespace MeshCombineStudio
{
public class RemoveGeometryBelowTerrain : MonoBehaviour
{
int totalTriangles;
int removeTriangles;
int skippedObjects;
public List<Transform> terrains = new List<Transform>();
public List<Transform> meshTerrains = new List<Transform>();
public Bounds[] terrainBounds, meshBounds;
Terrain[] terrainComponents;
Terrain[] terrainArray;
Bounds[] terrainBoundsArray; //, meshBoundsArray;
MeshRenderer[] mrs;
Mesh[] meshTerrainComponents;
Mesh[] meshArray;
public bool runOnStart;
private void Start()
{
if (runOnStart)
{
Remove(gameObject);
}
}
public void Remove(GameObject go)
{
MeshFilter[] mfs = go.GetComponentsInChildren<MeshFilter>(true);
totalTriangles = 0;
removeTriangles = 0;
skippedObjects = 0;
for (int i = 0; i < mfs.Length; i++)
{
RemoveMesh(mfs[i].transform, mfs[i].mesh);
}
Debug.Log("Removeable " + removeTriangles + " total " + totalTriangles + " improvement " + (((float)removeTriangles / totalTriangles) * 100).ToString("F2"));
Debug.Log("Skipped Objects " + skippedObjects);
}
public void RemoveMesh(Transform t, Mesh mesh)
{
if (mesh == null) return;
if (!(IsMeshUnderTerrain(t, mesh))) { ++skippedObjects; return; }
Vector3[] vertices = mesh.vertices;
List<int> newTriangles = new List<int>();
for (int i = 0; i < mesh.subMeshCount; i++)
{
newTriangles.AddRange(mesh.GetTriangles(i));
int length = newTriangles.Count;
RemoveTriangles(t, newTriangles, vertices);
if (newTriangles.Count < length) mesh.SetTriangles(newTriangles.ToArray(), i);
}
}
public bool IsMeshUnderTerrain(Transform t, Mesh mesh)
{
Bounds bounds = mesh.bounds;
bounds.center += t.position;
Vector3 min = bounds.min;
Vector3 max = bounds.max;
//Vector3 center = bounds.center;
Vector2 delta = new Vector2(max.x - min.x, max.z - min.z);
for (float z = 0; z < 1; z += 0.125f)
{
for (float x = 0; x < 1; x += 0.125f)
{
Vector3 p = new Vector3(min.x + (x * delta.x), min.y, min.z + (z * delta.y));
float height = 0;// terrainColliderCam.GetHeight(p);
if (p.y < height) return true;
}
}
return false;
}
public void GetTerrainComponents()
{
terrainComponents = new Terrain[terrains.Count];
for (int i = 0; i < terrains.Count; i++)
{
Terrain terrain = terrains[i].GetComponent<Terrain>();
terrainComponents[i] = terrain;
}
}
public void GetMeshRenderersAndComponents()
{
mrs = new MeshRenderer[meshTerrains.Count];
meshTerrainComponents = new Mesh[meshTerrains.Count];
for (int i = 0; i < meshTerrains.Count; i++)
{
mrs[i] = meshTerrains[i].GetComponent<MeshRenderer>();
MeshFilter mf = meshTerrains[i].GetComponent<MeshFilter>();
meshTerrainComponents[i] = mf.sharedMesh;
}
}
public void CreateTerrainBounds()
{
terrainBounds = new Bounds[terrainComponents.Length];
for (int i = 0; i < terrainBounds.Length; i++)
{
terrainBounds[i] = new Bounds();
terrainBounds[i].min = terrains[i].position;
terrainBounds[i].max = terrainBounds[i].min + terrainComponents[i].terrainData.size;
}
meshBounds = new Bounds[meshTerrains.Count];
for (int i = 0; i < meshTerrains.Count; i++)
{
meshBounds[i] = mrs[i].bounds;
}
}
public void MakeIntersectLists(Bounds bounds)
{
List<Terrain> terrainList = new List<Terrain>();
List<Mesh> meshList = new List<Mesh>();
List<Bounds> terrainBoundsList = new List<Bounds>();
List<Bounds> meshBoundsList = new List<Bounds>();
Vector3[] pos = new Vector3[8];
Vector3 size = bounds.size;
pos[0] = bounds.min;
pos[1] = pos[0] + new Vector3(size.x, 0, 0);
pos[2] = pos[0] + new Vector3(0, 0, size.z);
pos[3] = pos[0] + new Vector3(size.x, 0, size.z);
pos[4] = pos[0] + new Vector3(0, size.y, 0);
pos[5] = pos[0] + new Vector3(size.x, size.y, 0);
pos[6] = pos[0] + new Vector3(0, size.y, size.z);
pos[7] = pos[0] + size;
for (int i = 0; i < 8; i++)
{
int index = InterectTerrain(pos[i]);
if (index != -1)
{
terrainList.Add(terrainArray[index]);
terrainBoundsList.Add(terrainBounds[index]);
}
index = InterectMesh(pos[i]);
if (index != -1)
{
meshList.Add(meshArray[index]);
meshBoundsList.Add(meshBounds[index]);
}
}
terrainArray = terrainList.ToArray();
meshArray = meshList.ToArray();
terrainBoundsArray = terrainBoundsList.ToArray();
// meshBoundsArray = meshBoundsList.ToArray();
}
public int InterectTerrain(Vector3 pos)
{
for (int i = 0; i < terrainBounds.Length; i++)
{
if (terrainBounds[i].Contains(pos)) return i;
}
return -1;
}
public int InterectMesh(Vector3 pos)
{
for (int i = 0; i < meshBounds.Length; i++)
{
if (meshBounds[i].Contains(pos)) return i;
}
return -1;
}
// Ray ray = new Ray(Vector3.zero, Vector3.down);
public float GetTerrainHeight(Vector3 pos)
{
int index = -1;
for (int i = 0; i < terrainArray.Length; i++)
{
if (terrainBoundsArray[i].Contains(pos)) { index = i; break; }
}
if (index != -1)
{
return terrainArray[index].SampleHeight(pos);
}
return Mathf.Infinity;
}
public void RemoveTriangles(Transform t, List<int> newTriangles, Vector3[] vertices)
{
bool[] verticeIsBelow = new bool[vertices.Length];
Vector3 pos = Vector3.zero;
float height = 0;
for (int j = 0; j < newTriangles.Count; j += 3)
{
++totalTriangles;
int verticeIndex = newTriangles[j];
bool isBelow = verticeIsBelow[verticeIndex];
if (!isBelow)
{
pos = t.TransformPoint(vertices[verticeIndex]);
height = GetTerrainHeight(pos);
isBelow = pos.y < height;
}
if (isBelow)
{
verticeIsBelow[verticeIndex] = true;
verticeIndex = newTriangles[j + 1];
isBelow = verticeIsBelow[verticeIndex];
if (!isBelow)
{
pos = t.TransformPoint(vertices[verticeIndex]);
height = GetTerrainHeight(pos);
isBelow = pos.y < height;
}
if (isBelow)
{
verticeIsBelow[verticeIndex] = true;
verticeIndex = newTriangles[j + 2];
isBelow = verticeIsBelow[verticeIndex];
if (!isBelow)
{
pos = t.TransformPoint(vertices[verticeIndex]);
height = GetTerrainHeight(pos);
isBelow = pos.y < height;
}
if (isBelow)
{
verticeIsBelow[verticeIndex] = true;
++removeTriangles;
newTriangles.RemoveAt(j + 2);
newTriangles.RemoveAt(j + 1);
newTriangles.RemoveAt(j);
if (j + 3 < newTriangles.Count) j -= 3;
}
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f47068a0804dcdf41a46c89f754480ed
timeCreated: 1496067184
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class SwapCombineKey : MonoBehaviour
{
static public SwapCombineKey instance;
public List<MeshCombiner> meshCombinerList = new List<MeshCombiner>();
MeshCombiner meshCombiner;
GUIStyle textStyle;
void Awake()
{
instance = this;
meshCombiner = GetComponent<MeshCombiner>();
meshCombinerList.Add(meshCombiner);
}
void OnDestroy()
{
instance = null;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
QualitySettings.vSyncCount = 0;
meshCombiner.SwapCombine();
}
}
private void OnGUI()
{
if (textStyle == null)
{
textStyle = new GUIStyle("label");
textStyle.fontStyle = FontStyle.Bold;
textStyle.fontSize = 16;
}
textStyle.normal.textColor = this.meshCombiner.combinedActive ? Color.green : Color.red;
GUI.Label(new Rect(10, 45 + (meshCombinerList.Count * 22), 200, 30), "Toggle with 'Tab' key.", textStyle);
for (int i = 0; i < meshCombinerList.Count; i++)
{
MeshCombiner meshCombiner = meshCombinerList[i];
if (meshCombiner.combinedActive) GUI.Label(new Rect(10, 30 + (i * 22), 300, 30), meshCombiner.gameObject.name + " is Enabled.", textStyle);
else GUI.Label(new Rect(10, 30 + (i * 22), 300, 30), meshCombiner.gameObject.name + " is Disabled.", textStyle);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3c430fd3101f200428cac71e6b69b0dc
timeCreated: 1505065196
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,372 @@
//using System.Collections;
//using System.Collections.Generic;
//using UnityEngine;
//using MeshCombineStudio;
//using System;
//namespace MeshCombineStudio
//{
// static public class Voxelize
// {
// static readonly byte[] bits = new byte[] { 1, 2, 4, 8, 16, 32, 64, 128 };
// static Dictionary<Mesh, VoxelizedMesh> voxelizedLookup = new Dictionary<Mesh, VoxelizedMesh>();
// static List<float> intersectList = new List<float>();
// const byte insideVoxel = 1;
// const byte outsideVoxel = 2;
// public class VoxelizedMesh
// {
// public byte[,,] volume;
// public Bounds bounds;
// public Int3 voxels;
// }
// static VoxelizedMesh VoxelizeMesh(Transform t, float voxelResolution, int voxelizeLayer)
// {
// // TODO ray cast from right/left and top/down
// MeshRenderer mr = t.GetComponent<MeshRenderer>();
// if (mr == null) return null;
// MeshFilter mf = t.GetComponent<MeshFilter>();
// if (mf == null) return null;
// Mesh mesh = mf.sharedMesh;
// if (mesh == null) return null;
// VoxelizedMesh vm = new VoxelizedMesh();
// voxelizedLookup.Add(mesh, vm);
// Transform oldParent = t.parent;
// Vector3 oldPos = t.position;
// Quaternion oldRot = t.rotation;
// Vector3 oldScale = t.localScale;
// t.parent = null;
// t.position = Vector3.zero;
// t.rotation = Quaternion.identity;
// t.localScale = Vector3.one;
// int oldLayer = t.gameObject.layer;
// t.gameObject.layer = voxelizeLayer;
// LayerMask voxelizeLayerMask = 1 << voxelizeLayer;
// Bounds bounds = mr.bounds;
// Vector3 size = bounds.size;
// Int3 voxels = new Int3(Mathf.CeilToInt(size.x / voxelResolution), Mathf.CeilToInt(size.y / voxelResolution), Mathf.CeilToInt(size.z / voxelResolution));
// voxels += new Int3(2, 2, 2);
// int voxelsX = Mathf.CeilToInt(voxels.x / 8f);
// vm.voxels = voxels;
// size = new Vector3(voxels.x * voxelResolution, voxels.y * voxelResolution, voxels.z * voxelResolution);
// bounds.size = size;
// vm.bounds = bounds;
// byte[,,] volume = new byte[voxelsX, voxels.y, voxels.z];
// Ray ray = new Ray();
// Ray ray2 = new Ray();
// ray.direction = Vector3.forward;
// ray2.direction = Vector3.back;
// Vector3 pos = bounds.min;
// Vector3 pos2 = pos;
// pos2.z = bounds.max.z;
// // Debug.Log(PrintVector3(mr.bounds.size) + " new size " + PrintVector3(size) + " voxels " + voxels);
// int voxelCount = 0;
// Vector3 halfVoxel = Vector3.one * voxelResolution * 0.5f;
// Vector3 minBoundsVoxel = pos + halfVoxel;
// try
// {
// for (int x = 0; x < voxels.x; x++)
// {
// int xGrid = x / 8;
// byte bit = bits[x - (xGrid * 8)];
// for (int y = 0; y < voxels.y; y++)
// {
// Vector3 origin = pos + new Vector3((x + 0.5f) * voxelResolution, (y + 0.5f) * voxelResolution, 0);
// ray.origin = origin;
// origin.z = pos2.z;
// ray2.origin = origin;
// intersectList.Clear();
// MultiCast(ray, intersectList, 0.001f, size.z, voxelizeLayerMask);
// MultiCast(ray2, intersectList, -0.001f, size.z, voxelizeLayerMask);
// intersectList.Sort();
// float half = (float)intersectList.Count / 2;
// if (half != (int)half) { continue; }
// // Debug.Log(hitInfos.Length +" " + hitInfos2.Length +" " + list.Count);
// for (int i = 0; i < intersectList.Count; i += 2)
// {
// int z1 = Mathf.RoundToInt((intersectList[i] - pos.z) / voxelResolution);
// int z2 = Mathf.RoundToInt((intersectList[i + 1] - pos.z) / voxelResolution);
// for (int z = z1; z < z2; z++)
// {
// Vector3 voxelPos = new Vector3(x * voxelResolution, y * voxelResolution, z * voxelResolution) + minBoundsVoxel;
// voxelPos = t.TransformPoint(voxelPos);
// // volume[xGrid, y, z] |= bit;
// // if (!Physics.CheckBox(voxelPos, halfVoxel, Quaternion.identity, voxelizeLayerMask))
// {
// volume[xGrid, y, z] |= bit;
// ++voxelCount;
// }
// }
// }
// }
// }
// }
// catch (Exception e)
// {
// Debug.LogError(e.ToString());
// }
// // Debug.Log(t.name + " voxels " + voxelCount);
// vm.volume = volume;
// t.gameObject.layer = oldLayer;
// t.parent = oldParent;
// t.position = oldPos;
// t.rotation = oldRot;
// t.localScale = oldScale;
// return vm;
// }
// static string PrintVector3(Vector3 v)
// {
// return "(" + v.x + ", " + v.y + ", " + v.z + ")";
// }
// static void MultiCast(Ray ray, List<float> points, float hitOffset, float maxDistance, LayerMask voxelizeLayerMask)
// {
// RaycastHit hitInfo;
// while (Physics.Raycast(ray, out hitInfo, maxDistance, voxelizeLayerMask))
// {
// points.Add(hitInfo.point.z);
// Vector3 origin = ray.origin;
// ray.origin = new Vector3(origin.x, origin.y, hitInfo.point.z + hitOffset);
// }
// }
// static void Report(VoxelizedMesh vm, float voxelResolution)
// {
// int voxelResolutionX = (int)voxelResolution / 8;
// for (int x = 0; x < voxelResolutionX; x++)
// {
// for (int y = 0; y < voxelResolution; y++)
// {
// for (int z = 0; z < voxelResolution; z++)
// {
// Debug.Log(vm.volume[x, y, z]);
// }
// }
// }
// }
// static public void RemoveOverlap(Transform t, MeshCombineJobManager.MeshCombineJob meshCombineJob, MeshCache.SubMeshCache newMeshCache, ref byte[] vertexIsInsideVoxels)
// {
// if (vertexIsInsideVoxels == null) vertexIsInsideVoxels = new byte[65534];
// float voxelResolution = meshCombineJob.meshCombiner.voxelResolution;
// int voxelizeLayer = meshCombineJob.meshCombiner.voxelizeLayer;
// Vector3[] newVertices = newMeshCache.vertices;
// int[] newTriangles = newMeshCache.triangles;
// List<MeshObject> meshObjects = meshCombineJob.meshObjectsHolder.meshObjects;
// int startIndex = meshCombineJob.startIndex;
// int endIndex = meshCombineJob.endIndex;
// for (int a = startIndex; a < endIndex; a++)
// {
// MeshObject meshObject = meshObjects[a];
// CachedGameObject cachedGO = meshObject.cachedGO;
// // Get array of intersections
// // Bounds bounds = cachedGO.mr.bounds;
// Collider[] colliders = null;//!! Physics.OverlapBox(bounds.center, bounds.extents, Quaternion.identity, meshCombineJob.meshCombiner.overlapLayerMask);
// if (colliders.Length == 0)
// {
// // Debug.Log("No overlap " + cachedGO.go.name);
// continue;
// }
// // Debug.Log("Overlaps " + colliders.Length);
// Transform[] colliderTs = new Transform[colliders.Length];
// VoxelizedMesh[] colliderVms = new VoxelizedMesh[colliders.Length];
// for (int i = 0; i < colliderVms.Length; i++)
// {
// colliderTs[i] = colliders[i].transform;
// if (colliderTs[i] == cachedGO.t) continue;
// MeshFilter mf = colliderTs[i].GetComponent<MeshFilter>();
// if (mf == null) continue;
// Mesh mesh = mf.sharedMesh;
// if (mesh == null) continue;
// voxelizedLookup.TryGetValue(mesh, out colliderVms[i]);
// if (colliderVms[i] == null) colliderVms[i] = VoxelizeMesh(colliderTs[i], voxelResolution, voxelizeLayer);
// // Debug.LogError("Couldn't find voxelized mesh for " + mo.m + " " + child.name);
// }
// float invVoxelResolution = 1 / voxelResolution;
// int startTriangleIndex = meshObject.startNewTriangleIndex;
// int endTriangleIndex = meshObject.newTriangleCount + startTriangleIndex;
// // Debug.Log("start " + startTriangleIndex + " end " + endTriangleIndex);
// for (int i = startTriangleIndex; i < endTriangleIndex; i += 3)
// {
// bool insideAllVoxels = true;
// for (int k = 0; k < 3; k++)
// {
// int vertexIndex = newTriangles[i + k];
// if (vertexIndex == -1) continue;
// byte isInsideVoxel = vertexIsInsideVoxels[vertexIndex];
// if (isInsideVoxel == 0)
// {
// bool inside = false;
// for (int j = 0; j < colliders.Length; j++)
// {
// Transform colliderT = colliderTs[j];
// VoxelizedMesh colliderVm = colliderVms[j];
// if (colliderVm == null) continue;
// Vector3 boundsMin = colliderVm.bounds.min;
// Vector3 vertPos = t.TransformPoint(newVertices[vertexIndex]);
// Vector3 pos = colliderT.InverseTransformPoint(vertPos) - boundsMin;
// Vector3 grid = new Vector3(pos.x * invVoxelResolution, pos.y * invVoxelResolution, pos.z * invVoxelResolution);
// if (grid.x < 0 || grid.x >= colliderVm.voxels.x || grid.y < 0 || grid.y >= colliderVm.voxels.y || grid.z < 0 || grid.z >= colliderVm.voxels.z) continue;
// int xGrid = (int)grid.x;
// int xxGrid = xGrid / 8;
// byte bit = bits[(xGrid - (xxGrid * 8))];
// if ((colliderVm.volume[xxGrid, (int)grid.y, (int)grid.z] & bit) == 0) continue;
// inside = true;
// break;
// }
// vertexIsInsideVoxels[vertexIndex] = isInsideVoxel = (inside ? insideVoxel : outsideVoxel);
// }
// if (isInsideVoxel == outsideVoxel)
// {
// insideAllVoxels = false;
// break;
// }
// }
// if (insideAllVoxels)
// {
// meshCombineJob.trianglesRemoved += 3;
// newTriangles[i] = -1;
// }
// }
// }
// Array.Clear(vertexIsInsideVoxels, 0, newMeshCache.vertexCount);
// // Debug.Log("Removed " + meshCombineJob.trianglesRemoved);
// newMeshCache.triangles = newTriangles;
// }
// static public void DrawGizmos(GameObject go, float voxelResolution)
// {
// Transform[] ts = go.GetComponentsInChildren<Transform>();
// Gizmos.color = Color.red;
// for (int i = 0; i < ts.Length; i++) DrawVolume(ts[i], voxelResolution);
// Gizmos.color = Color.white;
// }
// static public void DrawVolume(Transform t, float voxelResolution)
// {
// MeshRenderer mr = t.GetComponent<MeshRenderer>();
// if (mr == null) return;
// MeshFilter mf = t.GetComponent<MeshFilter>();
// if (mf == null) return;
// Mesh m = mf.sharedMesh;
// if (m == null) return;
// VoxelizedMesh vm;
// voxelizedLookup.TryGetValue(m, out vm);
// if (vm == null) return;
// byte[,,] volume = vm.volume;
// if (volume == null) return;
// Vector3 pos = vm.bounds.min;
// Vector3 voxel = t.lossyScale * voxelResolution;
// Vector3 halfVoxel = Vector3.one * voxelResolution * 0.5f;
// Int3 voxels = vm.voxels;
// // Debug.Log(voxels);
// // Debug.Log(volume.Length);
// Gizmos.DrawWireCube(mr.bounds.center, mr.bounds.size);
// for (int x = 0; x < voxels.x; x++)
// {
// int xGrid = x / 8;
// int bit = x - (xGrid * 8);
// for (int y = 0; y < voxels.y; y++)
// {
// for (int z = 0; z < voxels.z; z++)
// {
// if ((volume[xGrid, y, z] & bits[bit]) > 0)
// {
// Vector3 localPos = new Vector3(pos.x + (x * voxelResolution), pos.y + (y * voxelResolution), pos.z + (z * voxelResolution)) + halfVoxel;
// Gizmos.DrawWireCube(t.TransformPoint(localPos), voxel);
// }
// }
// }
// }
// }
// }
//}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1abfeedba8fba6241b5632cfa2ad5222
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b676c661f38fdf340b7858cbb7dcce53
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class CachedComponents : MonoBehaviour
{
public GameObject go;
public Transform t;
public MeshRenderer mr;
public MeshFilter mf;
public GarbageCollectMesh garbageCollectMesh;
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 03afcff0c1e9bee4f8c9e97428da7b81
timeCreated: 1508479768
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,733 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class Console : MonoBehaviour
{
static public Console instance;
public KeyCode consoleKey = KeyCode.F1;
public bool logActive = true;
public bool showConsole;
public bool showOnError;
public bool combineAutomatic = true;
bool showLast = true;
bool setFocus;
GameObject selectGO;
public List<LogEntry> logs = new List<LogEntry>();
Rect window, inputRect = new Rect(), logRect = new Rect(), vScrollRect = new Rect();
string inputText;
float scrollPos = 0;
int lines = 20;
bool showUnityLog = true, showInputLog = true;
MeshCombiner[] meshCombiners;
MeshCombiner selectedMeshCombiner;
void Awake()
{
instance = this;
FindMeshCombiners();
window = new Rect();
inputText = string.Empty;
ReportStartup();
}
void ReportStartup()
{
Log("---------------------------------");
Log("*** MeshCombineStudio Console ***");
Log("---------------------------------");
Log("");
ReportMeshCombiners(false);
Log("combine automatic " + (combineAutomatic ? "on" : "off"));
if (meshCombiners != null && meshCombiners.Length > 0) SelectMeshCombiner(meshCombiners[0].name);
Log("");
Log("Type '?' to show commands");
// ExecuteCommand("?");
}
void FindMeshCombiners()
{
meshCombiners = GameObject.FindObjectsOfType<MeshCombiner>();
}
void ReportMeshCombiners(bool reportSelected = true)
{
for (int i = 0; i < meshCombiners.Length; i++) ReportMeshCombiner(meshCombiners[i], true);
if (selectedMeshCombiner != null)
{
Log("Selected MCS -> " + selectedMeshCombiner.name);
}
}
void ReportMeshCombiner(MeshCombiner meshCombiner, bool foundText = false)
{
Log((foundText ? "Found MCS -> " : "") + meshCombiner.name + " (" + (meshCombiner.combined ? "*color-green#Combined" : "*color-blue#Uncombined" ) + ")" + " -> Cell Size " + meshCombiner.cellSize + (meshCombiner.searchOptions.useMaxBoundsFactor ? " | Max Bounds Factor " + meshCombiner.searchOptions.maxBoundsFactor : "")
+ (meshCombiner.searchOptions.useVertexInputLimit ? " | Vertex Input Limit " + (meshCombiner.searchOptions.useVertexInputLimit ? meshCombiner.searchOptions.vertexInputLimit : 65534) : ""),
0, null, meshCombiner);
}
public int SelectMeshCombiner(string name)
{
if (meshCombiners == null && meshCombiners.Length == 0) return 0;
for (int i = 0; i < meshCombiners.Length; i++)
{
MeshCombiner meshCombiner = meshCombiners[i];
if (meshCombiner.name == name)
{
Log("Selected MCS -> " + meshCombiner.name + " (" + (meshCombiner.combined ? "*color-green#Combined" : "*color-blue#Uncombined") + ")", 0, null, meshCombiner);
selectedMeshCombiner = meshCombiner; return 2;
}
}
return 0;
}
private void OnEnable()
{
Application.logMessageReceived += HandleLog;
}
private void OnDisable()
{
Application.logMessageReceived -= HandleLog;
}
private void OnDestroy()
{
instance = null;
}
static public void Log(string logString, int commandType = 0, GameObject go = null, MeshCombiner meshCombiner = null)
{
instance.logs.Add(new LogEntry(logString, "", LogType.Log, false, commandType, go, meshCombiner));
}
void HandleLog(string logString, string stackTrace, LogType logType)
{
if (logActive)
{
logs.Add(new LogEntry(logString, stackTrace, logType, true));
if (showOnError && (logType == LogType.Error || logType == LogType.Warning))
{
SetConsoleActive(true);
showLast = true;
showUnityLog = true;
}
}
}
void Update()
{
if (Input.GetKeyDown(consoleKey))
{
SetConsoleActive(!showConsole);
}
}
void SetConsoleActive(bool active)
{
showConsole = active;
if (showConsole)
{
setFocus = true;
}
}
void ExecuteCommand(string cmd)
{
logs.Add(new LogEntry(cmd, "", LogType.Log, false, 1));
LogEntry log = logs[logs.Count - 1];
if (cmd == "?")
{
Log("'F1' to show/hide console");
Log("'dir', 'dirAll', 'dirSort', 'cd', 'show', 'showAll', 'hide', 'hideAll'");
Log("'components', 'lines', 'clear', 'gc collect'");
Log("'select (MeshCombineStudio name)', ");
Log("'report MeshCombineStudio'");
Log("'combine', 'uncombine', 'combine automatic on/off'");
Log("'max bounds factor (float)/off'");
Log("'vertex input limit (float)/off'");
Log("'vertex input limit lod (float)/off'");
Log("'cell size (float)'");
log.commandType = 2;
}
else if (cmd == "gc collect")
{
System.GC.Collect();
log.commandType = 2;
}
else if (cmd == "dir") { Dir(); log.commandType = 2; }
else if (cmd == "components") { Components(log); }
else if (cmd.Contains("lines "))
{
int.TryParse(cmd.Replace("lines ", ""), out lines);
lines = Mathf.Clamp(lines, 5, 50);
log.commandType = 2;
}
else if (cmd == "cd..") { CD(log, ".."); }
else if (cmd == "cd\\") { CD(log, "\\"); }
else if (cmd.Contains("cd ")) { CD(log, cmd.Replace("cd ", "")); }
else if (cmd.Contains("show "))
{
Transform t = Methods.Find<Transform>(selectGO, cmd.Replace("show ", ""));
if (t != null) { t.gameObject.SetActive(true); log.commandType = 2; }
}
else if (cmd == "show")
{
if (selectGO != null) { selectGO.SetActive(true); log.commandType = 2; }
}
else if (cmd.Contains("showAll "))
{
SetActiveContains(cmd.Replace("showAll ", ""), true);
log.commandType = 2;
}
else if (cmd.Contains("hide "))
{
GameObject go = GameObject.Find(cmd.Replace("hide ", ""));
if (go != null) { go.SetActive(false); log.commandType = 2; }
}
else if (cmd.Contains("hideAll "))
{
SetActiveContains(cmd.Replace("hideAll ", ""), false);
log.commandType = 2;
}
else if (cmd == "hide")
{
if (selectGO != null) { selectGO.SetActive(false); log.commandType = 2; }
}
else if (cmd.Contains("clear")) { Clear(log, cmd.Replace("clear ", "")); }
else if (cmd.Contains("dir ")) { DirContains(cmd.Replace("dir ", "")); log.commandType = 2; }
else if (cmd == "dirAll") { DirAll(); log.commandType = 2; }
else if (cmd.Contains("dirSort ")) { DirSort(cmd.Replace("dirSort ", "")); log.commandType = 2; }
else if (cmd == "dirSort") { DirSort(); log.commandType = 2; }
else if (cmd.Contains("cell size "))
{
int cellSize;
int.TryParse(cmd.Replace("cell size ", ""), out cellSize);
if (cellSize < 4)
{
Log("cell size should be bigger than 4");
return;
}
if (selectedMeshCombiner != null)
{
selectedMeshCombiner.cellSize = cellSize;
selectedMeshCombiner.AddObjectsAutomatically();
if (combineAutomatic) selectedMeshCombiner.CombineAll();
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
else if (cmd == "report MeshCombineStudio")
{
ReportMeshCombiners();
log.commandType = 2;
}
else if (cmd == "combine")
{
if (selectedMeshCombiner != null)
{
selectedMeshCombiner.octreeContainsObjects = false;
selectedMeshCombiner.CombineAll();
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
else if (cmd == "uncombine")
{
if (selectedMeshCombiner != null)
{
selectedMeshCombiner.DestroyCombinedObjects();
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
else if (cmd == "combine automatic off")
{
combineAutomatic = false;
log.commandType = 2;
}
else if (cmd == "combine automatic on")
{
combineAutomatic = true;
log.commandType = 2;
}
else if (cmd.Contains("select "))
{
if (SelectMeshCombiner(cmd.Replace("select ", "")) == 2)
{
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
else if (cmd == "max bounds factor off")
{
if (selectedMeshCombiner != null)
{
selectedMeshCombiner.searchOptions.useMaxBoundsFactor = false;
selectedMeshCombiner.AddObjectsAutomatically();
if (combineAutomatic) selectedMeshCombiner.CombineAll();
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
else if (cmd.Contains("max bounds factor "))
{
float maxBoundsFactor;
float.TryParse(cmd.Replace("max bounds factor ", ""), out maxBoundsFactor);
if (maxBoundsFactor < 1)
{
Log("max bounds factor needs to be bigger than 1");
return;
}
if (selectedMeshCombiner != null)
{
selectedMeshCombiner.searchOptions.useMaxBoundsFactor = true;
selectedMeshCombiner.searchOptions.maxBoundsFactor = maxBoundsFactor;
selectedMeshCombiner.AddObjectsAutomatically();
if (combineAutomatic) selectedMeshCombiner.CombineAll();
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
else if (cmd == "vertex input limit off")
{
if (selectedMeshCombiner != null)
{
selectedMeshCombiner.searchOptions.useVertexInputLimit = false;
selectedMeshCombiner.AddObjectsAutomatically();
if (combineAutomatic) selectedMeshCombiner.CombineAll();
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
else if (cmd.Contains("vertex input limit "))
{
int vertexInputLimit;
int.TryParse(cmd.Replace("vertex input limit ", ""), out vertexInputLimit);
if (vertexInputLimit < 1)
{
Log("vertex input limit needs to be bigger than 1");
return;
}
if (selectedMeshCombiner != null)
{
selectedMeshCombiner.searchOptions.useVertexInputLimit = true;
selectedMeshCombiner.searchOptions.vertexInputLimit = vertexInputLimit;
selectedMeshCombiner.AddObjectsAutomatically();
if (combineAutomatic) selectedMeshCombiner.CombineAll();
ReportMeshCombiner(selectedMeshCombiner);
log.commandType = 2;
}
}
}
void DirSort()
{
GameObject[] gos = Methods.Search<GameObject>(selectGO);
SortLog(gos, true);
}
void DirSort(string name)
{
GameObject[] gos = Methods.Search<GameObject>();
List<GameObject> sortedGos = new List<GameObject>();
for (int i = 0; i < gos.Length; i++)
{
if (Methods.Contains(gos[i].name, name)) sortedGos.Add(gos[i]);
}
SortLog(sortedGos.ToArray());
}
public void SortLog(GameObject[] gos, bool showMeshInfo = false)
{
List<GameObject> list = new List<GameObject>();
List<int> amountList = new List<int>();
int count = 0;
int meshCount = 0;
for (int i = 0; i < gos.Length; i++)
{
GameObject go = gos[i];
GetMeshInfo(go, ref meshCount);
string name = go.name;
int index = -1;
for (int j = 0; j < list.Count; j++)
{
if (list[j].name == name) { index = j; break; }
}
if (index == -1)
{
list.Add(go);
amountList.Add(1);
count++;
}
else
{
amountList[index]++;
count++;
}
}
int temp = 0;
for (int i = 0; i < list.Count; i++)
{
string text = list[i].name + " -> " + amountList[i] + " " + GetMeshInfo(list[i], ref temp);
Log(text);
}
Log("Total amount " + count + " Total items " + list.Count + " Total shared meshes " + meshCount);
}
string GetMeshInfo(GameObject go, ref int meshCount)
{
MeshFilter mf = go.GetComponent<MeshFilter>();
if (mf != null)
{
Mesh m = mf.sharedMesh;
if (m != null)
{
++meshCount;
return "(vertices " + m.vertexCount + ", combine " + Mathf.FloorToInt(65000 / m.vertexCount) + ")";
}
}
return "";
}
void TimeStep(string cmd)
{
float time;
float.TryParse(cmd, out time);
Time.fixedDeltaTime = time;
}
void TimeScale(string cmd)
{
float time;
float.TryParse(cmd, out time);
Time.timeScale = time;
}
void Clear(LogEntry log, string cmd)
{
if (cmd == "clear") { logs.Clear(); log.commandType = 2; }
else if (cmd == "input")
{
for (int i = 0; i < logs.Count; i++)
{
if (!logs[i].unityLog) logs.RemoveAt(i--);
}
log.commandType = 2;
}
else if (cmd == "unity")
{
for (int i = 0; i < logs.Count; i++)
{
if (logs[i].unityLog) logs.RemoveAt(i--);
}
log.commandType = 2;
}
}
void DirAll()
{
GameObject[] gos = Methods.Search<GameObject>(selectGO);
int meshCount = 0;
for (int i = 0; i < gos.Length; i++) Log(GetPath(gos[i]) + "\\" + gos[i].transform.childCount + " " + GetMeshInfo(gos[i], ref meshCount), 0, gos[i]);
Log(gos.Length + " (meshes " + meshCount + ")\\..");
}
void Dir()
{
int meshCount = 0;
if (selectGO == null)
{
#if !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2
GameObject[] gos = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
for (int i = 0; i < gos.Length; i++) Log(gos[i].name + "\\" + gos[i].transform.childCount + " " + GetMeshInfo(gos[i], ref meshCount), 0, gos[i]);
Log(gos.Length + " (meshes " + meshCount + ")\\..");
#endif
}
else
{
ShowPath();
Transform selectT = selectGO.transform;
for (int i = 0; i < selectT.childCount; i++)
{
Transform child = selectT.GetChild(i);
Log(child.name + "\\" + child.childCount + " " + GetMeshInfo(child.gameObject, ref meshCount), 0, child.gameObject);
}
Log(selectT.childCount + " (meshes " + meshCount + ")\\..");
}
}
void Components(LogEntry log)
{
if (selectGO == null) { log.commandType = 1; return; }
Component[] components = selectGO.GetComponents<Component>();
ShowPath(true);
for (int i = 0; i < components.Length; i++)
{
if (components[i] != null) Log(components[i].GetType().Name);
}
log.commandType = 2;
}
void ShowPath(bool showLines = true)
{
string path = GetPath(selectGO);
if (path != "") Log(path); else Log("Root\\");
if (showLines) Log("---------------------------------");
}
string GetPath(GameObject go)
{
if (go != null)
{
string path = go.name;
Transform t = go.transform;
while (t.parent != null)
{
path = path.Insert(0, t.parent.name + "\\");
t = t.parent;
}
return path;
}
return "";
}
void CD(LogEntry log, string name)
{
if (name == "..")
{
if (selectGO != null)
{
if (selectGO.transform.parent != null) selectGO = selectGO.transform.parent.gameObject;
else selectGO = null;
log.commandType = 2;
ShowPath(false);
return;
}
}
else if (name == "\\") { selectGO = null; log.commandType = 2; return; }
Transform t = Methods.Find<Transform>(selectGO, name);
if (t != null)
{
selectGO = t.gameObject;
ShowPath(false);
log.commandType = 2;
}
}
public void SetActiveContains(string textContains, bool active)
{
GameObject[] gos = Methods.Search<GameObject>(selectGO);
int count = 0;
for (int i = 0; i < gos.Length; i++)
{
if (Methods.Contains(gos[i].name, textContains))
{
// we shouldn't hide GUI elements :)
if (gos[i].transform.parent.name.IndexOf("GUI") == 0 || gos[i].transform.parent.parent == null || gos[i].transform.parent.parent.name.IndexOf("GUI") == 0)
{
gos[i].SetActive(active);
++count;
}
}
}
Log("Total amount set to " + active + " : " + count);
}
public void DirContains(string textContains)
{
GameObject[] gos = Methods.Search<GameObject>(selectGO);
int count = 0;
for (int i = 0; i < gos.Length; i++)
{
if (Methods.Contains(gos[i].name, textContains)) { Log(gos[i].name, 0, gos[i]); ++count; }
}
Log("Total amount: " + count);
}
private void OnGUI()
{
if (!showConsole) return;
window.x = 225;
window.y = 5;
window.yMax = (lines * 20) + 30;
window.xMax = Screen.width - (window.x);
GUI.Box(window, "Console");
inputRect.x = window.x + 5;
inputRect.y = window.yMax - 25;
inputRect.xMax = window.xMax - 10;
inputRect.yMax = window.yMax - 5;
if (showInputLog)
{
if (GUI.GetNameOfFocusedControl() == "ConsoleInput")
{
if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
{
showLast = true;
ExecuteCommand(inputText);
inputText = string.Empty;
}
}
GUI.SetNextControlName("ConsoleInput");
GUI.changed = false;
inputText = GUI.TextField(inputRect, inputText);
if (GUI.changed)
{
if (inputText.Contains("`"))
{
inputText = inputText.Replace("`", "");
SetConsoleActive(!showConsole);
}
}
if (setFocus)
{
setFocus = false;
GUI.FocusControl("ConsoleInput");
}
}
if (showInputLog) GUI.color = Color.green; else GUI.color = Color.grey;
if (GUI.Button(new Rect(window.xMin + 5, window.yMin + 5, 75, 20), "Input Log"))
{
showInputLog = !showInputLog;
}
if (showUnityLog) GUI.color = Color.green; else GUI.color = Color.grey;
if (GUI.Button(new Rect(window.xMin + 85, window.yMin + 5, 75, 20), "Unity Log"))
{
showUnityLog = !showUnityLog;
}
GUI.color = Color.white;
if (!showInputLog && !showUnityLog) showInputLog = true;
logRect.x = window.x + 5;
logRect.y = window.y + 25;
logRect.xMax = window.xMax - 20;
logRect.yMax = logRect.y + 20;
vScrollRect.x = window.xMax - 15;
vScrollRect.y = logRect.y;
vScrollRect.xMax = window.xMax - 5;
vScrollRect.yMax = window.yMax - 45;
float size = Mathf.Ceil(vScrollRect.height / 20);
if (showLast && Event.current.type != EventType.Repaint) scrollPos = logs.Count;
GUI.changed = false;
scrollPos = GUI.VerticalScrollbar(vScrollRect, scrollPos, size > logs.Count - 1 ? logs.Count - 1 : size - 1, 0, logs.Count - 1);
if (GUI.changed)
{
showLast = false;
}
int start = (int)scrollPos;
if (start < 0) start = 0;
int end = start + (int)size;
if (end > logs.Count) end = logs.Count;
int amount = end - start;
int i = start;
int index = 0;
while (index != amount && i < logs.Count)
{
LogEntry log = logs[i];
if ((log.unityLog && showUnityLog) || (!log.unityLog && showInputLog))
{
if (log.logType == LogType.Warning) AnimateColor(Color.yellow, log, 0.75f);
else if (log.logType == LogType.Error) AnimateColor(Color.red, log, 0.75f);
else if (log.logType == LogType.Exception) AnimateColor(Color.magenta, log, 0.75f);
else if (log.unityLog) AnimateColor(Color.white, log, 0.75f);
else if (log.commandType == 1) GUI.color = new Color(0, 0.5f, 0);
else if (log.commandType == 2) GUI.color = Color.green;
else if (log.go != null) GUI.color = log.go.activeSelf ? Color.white : Color.white * 0.7f;
string text = log.logString;
if (text.Contains("*color-"))
{
if (text.Contains("*color-green#")) { text = text.Replace("*color-green#", ""); GUI.color = Color.green; }
else if (text.Contains("*color-blue#")) { text = text.Replace("*color-blue#", ""); GUI.color = Color.blue; }
}
GUI.Label(logRect, i + ") ");
logRect.xMin += 55;
GUI.Label(logRect, text + ((log.stackTrace != "") ? (" (" + log.stackTrace + ")") : ""));
logRect.xMin -= 55;
GUI.color = Color.white;
logRect.y += 20;
index++;
}
++i;
}
}
void AnimateColor(Color col, LogEntry log, float multi)
{
GUI.color = Color.Lerp(col * multi, col, Mathf.Abs(Mathf.Sin(Time.time)));
}
public class LogEntry
{
public string logString;
public string stackTrace;
public LogType logType;
public int commandType;
public bool unityLog;
public float tStamp;
public GameObject go;
public MeshCombiner meshCombiner;
public LogEntry(string logString, string stackTrace, LogType logType, bool unityLog = false, int commandType = 0, GameObject go = null, MeshCombiner meshCombiner = null)
{
this.logString = logString;
this.stackTrace = stackTrace;
this.logType = logType;
this.unityLog = unityLog;
this.commandType = commandType;
this.go = go;
this.meshCombiner = meshCombiner;
// tStamp = Time.time;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 866d6feafa7767a4cb2fcc19a7e5814c
timeCreated: 1509385662
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class DirectDraw : MonoBehaviour
{
MeshRenderer[] mrs;
Mesh[] meshes;
Material[] mats;
Vector3[] positions;
Quaternion[] rotations;
private void Awake()
{
mrs = GetComponentsInChildren<MeshRenderer>(false);
SetMeshRenderersEnabled(false);
meshes = new Mesh[mrs.Length];
mats = new Material[mrs.Length];
positions = new Vector3[mrs.Length];
rotations = new Quaternion[mrs.Length];
for (int i = 0; i < mrs.Length; i++)
{
MeshFilter mf = mrs[i].GetComponent<MeshFilter>();
meshes[i] = mf.sharedMesh;
mats[i] = mrs[i].sharedMaterial;
positions[i] = mrs[i].transform.position;
rotations[i] = mrs[i].transform.rotation;
}
}
void SetMeshRenderersEnabled(bool enabled)
{
for (int i = 0; i < mrs.Length; i++) mrs[i].enabled = enabled;
}
private void Update()
{
for (int i = 0; i < mrs.Length; i++)
{
Graphics.DrawMesh(meshes[i], positions[i], rotations[i], mats[i], 0);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fe3ead8849c569942bd92549d4b8b33b
timeCreated: 1504681663
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class DisabledLodMeshRender : MonoBehaviour
{
[HideInInspector] public MeshCombiner meshCombiner;
public CachedLodGameObject cachedLodGO;
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 543503b98c01a314fb4d57359cf83933
timeCreated: 1510253824
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class DisabledMeshRenderer : MonoBehaviour
{
[HideInInspector] public MeshCombiner meshCombiner;
public CachedGameObject cachedGO;
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1cc7efff353789c46a358e329b54fac1
timeCreated: 1510254104
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class EnableChildrenMeshRenderers : MonoBehaviour
{
public bool execute;
void Update()
{
if (execute)
{
execute = false;
Execute();
}
}
void Execute()
{
var mrs = GetComponentsInChildren<MeshRenderer>();
foreach (var mr in mrs) mr.enabled = true;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4730eb4026f3f184da3245e99672aa8a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,481 @@
using System;
using System.Runtime.CompilerServices;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class FastListBase
{
protected const int defaultCapacity = 4;
public int Count;
protected int _count;
protected int arraySize;
}
public class FastListBase<T> : FastListBase
{
public T[] items;
//public T this[int index]
//{
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// get { return items[index]; }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// set { items[index] = value; }
//}
protected void DoubleCapacity()
{
arraySize *= 2;
T[] newItems = new T[arraySize];
Array.Copy(items, newItems, _count);
items = newItems;
}
}
[Serializable]
public class FastList<T> : FastListBase<T>
{
// static readonly T[] emptyArray = new T[0];
// Constructors
//=========================================================================================================================================*********
//=========================================================================================================================================*********
public FastList()
{
items = new T[defaultCapacity];
arraySize = defaultCapacity;
}
public FastList(bool reserve, int reserved)
{
int capacity = Mathf.Max(reserved, defaultCapacity);
items = new T[capacity];
arraySize = capacity;
Count = _count = reserved;
}
public FastList(int capacity)
{
if (capacity < 1) capacity = 1;
items = new T[capacity];
arraySize = capacity;
// Debug.Log(items.Length);
}
public FastList(FastList<T> list)
{
if (list == null)
{
items = new T[defaultCapacity];
arraySize = defaultCapacity;
return;
}
items = new T[list.Count];
Array.Copy(list.items, items, list.Count);
arraySize = items.Length;
Count = _count = items.Length;
}
public FastList(T[] items)
{
this.items = items;
_count = Count = arraySize = items.Length;
}
//=========================================================================================================================================*********
//=========================================================================================================================================*********
protected void SetCapacity(int capacity)
{
arraySize = capacity;
T[] newItems = new T[arraySize];
if (_count > 0) Array.Copy(items, newItems, _count);
items = newItems;
}
public void SetCount(int count)
{
if (count > arraySize) SetCapacity(count);
Count = _count = count;
}
public void EnsureCount(int count)
{
if (count <= _count) return;
if (count > arraySize) SetCapacity(count);
Count = _count = count;
}
public virtual void SetArray(T[] items)
{
this.items = items;
_count = Count = arraySize = items.Length;
}
public int AddUnique(T item)
{
if (!Contains(item)) return Add(item);
return -1;
}
public bool Contains(T item)
{
return Array.IndexOf(items, item, 0, _count) != -1;
}
public int IndexOf(T item)
{
return Array.IndexOf(items, item, 0, _count);
}
public T GetIndex(T item)
{
int index = Array.IndexOf(items, item, 0, _count);
if (index == -1) return default(T); else return items[index];
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual int Add(T item)
{
if (_count == arraySize) DoubleCapacity();
items[_count] = item;
Count = ++_count;
return _count - 1;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual int AddThreadSafe(T item)
{
lock (this)
{
if (_count == arraySize) DoubleCapacity();
items[_count] = item;
Count = ++_count;
return _count - 1;
}
}
public virtual void Add(T item, T item2)
{
if (_count + 1 >= arraySize) DoubleCapacity();
items[_count++] = item;
items[_count++] = item2;
Count = _count;
}
public virtual void Add(T item, T item2, T item3)
{
if (_count + 2 >= arraySize) DoubleCapacity();
items[_count++] = item;
items[_count++] = item2;
items[_count++] = item3;
Count = _count;
}
public virtual void Add(T item, T item2, T item3, T item4)
{
if (_count + 3 >= arraySize) DoubleCapacity();
items[_count++] = item;
items[_count++] = item2;
items[_count++] = item3;
items[_count++] = item4;
Count = _count;
}
public virtual void Add(T item, T item2, T item3, T item4, T item5)
{
if (_count + 4 >= arraySize) DoubleCapacity();
items[_count++] = item;
items[_count++] = item2;
items[_count++] = item3;
items[_count++] = item4;
items[_count++] = item5;
Count = _count;
}
public virtual void Insert(int index, T item)
{
if (index > _count) { Debug.LogError("Index " + index + " is out of range " + _count); }
if (_count == arraySize) DoubleCapacity();
if (index < _count) Array.Copy(items, index, items, index + 1, _count - index);
items[index] = item;
Count = ++_count;
}
public virtual void AddRange(T[] arrayItems)
{
if (arrayItems == null) return;
int length = arrayItems.Length;
int newCount = _count + length;
if (newCount >= arraySize) SetCapacity(newCount * 2);
Array.Copy(arrayItems, 0, items, _count, length);
Count = _count = newCount;
}
public virtual void AddRange(T[] arrayItems, int startIndex, int length)
{
int newCount = _count + length;
if (newCount >= arraySize) SetCapacity(newCount * 2);
Array.Copy(arrayItems, startIndex, items, _count, length);
Count = _count = newCount;
}
public virtual void AddRange(FastList<T> list)
{
if (list.Count == 0) return;
int newCount = _count + list.Count;
if (newCount >= arraySize) SetCapacity(newCount * 2);
Array.Copy(list.items, 0, items, _count, list.Count);
Count = _count = newCount;
}
public virtual int GrabListThreadSafe(FastList<T> threadList, bool fastClear = false)
{
lock (threadList)
{
int count = _count;
AddRange(threadList);
if (fastClear) threadList.FastClear(); else threadList.Clear();
return count;
}
}
//public void AddRange(T item, int amount)
//{
// int newCount = _count + amount;
// if (newCount >= arraySize) SetCapacity(newCount * 2);
// for (int i = 0; i < amount; i++) items[_count++] = item;
// Count = _count;
//}
public virtual void ChangeRange(int startIndex, T[] arrayItems)
{
for (int i = 0; i < arrayItems.Length; i++)
{
items[startIndex + i] = arrayItems[i];
}
}
// Slow
public virtual bool Remove(T item, bool weakReference = false)
{
int index = Array.IndexOf(items, item, 0, _count);
if (index >= 0)
{
items[index] = items[--_count];
items[_count] = default(T);
Count = _count;
return true;
}
return false;
}
public virtual void RemoveAt(int index)
{
if (index >= _count) { Debug.LogError("Index " + index + " is out of range. List count is " + _count); return; }
items[index] = items[--_count];
items[_count] = default(T);
Count = _count;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void RemoveLast()
{
if (_count == 0) return;
--_count;
items[_count] = default(T);
Count = _count;
}
//public void RemoveRange(int startIndex, int length)
//{
// if (startIndex + length > _count) { Debug.LogError("StartIndex " + startIndex + " Length " + length + " is out of range. List count is " + _count); return; }
// int minIndex = startIndex + length;
// int copyIndex = _count - length;
// if (copyIndex < minIndex) copyIndex = minIndex;
// int length2 = _count - copyIndex;
// int index = startIndex;
// // Debug.Log("CopyIndex " + copyIndex + " length2 " + length2 + " rest " + (length - length2));
// for (int i = 0; i < length2; i++)
// {
// if (items[index] == null) { Debug.LogError(" item list " + (index) + " is null! List count " + _count); }
// items[index] = items[copyIndex + i];
// items[copyIndex + i] = default(T);
// --_count;
// }
// length -= length2;
// for (int i = 0; i < length; i++)
// {
// items[index++] = default(T);
// --_count;
// }
// Count = _count;
//}
public virtual void RemoveRange(int index, int length)
{
if (_count - index < length)
{
Debug.LogError("Invalid length!");
}
if (length > 0)
{
_count -= length;
if (index < _count)
{
Array.Copy(items, index + length, items, index, _count - index);
}
Array.Clear(items, _count, length);
Count = _count;
}
}
public virtual T Dequeue()
{
if (_count == 0)
{
Debug.LogError("List is empty!");
return default(T);
}
T item = items[--_count];
items[_count] = default(T);
Count = _count;
return item;
}
public virtual T Dequeue(int index)
{
T item = items[index];
items[index] = items[--_count];
items[_count] = default(T);
Count = _count;
return item;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void Clear()
{
Array.Clear(items, 0, _count);
Count = _count = 0;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void ClearThreadSafe()
{
lock (this)
{
Array.Clear(items, 0, _count);
Count = _count = 0;
}
}
public virtual void ClearRange(int startIndex)
{
Array.Clear(items, startIndex, _count - startIndex);
Count = _count = startIndex;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void FastClear()
{
Count = _count = 0;
}
public virtual void FastClear(int newCount)
{
if (newCount < Count)
{
Count = _count = newCount;
}
}
public virtual T[] ToArray()
{
T[] array = new T[_count];
Array.Copy(items, 0, array, 0, _count);
return array;
}
}
[Serializable]
public class SortedFastList<T> : FastList<T>
{
new public void RemoveAt(int index)
{
if (index >= _count) { Debug.LogError("Index " + index + " is out of range " + _count); }
_count--;
if (index < _count) Array.Copy(items, index + 1, items, index, _count - index);
items[_count] = default(T);
Count = _count;
}
new public void RemoveRange(int index, int endIndex)
{
int length = (endIndex - index) + 1;
if (index < 0)
{
Debug.LogError("Index needs to be bigger than 0 -> " + index);
return;
}
if (length < 0)
{
Debug.LogError("Length needs to be bigger than 0 -> " + length);
return;
}
if (_count - index < length)
{
return;
}
_count -= length;
if (index < _count)
{
Array.Copy(items, index + length, items, index, _count - index);
}
Array.Clear(items, _count, length);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1b551b40363254e4d834daa4f6baac9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
[ExecuteInEditMode]
public class GarbageCollectMesh : MonoBehaviour
{
public Mesh mesh;
void OnDestroy()
{
if (mesh != null)
{
#if UNITY_EDITOR
DestroyImmediate(mesh);
#else
Destroy(mesh);
#endif
}
// Debug.Log("Destroy Mesh");
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 585afa5e7b5db2c42986fb8e6960e8d7
timeCreated: 1497467774
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,75 @@
using UnityEngine;
using System.Collections;
namespace MeshCombineStudio
{
public class MCS_CameraController : MonoBehaviour {
public float speed = 10;
public float mouseMoveSpeed = 1;
public float shiftMulti = 3f;
public float controlMulti = 0.5f;
Vector3 oldMousePosition;
GameObject cameraMountGO, cameraChildGO;
Transform cameraMountT, cameraChildT, t;
private void Awake()
{
t = transform;
CreateParents();
}
void CreateParents()
{
cameraMountGO = new GameObject("CameraMount");
cameraChildGO = new GameObject("CameraChild");
cameraMountT = cameraMountGO.transform;
cameraChildT = cameraChildGO.transform;
cameraChildT.SetParent(cameraMountT);
cameraMountT.position = t.position;
cameraMountT.rotation = t.rotation;
t.SetParent(cameraChildT);
}
private void Update()
{
Vector3 deltaMouse = (Input.mousePosition - oldMousePosition) * mouseMoveSpeed * (Time.deltaTime * 60);
if (Input.GetMouseButton(1))
{
cameraMountT.Rotate(0, deltaMouse.x, 0, Space.Self);
cameraChildT.Rotate(-deltaMouse.y, 0, 0, Space.Self);
}
oldMousePosition = Input.mousePosition;
Vector3 move = Vector3.zero;
if (Input.GetKey(KeyCode.W)) move.z = speed;
else if (Input.GetKey(KeyCode.S)) move.z = -speed;
else if (Input.GetKey(KeyCode.A)) move.x = -speed;
else if (Input.GetKey(KeyCode.D)) move.x = speed;
else if (Input.GetKey(KeyCode.Q)) move.y = -speed;
else if (Input.GetKey(KeyCode.E)) move.y = speed;
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) move *= shiftMulti;
else if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) move *= controlMulti;
move *= Time.deltaTime * 60;
Quaternion rotation = Quaternion.identity;
rotation.eulerAngles = new Vector3(cameraChildT.eulerAngles.x, cameraMountT.eulerAngles.y, 0);
move = rotation * move;
// move = cameraMountT.rotation * move;
cameraMountT.position += move;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 378152e1b020e6d4987908966ef4833e
timeCreated: 1505372378
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,305 @@
using UnityEngine;
namespace MeshCombineStudio
{
public class MCS_FPSCounter : MonoBehaviour
{
static public MCS_FPSCounter instance;
[Header("___ Settings ___________________________________________________________________________________________________________")]
public float interval = 0.25f;
public enum GUIType { DisplayRunning, DisplayResults, DisplayNothing }
public GUIType displayType = GUIType.DisplayRunning;
public Vector2 gradientRange = new Vector2(15, 60);
public Font fontRun;
public Font fontResult;
public Texture logo;
public bool showLogoOnResultsScreen = true;
public KeyCode showHideButton = KeyCode.Backspace;
public bool acceptInput = true;
public bool reset;
[Header("___ Results ___________________________________________________________________________________________________________")]
public float currentFPS = 0;
public float averageFPS = 0;
public float minimumFPS = 0;
public float maximumFPS = 0;
// Privates
int totalFrameCount, tempFrameCount;
double tStamp, tStampTemp;
// GUI-------------------------------------------
string currentFPSText, avgFPSText, minFPSText, maxFSPText;
GUIStyle bigStyle = new GUIStyle(); GUIStyle bigStyleShadow;
GUIStyle smallStyle = new GUIStyle(); GUIStyle smallStyleShadow; GUIStyle smallStyleLabel;
GUIStyle headerStyle = new GUIStyle();
Rect[] rectsRun = { new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect() };
Rect[] rectsResult = { new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect(), new Rect() };
Gradient gradient = new Gradient();
const float line1 = 4;
const float line2 = line1 + 26;
const float line3 = line2 + 14;
const float line4 = line3 + 14;
const float labelWidth = 26;
const float paddingH = 8;
const float lineHeight = 22;
float columnRight;
float columnLeft;
Color fontShadow = new Color(0, 0, 0, 0.5f);
Color label = new Color(0.8f, 0.8f, 0.8f, 1);
Color colorCurrent, colorAvg;
const string resultHeader = "BENCHMARK RESULTS";
const string resultLabelAvg = "AVERAGE FPS:";
const string resultLabelMin = "MINIMUM FPS:";
const string resultLabelMax = "MAXIMUM FPS:";
GUIContent resultHeaderGUI = new GUIContent(resultHeader);
GUIContent reslutLabelAvgGUI = new GUIContent(resultLabelAvg);
GUIContent avgTextGUI = new GUIContent();
GUIContent instructions = new GUIContent("PRESS SPACEBAR TO RERUN BENCHMARK | PRESS ESCAPE TO RETURN TO MENU");
const string runLabelAvg = "Avg:";
const string runLabelMin = "Min:";
const string runLabelMax = "Max:";
Vector2 screenSize = new Vector2(0, 0);
GUIType oldDisplayType = GUIType.DisplayNothing;
//-----------------------------------------------
private void Awake()
{
instance = this;
gradient.colorKeys = new GradientColorKey[] { new GradientColorKey(new Color(1, 0, 0, 1), 0), new GradientColorKey(new Color(1, 1, 0, 1), 0.5f), new GradientColorKey(new Color(0, 1, 0, 1), 1f) };
}
void OnDestroy() { if (instance == this) instance = null; }
void OnGUI()
{
if (displayType == GUIType.DisplayNothing) return;
else if (displayType == GUIType.DisplayRunning)
{
if (Screen.width != screenSize.x || Screen.height != screenSize.y) { screenSize.x = Screen.width; screenSize.y = Screen.height; SetRectsRun(); }
// TEXT DROPSHADOWS ----------------------------------------------------------
GUI.Label(rectsRun[0], currentFPSText, bigStyleShadow); // Result Current FPS
GUI.Label(rectsRun[1], avgFPSText, smallStyleShadow); // Result Average FPS
GUI.Label(rectsRun[2], minFPSText, smallStyleShadow); // ReSult Minimum FPS
GUI.Label(rectsRun[3], maxFSPText, smallStyleShadow); // Result Maximum FPS
GUI.Label(rectsRun[4], runLabelAvg, smallStyleShadow); // Label Average FPS
GUI.Label(rectsRun[5], runLabelMin, smallStyleShadow); // Label Minimum FPS
GUI.Label(rectsRun[6], runLabelMax, smallStyleShadow); // Label Maximum FPS
// TEXT ----------------------------------------------------------------------
GUI.Label(rectsRun[7], currentFPSText, bigStyle); // Result Current FPS
GUI.Label(rectsRun[8], avgFPSText, smallStyle); // Result Average FPS
GUI.Label(rectsRun[9], minFPSText, smallStyle); // ReSult Minimum FPS
GUI.Label(rectsRun[10], maxFSPText, smallStyle); // Result Maximum FPS
GUI.Label(rectsRun[11], runLabelAvg, smallStyleLabel); // Label Average FPS
GUI.Label(rectsRun[12], runLabelMin, smallStyleLabel); // Label Minimum FPS
GUI.Label(rectsRun[13], runLabelMax, smallStyleLabel); // Label Maximum FPS
}
else
{
if (Screen.width != screenSize.x || Screen.height != screenSize.y) { screenSize.x = Screen.width; screenSize.y = Screen.height; SetRectsResult(); }
if (showLogoOnResultsScreen) GUI.DrawTexture(rectsResult[8], logo);
GUI.Label(rectsResult[0], resultHeaderGUI, headerStyle); // Header
GUI.DrawTexture(rectsResult[1], Texture2D.whiteTexture); // Line
GUI.Label(rectsResult[2], reslutLabelAvgGUI, smallStyle); // Label Average FPS
GUI.Label(rectsResult[4], resultLabelMin, smallStyleLabel); // Label Minimum FPS
GUI.Label(rectsResult[6], resultLabelMax, smallStyleLabel); // Label Maximum FPS
GUI.Label(rectsResult[3], avgTextGUI, bigStyle); // Result Average FPS
GUI.Label(rectsResult[5], minFPSText, smallStyle); // ReSult Minimum FPS
GUI.Label(rectsResult[7], maxFSPText, smallStyle); // Result Maximum FPS
GUI.Label(rectsResult[9], instructions, smallStyleLabel); // Instructions
}
} //==============================================================================================================
void SetRectsRun()
{
columnRight = Screen.width - (labelWidth + paddingH);
columnLeft = columnRight - (labelWidth + paddingH);
// float editorOffset = Screen.height * 0.09f;
float editorOffset = 0;
// TEXT DROPSHADOWS ----------------------------------------------------------
rectsRun[0].Set(Screen.width - (40 + paddingH) + 1, editorOffset + line1 + 2, 40, lineHeight); // Result Current FPS
rectsRun[1].Set(columnRight + 1, editorOffset + line2 + 2, labelWidth, lineHeight); // Result Average FPS
rectsRun[2].Set(columnRight + 1, editorOffset + line3 + 2, labelWidth, lineHeight); // ReSult Minimum FPS
rectsRun[3].Set(columnRight + 1, editorOffset + line4 + 2, labelWidth, lineHeight); // Result Maximum FPS
rectsRun[4].Set(columnLeft + 1, editorOffset + line2 + 2, labelWidth, lineHeight); // Label Average FPS
rectsRun[5].Set(columnLeft + 1, editorOffset + line3 + 2, labelWidth, lineHeight); // Label Minimum FPS
rectsRun[6].Set(columnLeft + 1, editorOffset + line4 + 2, labelWidth, lineHeight); // Label Maximum FPS
// TEXT ----------------------------------------------------------------------
rectsRun[7].Set(Screen.width - (45 + paddingH), editorOffset + line1, 45, lineHeight); // Result Current FPS
rectsRun[8].Set(columnRight, editorOffset + line2, labelWidth, lineHeight); // Result Average FPS
rectsRun[9].Set(columnRight, editorOffset + line3, labelWidth, lineHeight); // ReSult Minimum FPS
rectsRun[10].Set(columnRight, editorOffset + line4, labelWidth, lineHeight); // Result Maximum FPS
rectsRun[11].Set(columnLeft, editorOffset + line2, labelWidth, lineHeight); // Label Average FPS
rectsRun[12].Set(columnLeft, editorOffset + line3, labelWidth, lineHeight); // Label Minimum FPS
rectsRun[13].Set(columnLeft, editorOffset + line4, labelWidth, lineHeight); // Result Maximum FPS
} //==============================================================================================================
void SetRectsResult()
{
float totalHeight = 512 / 2;
rectsResult[8].Set((Screen.width / 2) - (logo.width / 2), (Screen.height / 2) - totalHeight, logo.width, logo.height); // Drone Logo
Vector2 size = headerStyle.CalcSize(resultHeaderGUI);
rectsResult[0].Set((Screen.width / 2) - (size.x / 2), (Screen.height / 2) - (totalHeight - 256), size.x, size.y); // Header
size.x += 10;
rectsResult[1].Set((Screen.width / 2) - (size.x / 2), (Screen.height / 2) - (totalHeight - 256 - 30), size.x, 1); // Line
rectsResult[2].Set((Screen.width / 2) - 200, (Screen.height / 2) - (totalHeight - 256 - 30 - 30), 200, 24); // Label Average FPS
rectsResult[4].Set((Screen.width / 2) - 200, (Screen.height / 2) - (totalHeight - 256 - 30 - 30 - 20), 200, 24); // Label Minimum FPS
rectsResult[6].Set((Screen.width / 2) - 200, (Screen.height / 2) - (totalHeight - 256 - 30 - 30 - 20 - 20), 200, 24); // Label Maximum FPS
rectsResult[3].Set((Screen.width / 2), (Screen.height / 2) - (totalHeight - 256 - 30 - 18), 65, 24); // Result Average FPS
rectsResult[5].Set((Screen.width / 2), (Screen.height / 2) - (totalHeight - 256 - 30 - 30 - 20), 65, 24); // ReSult Minimum FPS
rectsResult[7].Set((Screen.width / 2), (Screen.height / 2) - (totalHeight - 256 - 30 - 30 - 20 - 20), 65, 24); // Result Maximum FPS
size = smallStyleLabel.CalcSize(instructions);
rectsResult[9].Set((Screen.width / 2) - (size.x / 2), (Screen.height / 2) - (totalHeight - 256 - 30 - 30 - 20 - 20 - 40), size.x, size.y); // Instructions
} //==============================================================================================================
void Start()
{
headerStyle.normal.textColor = label;
headerStyle.fontSize = 24;
headerStyle.font = fontResult;
headerStyle.alignment = TextAnchor.UpperCenter;
bigStyle.alignment = TextAnchor.UpperRight;
bigStyle.font = fontRun;
bigStyle.fontSize = 24;
bigStyle.normal.textColor = Color.green;
bigStyleShadow = new GUIStyle(bigStyle);
bigStyleShadow.normal.textColor = fontShadow;
smallStyle.alignment = TextAnchor.UpperRight;
smallStyle.font = fontRun;
smallStyle.fontSize = 12;
smallStyle.normal.textColor = Color.white;
smallStyleShadow = new GUIStyle(smallStyle);
smallStyleShadow.normal.textColor = fontShadow;
smallStyleLabel = new GUIStyle(smallStyle);
smallStyleLabel.normal.textColor = label;
Invoke("Reset", 0.5f);
} //==============================================================================================================
void Update()
{
if (displayType != oldDisplayType)
{
if (displayType == GUIType.DisplayResults)
{
SetRectsResult();
colorAvg = EvaluateGradient(averageFPS);
bigStyle.normal.textColor = colorAvg;
avgTextGUI.text = avgFPSText;
}
else if (displayType == GUIType.DisplayRunning)
{
Reset();
SetRectsRun();
}
oldDisplayType = displayType;
}
if (Input.GetKeyDown(showHideButton) && acceptInput && displayType != GUIType.DisplayResults)
{
if (displayType == GUIType.DisplayNothing) displayType = GUIType.DisplayRunning;
else displayType = GUIType.DisplayNothing;
}
if (displayType == GUIType.DisplayNothing) return;
else if (displayType == GUIType.DisplayRunning) GetFPS();
if (reset) { reset = false; Reset(); }
} //==============================================================================================================
public void StartBenchmark()
{
Reset();
SetRectsRun();
displayType = GUIType.DisplayRunning;
} //==============================================================================================================
public void StopBenchmark()
{
SetRectsResult();
displayType = GUIType.DisplayResults;
colorAvg = EvaluateGradient(averageFPS);
bigStyle.normal.textColor = colorAvg;
//R_Console.Log("---------------------------------");
//R_Console.Log("Average FPS: " + averageFPS.ToString("F2"));
//R_Console.Log("Mininum FPS: " + minimumFPS.ToString("F2"));
//R_Console.Log("Maximum FPS: " + maximumFPS.ToString("F2"));
//R_Console.Log("---------------------------------");
} //==============================================================================================================
void GetFPS()
{
tempFrameCount++;
totalFrameCount++;
if (Time.realtimeSinceStartup - tStampTemp > interval)
{
currentFPS = (float)(tempFrameCount / (Time.realtimeSinceStartup - tStampTemp));
averageFPS = (float)(totalFrameCount / (Time.realtimeSinceStartup - tStamp));
if (currentFPS < minimumFPS) minimumFPS = currentFPS;
if (currentFPS > maximumFPS) maximumFPS = currentFPS;
tStampTemp = Time.realtimeSinceStartup;
tempFrameCount = 0;
currentFPSText = "FPS " + currentFPS.ToString("0.0");
avgFPSText = averageFPS.ToString("0.0");
minFPSText = minimumFPS.ToString("0.0");
maxFSPText = maximumFPS.ToString("0.0");
colorCurrent = EvaluateGradient(currentFPS);
bigStyle.normal.textColor = colorCurrent;
}
} //==============================================================================================================
public void Reset()
{
tStamp = Time.realtimeSinceStartup;
tStampTemp = Time.realtimeSinceStartup;
currentFPS = 0;
averageFPS = 0;
minimumFPS = 999.9f;
maximumFPS = 0;
tempFrameCount = 0;
totalFrameCount = 0;
} //==============================================================================================================
Color EvaluateGradient(float f) { return gradient.Evaluate(Mathf.Clamp01((f - gradientRange.x) / (gradientRange.y - gradientRange.x))); }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4e83c49ade708374995107d7992d0c66
timeCreated: 1510142056
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,407 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.CompilerServices;
namespace MeshCombineStudio
{
public struct AABB3
{
public Vector3 min;
public Vector3 max;
public AABB3(Vector3 min, Vector3 max)
{
this.min = min;
this.max = max;
}
}
public struct Triangle3
{
public Vector3 a, b, c;
public Vector3 dirAb, dirAc, dirBc;
public Vector3 h1;
public float ab, ac, bc;
public float area, h, ah, hb;
public void Calc()
{
var _a = a;
var _b = b;
var _c = c;
var _dirAb = b - a;
var _dirAc = c - a;
var _dirBc = c - b;
float _ab = _dirAb.magnitude;
float _ac = _dirAc.magnitude;
float _bc = _dirBc.magnitude;
if (_ac > _ab && _ac > _bc)
{
a = _a;
b = _c;
c = _b;
}
else if (_bc > _ab)
{
a = _c;
b = _b;
c = _a;
}
dirAb = b - a;
dirAc = c - a;
dirBc = c - b;
ab = dirAb.magnitude;
ac = dirAc.magnitude;
bc = dirBc.magnitude;
float s = (ab + ac + bc) * 0.5f;
area = Mathf.Sqrt(s * (s - ab) * (s - ac) * (s - bc));
h = (2 * area) / ab;
ah = Mathf.Sqrt((ac * ac) - (h * h));
hb = ab - ah;
// Debug.Log("ab " + ab + " ac " + ac + " bc " + bc + " area " + area + " h " + h + " ah " + ah);
h1 = a + (dirAb * ((1 / ab) * ah));
}
}
public struct Sphere3
{
public Vector3 center;
public float radius;
public Sphere3(Vector3 center, float radius)
{
this.center = center;
this.radius = radius;
}
}
public struct Int2
{
public int x, y;
public Int2(int x, int y)
{
this.x = x;
this.y = y;
}
}
public struct Int3
{
public int x, y, z;
public Int3(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public static Int3 operator +(Int3 a, Int3 b)
{
return a + b;
}
}
static public class Mathw
{
static public readonly int[] bits = new int[] { 1 << 0 , 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7, 1 << 8, 1 << 9, 1 << 10, 1 << 11, 1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16, 1 << 17,
1 << 18, 1 << 19, 1 << 20, 1 << 21, 1 << 22, 1 << 23, 1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29, 1 << 30, 1 << 31};
static public Vector3 Clamp(Vector3 v, float min, float max)
{
if (v.x < min) v.x = min;
else if (v.x > max) v.x = max;
if (v.y < min) v.y = min;
else if (v.y > max) v.y = max;
if (v.z < min) v.z = min;
else if (v.z > max) v.z = max;
return v;
}
static public Vector3 FloatToVector3(float v)
{
return new Vector3(v, v, v);
}
static public float SinDeg(float angle)
{
return Mathf.Sin(angle * Mathf.Deg2Rad);// * Mathf.Rad2Deg;
}
static public float GetMax(Vector3 v)
{
float max = v.x;
if (v.y > max) max = v.y;
if (v.z > max) max = v.z;
return max;
}
static public Vector3 SetMin(Vector3 v, float min)
{
if (v.x < min) v.x = min;
if (v.y < min) v.y = min;
if (v.z < min) v.z = min;
return v;
}
static public Vector3 Snap(Vector3 v, float snapSize)
{
v.x = Mathf.Floor(v.x / snapSize) * snapSize;
v.y = Mathf.Floor(v.y / snapSize) * snapSize;
v.z = Mathf.Floor(v.z / snapSize) * snapSize;
return v;
}
static public Vector3 Abs(Vector3 v)
{
return new Vector3(v.x < 0 ? -v.x : v.x, v.y < 0 ? -v.y : v.y, v.z < 0 ? -v.z : v.z);
}
static public bool IntersectAABB3Sphere3(AABB3 box, Sphere3 sphere)
{
Vector3 center = sphere.center;
Vector3 min = box.min;
Vector3 max = box.max;
float totalDistance = 0f;
float distance;
if (center.x < min.x)
{
distance = center.x - min.x;
totalDistance += distance * distance;
}
else if (center.x > max.x)
{
distance = center.x - max.x;
totalDistance += distance * distance;
}
if (center.y < min.y)
{
distance = center.y - min.y;
totalDistance += distance * distance;
}
else if (center.y > max.y)
{
distance = center.y - max.y;
totalDistance += distance * distance;
}
if (center.z < min.z)
{
distance = center.z - min.z;
totalDistance += distance * distance;
}
else if (center.z > max.z)
{
distance = center.z - max.z;
totalDistance += distance * distance;
}
return totalDistance <= sphere.radius * sphere.radius;
}
static public bool IntersectAABB3Triangle3(Vector3 boxCenter, Vector3 boxHalfSize, Triangle3 triangle)
{
Vector3 v0, v1, v2;
float min, max, fex, fey, fez;
Vector3 normal, e0, e1, e2;
v0 = triangle.a - boxCenter;
v1 = triangle.b - boxCenter;
v2 = triangle.c - boxCenter;
e0 = v1 - v0;
e1 = v2 - v1;
e2 = v0 - v2;
fex = Abs(e0[0]);
fey = Abs(e0[1]);
fez = Abs(e0[2]);
if (!AxisTest_X01(v0, v2, boxHalfSize, e0[2], e0[1], fez, fey, out min, out max)) return false;
if (!AxisTest_Y02(v0, v2, boxHalfSize, e0[2], e0[0], fez, fex, out min, out max)) return false;
if (!AxisTest_Z12(v1, v2, boxHalfSize, e0[1], e0[0], fey, fex, out min, out max)) return false;
fex = Abs(e1[0]);
fey = Abs(e1[1]);
fez = Abs(e1[2]);
if (!AxisTest_X01(v0, v2, boxHalfSize, e1[2], e1[1], fez, fey, out min, out max)) return false;
if (!AxisTest_Y02(v0, v2, boxHalfSize, e1[2], e1[0], fez, fex, out min, out max)) return false;
if (!AxisTest_Z0(v0, v1, boxHalfSize, e1[1], e1[0], fey, fex, out min, out max)) return false;
fex = Abs(e2[0]);
fey = Abs(e2[1]);
fez = Abs(e2[2]);
if (!AxisTest_X2(v0, v1, boxHalfSize, e2[2], e2[1], fez, fey, out min, out max)) return false;
if (!AxisTest_Y1(v0, v1, boxHalfSize, e2[2], e2[0], fez, fex, out min, out max)) return false;
if (!AxisTest_Z12(v1, v2, boxHalfSize, e2[1], e2[0], fey, fex, out min, out max)) return false;
GetMinMax(v0[0], v1[0], v2[0], out min, out max);
if (min > boxHalfSize[0] || max < -boxHalfSize[0]) return false;
GetMinMax(v0[1], v1[1], v2[1], out min, out max);
if (min > boxHalfSize[1] || max < -boxHalfSize[1]) return false;
GetMinMax(v0[2], v1[2], v2[2], out min, out max);
if (min > boxHalfSize[2] || max < -boxHalfSize[2]) return false;
normal = Vector3.Cross(e0, e1);
if (!PlaneBoxOverlap(normal, v0, boxHalfSize)) return false;
return true;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static void GetMinMax(float x0, float x1, float x2, out float min, out float max)
{
min = max = x0;
if (x1 < min) min = x1;
else if (x1 > max) max = x1;
if (x2 < min) min = x2;
else if (x2 > max) max = x2;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool PlaneBoxOverlap(Vector3 normal, Vector3 vert, Vector3 maxBox)
{
float v;
Vector3 vmin = Vector3.zero, vmax = Vector3.zero;
for (int i = 0; i <= 2; i++)
{
v = vert[i];
if (normal[i] > 0.0f)
{
vmin[i] = -maxBox[i] - v;
vmax[i] = maxBox[i] - v;
}
else
{
vmin[i] = maxBox[i] - v;
vmax[i] = -maxBox[i] - v;
}
}
if (Vector3.Dot(normal, vmin) > 0.0f) return false;
if (Vector3.Dot(normal, vmax) >= 0.0f) return true;
return false;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static float Abs(float v)
{
return v < 0 ? -v : v;
}
/*======================== X-tests ========================*/
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool AxisTest_X01(Vector3 v0, Vector3 v2, Vector3 boxHalfSize, float a, float b, float fa, float fb, out float min, out float max)
{
float p0 = a * v0[1] - b * v0[2];
float p2 = a * v2[1] - b * v2[2];
if (p0 < p2) { min = p0; max = p2; } else { min = p2; max = p0; }
float rad = fa * boxHalfSize[1] + fb * boxHalfSize[2];
if (min > rad || max < -rad) return false;
return true;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool AxisTest_X2(Vector3 v0, Vector3 v1, Vector3 boxHalfSize, float a, float b, float fa, float fb, out float min, out float max)
{
float p0 = a * v0[1] - b * v0[2];
float p1 = a * v1[1] - b * v1[2];
if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; }
float rad = fa * boxHalfSize[1] + fb * boxHalfSize[2];
if (min > rad || max < -rad) return false;
return true;
}
/*======================== Y-tests ========================*/
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool AxisTest_Y02(Vector3 v0, Vector3 v2, Vector3 boxHalfSize, float a, float b, float fa, float fb, out float min, out float max)
{
float p0 = -a * v0[0] + b * v0[2];
float p2 = -a * v2[0] + b * v2[2];
if (p0 < p2) { min = p0; max = p2; } else { min = p2; max = p0; }
float rad = fa * boxHalfSize[0] + fb * boxHalfSize[2];
if (min > rad || max < -rad) return false;
return true;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool AxisTest_Y1(Vector3 v0, Vector3 v1, Vector3 boxHalfSize, float a, float b, float fa, float fb, out float min, out float max)
{
float p0 = -a * v0[0] + b * v0[2];
float p1 = -a * v1[0] + b * v1[2];
if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; }
float rad = fa * boxHalfSize[0] + fb * boxHalfSize[2];
if (min > rad || max < -rad) return false;
return true;
}
/*======================== Z-tests ========================*/
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool AxisTest_Z12(Vector3 v1, Vector3 v2, Vector3 boxHalfSize, float a, float b, float fa, float fb, out float min, out float max)
{
float p1 = a * v1[0] - b * v1[1];
float p2 = a * v2[0] - b * v2[1];
if (p2 < p1) { min = p2; max = p1; } else { min = p1; max = p2; }
float rad = fa * boxHalfSize[0] + fb * boxHalfSize[1];
if (min > rad || max < -rad) return false;
return true;
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool AxisTest_Z0(Vector3 v0, Vector3 v1, Vector3 boxHalfSize, float a, float b, float fa, float fb, out float min, out float max)
{
float p0 = a * v0[0] - b * v0[1];
float p1 = a * v1[0] - b * v1[1];
if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; }
float rad = fa * boxHalfSize[0] + fb * boxHalfSize[1];
if (min > rad || max < -rad) return false;
return true;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b7bc54856b835184b846778cd1be4c6c
timeCreated: 1497466510
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,285 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;
namespace MeshCombineStudio
{
static public class Methods
{
static public void SetTag(GameObject go, string tag)
{
Transform[] tArray = go.GetComponentsInChildren<Transform>();
for (int i = 0; i < tArray.Length; i++) { tArray[i].tag = tag; }
}
static public void SetTagWhenCollider(GameObject go, string tag)
{
Transform[] tArray = go.GetComponentsInChildren<Transform>();
for (int i = 0; i < tArray.Length; i++)
{
if (tArray[i].GetComponent<Collider>() != null) tArray[i].tag = tag;
}
}
static public void SetTagAndLayer(GameObject go, string tag, int layer)
{
// Debug.Log("Layer " + layer);
Transform[] tArray = go.GetComponentsInChildren<Transform>();
for (int i = 0; i < tArray.Length; i++) { tArray[i].tag = tag; tArray[i].gameObject.layer = layer; }
}
static public void SetLayer(GameObject go, int layer)
{
go.layer = layer;
Transform[] tArray = go.GetComponentsInChildren<Transform>();
for (int i = 0; i < tArray.Length; i++) tArray[i].gameObject.layer = layer;
}
static public bool LayerMaskContainsLayer(int layerMask, int layer)
{
return ((1 << layer) & layerMask) != 0;
}
static public int GetFirstLayerInLayerMask(int layerMask)
{
for (int i = 0; i < 32; i++)
{
if ((layerMask & Mathw.bits[i]) != 0) return i;
}
return -1;
}
static public bool Contains(string compare, string name)
{
List<string> cuts = new List<string>();
int index;
do
{
index = name.IndexOf("*");
if (index != -1)
{
if (index != 0) { cuts.Add(name.Substring(0, index)); }
if (index != name.Length - 1) { name = name.Substring(index + 1); }
else break;
}
}
while (index != -1);
cuts.Add(name);
for (int i = 0; i < cuts.Count; i++)
{
//Debug.Log(cuts.items[i] +" " + compare);
if (!compare.Contains(cuts[i])) return false;
}
//Debug.Log("Passed");
return true;
}
static public T[] Search<T>(GameObject parentGO = null)
{
GameObject[] gos = null;
if (parentGO == null) {
#if !UNITY_5_1 && !UNITY_5_2
gos = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
#endif
}
else gos = new GameObject[] { parentGO };
if (gos == null) return null;
if (typeof(T) == typeof(GameObject))
{
List<GameObject> list = new List<GameObject>();
for (int i = 0; i < gos.Length; i++)
{
Transform[] transforms = gos[i].GetComponentsInChildren<Transform>(true);
for (int j = 0; j < transforms.Length; j++) list.Add(transforms[j].gameObject);
}
return list.ToArray() as T[];
}
else
{
if (parentGO == null)
{
List<T> list = new List<T>();
for (int i = 0; i < gos.Length; i++)
{
list.AddRange(gos[i].GetComponentsInChildren<T>(true));
}
return list.ToArray();
}
else return parentGO.GetComponentsInChildren<T>(true);
}
}
#if !UNITY_5
static public FastList<GameObject> GetAllRootGameObjects()
{
FastList<GameObject> list = new FastList<GameObject>();
for (int i = 0; i < UnityEngine.SceneManagement.SceneManager.sceneCount; i++)
{
list.AddRange(UnityEngine.SceneManagement.SceneManager.GetSceneAt(i).GetRootGameObjects());
}
return list;
}
#endif
static public T[] SearchParent<T>(GameObject parentGO, bool searchInActiveGameObjects) where T : Component
{
if (parentGO == null) return SearchAllScenes<T>(searchInActiveGameObjects).ToArray();
if (!searchInActiveGameObjects && !parentGO.activeInHierarchy) return null;
if (typeof(T) == typeof(GameObject))
{
var ts = parentGO.GetComponentsInChildren<Transform>(searchInActiveGameObjects);
GameObject[] gos = new GameObject[ts.Length];
for (int i = 0; i < gos.Length; i++) gos[i] = ts[i].gameObject;
return gos as T[];
}
return parentGO.GetComponentsInChildren<T>(searchInActiveGameObjects);
}
#if !UNITY_5
static public T[] SearchScene<T>(UnityEngine.SceneManagement.Scene scene, bool searchInActiveGameObjects) where T : Component
{
var gos = scene.GetRootGameObjects();
var list = new FastList<T>();
foreach (var go in gos) list.AddRange(SearchParent<T>(go, searchInActiveGameObjects));
return list.ToArray();
}
#endif
static public FastList<T> SearchAllScenes<T>(bool searchInActiveGameObjects) where T : Component
{
var list = new FastList<T>();
#if !UNITY_5
FastList<GameObject> gos = GetAllRootGameObjects();
for (int i = 0; i < gos.Count; i++)
{
var result = SearchParent<T>(gos.items[i], searchInActiveGameObjects);
list.AddRange(result);
}
#else
list.items = GameObject.FindObjectsOfType<T>();
list.SetCount(list.items.Length);
if (!searchInActiveGameObjects)
{
for (int i = 0; i < list.Count; i++)
{
if (!list.items[i].gameObject.activeInHierarchy) list.RemoveAt(i--);
}
}
#endif
return list;
}
static public T Find<T>(GameObject parentGO, string name) where T : UnityEngine.Component
{
T[] gos = SearchParent<T>(parentGO, true);
for (int i = 0; i < gos.Length; i++)
{
if (gos[i].name == name) return gos[i];
}
return null;
}
static public void SetCollidersActive(Collider[] colliders, bool active, string[] nameList)
{
for (int i = 0; i < colliders.Length; i++)
{
for (int j = 0; j < nameList.Length; j++)
{
if (colliders[i].name.Contains(nameList[j])) colliders[i].enabled = active;
}
}
}
static public void SelectChildrenWithMeshRenderer(Transform t)
{
#if UNITY_EDITOR
MeshRenderer[] mrs = t.GetComponentsInChildren<MeshRenderer>();
GameObject[] gos = new GameObject[mrs.Length];
for (int i = 0; i < mrs.Length; i++) gos[i] = mrs[i].gameObject;
UnityEditor.Selection.objects = gos;
#endif
}
static public void DestroyChildren(Transform t)
{
while (t.childCount > 0)
{
Transform child = t.GetChild(0);
child.parent = null;
GameObject.DestroyImmediate(child.gameObject);
}
}
static public void Destroy(GameObject go)
{
if (go == null) return;
#if UNITY_EDITOR
GameObject.DestroyImmediate(go);
#else
GameObject.Destroy(go);
#endif
}
static public void SetChildrenActive(Transform t, bool active)
{
for (int i = 0; i < t.childCount; i++)
{
Transform child = t.GetChild(i);
child.gameObject.SetActive(active);
}
}
static public void SnapBoundsAndPreserveArea(ref Bounds bounds, float snapSize, Vector3 offset)
{
Vector3 newCenter = Mathw.Snap(bounds.center, snapSize) + offset;
bounds.size += Mathw.Abs(newCenter - bounds.center) * 2;
bounds.center = newCenter;
}
static public void ListRemoveAt<T>(List<T> list, int index)
{
list[index] = list[list.Count - 1];
list.RemoveAt(list.Count - 1);
}
static public void CopyComponent(Component component, GameObject target)
{
Type type = component.GetType();
target.AddComponent(type);
PropertyInfo[] propInfo = type.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
foreach (var property in propInfo)
{
property.SetValue(target.GetComponent(type), property.GetValue(component, null), null);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d68ccf92729e6604aa5673d5d42a77cf
timeCreated: 1494490213
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using UnityEngine;
using System.Collections;
namespace MeshCombineStudio
{
public class ReadMe : MonoBehaviour {
public bool buttonEdit;
public string readme;
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: eac827fa24e617e478912ae0761ce9f5
timeCreated: 1511099101
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace MeshCombineStudio
{
static public class TriangleAAB3
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7a11984188c2c8048b2e0ee040857025
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f108ac526b27b644387ec1ac932eb9a6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,128 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace MeshCombineStudio
{
public class BaseOctree
{
public class Cell
{
public Cell mainParent;
public Cell parent;
// public Cell[] cells;
public bool[] cellsUsed;
public Bounds bounds;
public int cellIndex;
public int cellCount;
public int level = 0;
public int maxLevels;
public Cell() { }
public Cell(Vector3 position, Vector3 size, int maxLevels)
{
bounds = new Bounds(position, size);
this.maxLevels = maxLevels;
}
public Cell(Cell parent, int cellIndex, Bounds bounds)
{
if (parent != null)
{
maxLevels = parent.maxLevels;
mainParent = parent.mainParent;
level = parent.level + 1;
}
this.parent = parent;
this.cellIndex = cellIndex;
this.bounds = bounds;
}
public void SetCell(Cell parent, int cellIndex, Bounds bounds)
{
if (parent != null)
{
maxLevels = parent.maxLevels;
mainParent = parent.mainParent;
level = parent.level + 1;
}
this.parent = parent;
this.cellIndex = cellIndex;
this.bounds = bounds;
}
protected int AddCell<T, U>(ref T[] cells, Vector3 position, out bool maxCellCreated) where T : Cell, new() where U : Cell, new()
{
Vector3 localPos = position - bounds.min;
int x = (int)(localPos.x / bounds.extents.x);
int y = (int)(localPos.y / bounds.extents.y);
int z = (int)(localPos.z / bounds.extents.z);
int index = x + (y * 4) + (z * 2);
AddCell<T, U>(ref cells, index, x, y, z, out maxCellCreated);
return index;
}
protected void AddCell<T, U>(ref T[] cells, int index, int x, int y, int z, out bool maxCellCreated) where T : Cell, new() where U : Cell, new()
{
if (cells == null) { cells = new T[8]; }
if (cellsUsed == null) { cellsUsed = new bool[8]; }
// Reporter.Log("index "+index+" position "+localPos+" x: "+x+" y: "+y+" z: "+z+" extents "+bounds.extents);
if (!cellsUsed[index])
{
Bounds subBounds = new Bounds(new Vector3(bounds.min.x + (bounds.extents.x * (x + 0.5f)), bounds.min.y + (bounds.extents.y * (y + 0.5f)), bounds.min.z + (bounds.extents.z * (z + 0.5f))), bounds.extents);
if (level == maxLevels - 1)
{
cells[index] = new U() as T;
cells[index].SetCell(this, index, subBounds);
maxCellCreated = true;
}
else
{
maxCellCreated = false;
cells[index] = new T();
cells[index].SetCell(this, index, subBounds);
}
cellsUsed[index] = true;
++cellCount;
}
else maxCellCreated = false;
}
//public void RemoveCell(int index)
//{
// cells[index] = null;
// cellsUsed[index] = false;
// --cellCount;
// if (cellCount == 0)
// {
// if (parent != null) parent.RemoveCell(cellIndex);
// }
//}
public bool InsideBounds(Vector3 position)
{
position -= bounds.min;
if (position.x >= bounds.size.x || position.y >= bounds.size.y || position.z >= bounds.size.z || position.x <= 0 || position.y <= 0 || position.z <= 0) { return false; }
return true;
} //===============================================================================================================================
public void Reset(ref Cell[] cells)
{
cells = null;
cellsUsed = null;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5ab51a03cf378854e91c71ccf032dd7c
timeCreated: 1490856533
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,435 @@
using UnityEngine;
using System;
using System.Collections.Generic;
namespace MeshCombineStudio
{
public class ObjectOctree
{
public class LODParent
{
public GameObject cellGO;
public Transform cellT;
public LODGroup lodGroup;
public LODLevel[] lodLevels;
public bool hasChanged;
public int jobsPending;
public LODParent(int lodCount)
{
lodLevels = new LODLevel[lodCount];
for (int i = 0; i < lodLevels.Length; i++) lodLevels[i] = new LODLevel();
}
public void AssignLODGroup(MeshCombiner meshCombiner)
{
LOD[] lods = new LOD[lodLevels.Length];
int lodGroupParentIndex = lods.Length - 1;
for (int i = 0; i < lodLevels.Length; i++)
{
LODLevel lodLevel = lodLevels[i];
// Debug.Log(i + " " + lodLevel.newMeshRenderers.Count);
lods[i] = new LOD(meshCombiner.lodGroupsSettings[lodGroupParentIndex].lodSettings[i].screenRelativeTransitionHeight, lodLevel.newMeshRenderers.ToArray());
}
lodGroup.SetLODs(lods);
lodGroup.size = meshCombiner.cellSize;
}
public void ApplyChanges(MeshCombiner meshCombiner)
{
for (int i = 0; i < lodLevels.Length; i++) lodLevels[i].ApplyChanges(meshCombiner);
hasChanged = false;
}
}
public class LODLevel
{
public List<CachedGameObject> cachedGOs = new List<CachedGameObject>();
public List<MeshObjectsHolder> meshObjectsHolders;
public List<MeshObjectsHolder> changedMeshObjectsHolders;
public List<MeshRenderer> newMeshRenderers = new List<MeshRenderer>();
public int vertCount, objectCount = 0;
public int GetSortMeshIndex(Material mat, bool shadowCastingModeTwoSided, int lightmapIndex)
{
int matInstanceID = mat.GetInstanceID();
for (int i = 0; i < meshObjectsHolders.Count; i++)
{
MeshObjectsHolder meshObjectHolder = meshObjectsHolders[i];
// if (mat == null) Debug.Log("Material null");
if (meshObjectHolder.mat == null) { continue; }// Debug.Log("Sorted mat null");
if (meshObjectHolder.mat.GetInstanceID() == matInstanceID && meshObjectHolder.shadowCastingModeTwoSided == shadowCastingModeTwoSided && meshObjectHolder.lightmapIndex == lightmapIndex) return i;
// if (meshObjectHolder.mat.name == mat.name && meshObjectHolder.mat.shader == mat.shader && meshObjectHolder.shadowCastingModeTwoSided == shadowCastingModeTwoSided && meshObjectHolder.lightmapIndex == lightmapIndex &&
// (!mat.HasProperty("_MainTex") || (mat.HasProperty("_MainTex") && meshObjectHolder.mat.GetTexture("_MainTex") == mat.GetTexture("_MainTex")))) return i;
}
return -1;
}
public void ApplyChanges(MeshCombiner meshCombiner)
{
for (int i = 0; i < changedMeshObjectsHolders.Count; i++)
{
MeshObjectsHolder meshObjectHolder = changedMeshObjectsHolders[i];
meshObjectHolder.hasChanged = false;
}
changedMeshObjectsHolders.Clear();
}
}
public class MaxCell : Cell
{
static public int maxCellCount;
public LODParent[] lodParents;
public List<LODParent> changedLodParents;
public bool hasChanged;
public void ApplyChanges(MeshCombiner meshCombiner)
{
for (int i = 0; i < changedLodParents.Count; i++) changedLodParents[i].ApplyChanges(meshCombiner);
changedLodParents.Clear();
hasChanged = false;
}
}
public class Cell : BaseOctree.Cell
{
public Cell[] cells;
public Cell() { }
public Cell(Vector3 position, Vector3 size, int maxLevels) : base(position, size, maxLevels) { }
public CachedGameObject AddObject(Vector3 position, MeshCombiner meshCombiner, CachedGameObject cachedGO, int lodParentIndex, int lodLevel, bool isChangeMode = false)
{
if (InsideBounds(position))
{
AddObjectInternal(meshCombiner, cachedGO, position, lodParentIndex, lodLevel, isChangeMode);
return cachedGO;
}
return null;
}
void AddObjectInternal(MeshCombiner meshCombiner, CachedGameObject cachedGO, Vector3 position, int lodParentIndex, int lodLevel, bool isChangeMode)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.lodParents == null) thisCell.lodParents = new LODParent[10];
if (thisCell.lodParents[lodParentIndex] == null) thisCell.lodParents[lodParentIndex] = new LODParent(lodParentIndex + 1);
LODParent lodParent = thisCell.lodParents[lodParentIndex];
LODLevel lod = lodParent.lodLevels[lodLevel];
lod.cachedGOs.Add(cachedGO);
if (isChangeMode)
{
if (SortObject(meshCombiner, lod, cachedGO))
{
if (!thisCell.hasChanged)
{
thisCell.hasChanged = true;
if (meshCombiner.changedCells == null) meshCombiner.changedCells = new List<MaxCell>();
meshCombiner.changedCells.Add(thisCell);
}
if (!lodParent.hasChanged)
{
lodParent.hasChanged = true;
thisCell.changedLodParents.Add(lodParent);
}
}
}
lod.objectCount++;
lod.vertCount += cachedGO.mesh.vertexCount;
return;
}
else
{
bool maxCellCreated;
int index = AddCell<Cell, MaxCell>(ref cells, position, out maxCellCreated);
if (maxCellCreated) MaxCell.maxCellCount++;
cells[index].AddObjectInternal(meshCombiner, cachedGO, position, lodParentIndex, lodLevel, isChangeMode);
}
}
public void SortObjects(MeshCombiner meshCombiner)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
LODParent[] lodParents = thisCell.lodParents;
for (int i = 0; i < lodParents.Length; i++)
{
LODParent lodParent = lodParents[i];
if (lodParent == null) continue;
for (int j = 0; j < lodParent.lodLevels.Length; j++)
{
LODLevel lod = lodParent.lodLevels[j];
if (lod == null || lod.cachedGOs.Count == 0) return;
for (int k = 0; k < lod.cachedGOs.Count; ++k)
{
CachedGameObject cachedGO = lod.cachedGOs[k];
if (!SortObject(meshCombiner, lod, cachedGO))
{
Methods.ListRemoveAt(lod.cachedGOs, k--);
}
}
}
}
}
else
{
for (int i = 0; i < 8; ++i)
{
if (cellsUsed[i]) cells[i].SortObjects(meshCombiner);
}
}
}
public bool SortObject(MeshCombiner meshCombiner, LODLevel lod, CachedGameObject cachedGO, bool isChangeMode = false)
{
if (cachedGO.mr == null) return false;
if (lod.meshObjectsHolders == null) lod.meshObjectsHolders = new List<MeshObjectsHolder>();
Material[] mats = cachedGO.mr.sharedMaterials;
// TODO check submeshes and material
int length = Mathf.Min(cachedGO.mesh.subMeshCount, mats.Length);
for (int l = 0; l < length; l++)
{
Material mat = mats[l];
if (mat == null) continue;
bool shadowCastingModeTwoSided = (cachedGO.mr.shadowCastingMode == UnityEngine.Rendering.ShadowCastingMode.TwoSided);
int lightmapIndex = meshCombiner.validCopyBakedLighting ? cachedGO.mr.lightmapIndex : -1;
int index = lod.GetSortMeshIndex(mat, shadowCastingModeTwoSided, lightmapIndex);
MeshObjectsHolder meshObjectHolder;
if (index == -1)
{
meshObjectHolder = new MeshObjectsHolder(cachedGO, mat, l, shadowCastingModeTwoSided, lightmapIndex);
lod.meshObjectsHolders.Add(meshObjectHolder);
}
else
{
meshObjectHolder = lod.meshObjectsHolders[index];
meshObjectHolder.meshObjects.Add(new MeshObject(cachedGO, l));
}
if (isChangeMode && !meshObjectHolder.hasChanged)
{
meshObjectHolder.hasChanged = true;
lod.changedMeshObjectsHolders.Add(meshObjectHolder);
}
}
return true;
}
public void CombineMeshes(MeshCombiner meshCombiner, int lodParentIndex)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
LODParent lodParent = thisCell.lodParents[lodParentIndex];
if (lodParent == null) return;
lodParent.cellGO = new GameObject(meshCombiner.useCells ? "Cell " + bounds.center : "Combined Objects");
lodParent.cellT = lodParent.cellGO.transform;
lodParent.cellT.position = bounds.center;
lodParent.cellT.parent = meshCombiner.lodParentHolders[lodParentIndex].t;
if (lodParentIndex > 0)
{
lodParent.lodGroup = lodParent.cellGO.AddComponent<LODGroup>();
lodParent.lodGroup.localReferencePoint = lodParent.cellT.position = bounds.center;
}
LODLevel[] lods = lodParent.lodLevels;
for (int i = 0; i < lods.Length; i++)
{
LODLevel lod = lodParent.lodLevels[i];
if (lod == null || lod.meshObjectsHolders == null) return;
GameObject lodGO;
Transform lodT = null;
if (lodParentIndex > 0)
{
lodGO = new GameObject("LOD" + i);
lodT = lodGO.transform;
lodT.parent = lodParent.cellT;
}
for (int k = 0; k < lod.meshObjectsHolders.Count; ++k)
{
MeshObjectsHolder sortedMeshes = lod.meshObjectsHolders[k];
sortedMeshes.lodParent = lodParent;
sortedMeshes.lodLevel = i;
MeshCombineJobManager.instance.AddJob(meshCombiner, sortedMeshes, lodParentIndex > 0 ? lodT : lodParent.cellT, bounds.center);
}
}
}
else
{
for (int i = 0; i < 8; ++i)
{
if (cellsUsed[i]) cells[i].CombineMeshes(meshCombiner, lodParentIndex);
}
}
}
public void Draw(MeshCombiner meshCombiner, bool onlyMaxLevel, bool drawLevel0)
{
if (!onlyMaxLevel || level == maxLevels || (drawLevel0 && level == 0))
{
Gizmos.DrawWireCube(bounds.center, bounds.size);
if (level == maxLevels)
{
if (meshCombiner.drawMeshBounds)
{
MaxCell thisCell = (MaxCell)this;
LODParent[] lodParents = thisCell.lodParents;
for (int i = 0; i < lodParents.Length; i++)
{
if (lodParents[i] == null) continue;
LODLevel[] lods = lodParents[i].lodLevels;
Gizmos.color = meshCombiner.activeOriginal ? Color.blue : Color.green;
for (int j = 0; j < lods.Length; j++)
{
for (int k = 0; k < lods[j].cachedGOs.Count; k++)
{
if (lods[j].cachedGOs[k].mr == null) continue;
Bounds meshBounds = lods[j].cachedGOs[k].mr.bounds;
Gizmos.DrawWireCube(meshBounds.center, meshBounds.size);
}
}
Gizmos.color = Color.white;
}
return;
}
}
}
if (cells == null || cellsUsed == null) { return; }
for (int i = 0; i < 8; i++)
{
if (cellsUsed[i]) cells[i].Draw(meshCombiner, onlyMaxLevel, drawLevel0);
}
}
}
}
[Serializable]
public class MeshObjectsHolder
{
public Material mat;
public List<MeshObject> meshObjects = new List<MeshObject>();
public ObjectOctree.LODParent lodParent;
public List<CachedGameObject> newCachedGOs;
public int lodLevel;
public int lightmapIndex;
public bool shadowCastingModeTwoSided;
public bool hasChanged;
public MeshObjectsHolder(CachedGameObject cachedGO, Material mat, int subMeshIndex, bool shadowCastingModeTwoSided, int lightmapIndex)
{
// Debug.Log(useForLightmapping);
this.mat = mat;
this.shadowCastingModeTwoSided = shadowCastingModeTwoSided;
this.lightmapIndex = lightmapIndex;
meshObjects.Add(new MeshObject(cachedGO, subMeshIndex));
}
}
[Serializable]
public class MeshObject
{
public CachedGameObject cachedGO;
public MeshCache meshCache;
public int subMeshIndex;
public Vector3 position, scale;
public Quaternion rotation;
public Vector4 lightmapScaleOffset;
public bool intersectsSurface;
public int startNewTriangleIndex, newTriangleCount;
public bool skip;
public MeshObject(CachedGameObject cachedGO, int subMeshIndex)
{
this.cachedGO = cachedGO;
this.subMeshIndex = subMeshIndex;
Transform t = cachedGO.t;
position = t.position;
rotation = t.rotation;
scale = t.lossyScale;
lightmapScaleOffset = cachedGO.mr.lightmapScaleOffset;
}
}
[Serializable]
public class CachedGameObject
{
public GameObject go;
public Transform t;
public MeshRenderer mr;
public MeshFilter mf;
public Mesh mesh;
public CachedGameObject(GameObject go, Transform t, MeshRenderer mr, MeshFilter mf, Mesh mesh)
{
this.go = go;
this.t = t;
this.mr = mr;
this.mf = mf;
this.mesh = mesh;
}
public CachedGameObject(CachedComponents cachedComponent)
{
go = cachedComponent.go;
t = cachedComponent.t;
mr = cachedComponent.mr;
mf = cachedComponent.mf;
mesh = cachedComponent.mf.sharedMesh;
}
}
[Serializable]
public class CachedLodGameObject : CachedGameObject
{
public Vector3 center;
public int lodCount, lodLevel;
public CachedLodGameObject(CachedGameObject cachedGO, int lodCount, int lodLevel) : base(cachedGO.go, cachedGO.t, cachedGO.mr, cachedGO.mf, cachedGO.mesh)
{
this.lodCount = lodCount;
this.lodLevel = lodLevel;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 95bb6d48e5a70ec4bb2e73afcccda6c5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: