598 lines
20 KiB
C#
598 lines
20 KiB
C#
/* SimpleLOD 1.5a */
|
|
/* By Orbcreation BV */
|
|
/* Richard Knol */
|
|
/* March 18, 2015 */
|
|
|
|
/* Note: if you also use other packages by Orbcreation, */
|
|
/* you may end up with multiple copies of this file. */
|
|
/* In that case, better delete/merge those files into 1. */
|
|
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
#if UNITY_WP8
|
|
#elif UNITY_WP_8_1
|
|
#elif UNITY_WSA
|
|
#elif UNITY_WSA_8_0
|
|
#elif UNITY_WSA_8_1
|
|
#elif UNITY_WINRT
|
|
#elif UNITY_WINRT_8_0
|
|
#elif UNITY_WINRT_8_1
|
|
#elif NETFX_CORE
|
|
#else
|
|
using System.Threading;
|
|
#endif
|
|
|
|
namespace OrbCreationExtensions
|
|
{
|
|
public static class MeshExtensions {
|
|
|
|
public static void RecalculateTangents(this Mesh mesh) {
|
|
int vertexCount = mesh.vertexCount;
|
|
Vector3[] vertices = mesh.vertices;
|
|
Vector3[] normals = mesh.normals;
|
|
Vector2[] texcoords = mesh.uv;
|
|
int[] triangles = mesh.triangles;
|
|
int triangleCount = triangles.Length/3;
|
|
Vector4[] tangents = new Vector4[vertexCount];
|
|
Vector3[] tan1 = new Vector3[vertexCount];
|
|
Vector3[] tan2 = new Vector3[vertexCount];
|
|
int tri = 0;
|
|
if(texcoords.Length<=0) return;
|
|
for (int i = 0; i < (triangleCount); i++) {
|
|
int i1 = triangles[tri];
|
|
int i2 = triangles[tri+1];
|
|
int i3 = triangles[tri+2];
|
|
|
|
Vector3 v1 = vertices[i1];
|
|
Vector3 v2 = vertices[i2];
|
|
Vector3 v3 = vertices[i3];
|
|
|
|
Vector2 w1 = texcoords[i1];
|
|
Vector2 w2 = texcoords[i2];
|
|
Vector2 w3 = texcoords[i3];
|
|
|
|
float x1 = v2.x - v1.x;
|
|
float x2 = v3.x - v1.x;
|
|
float y1 = v2.y - v1.y;
|
|
float y2 = v3.y - v1.y;
|
|
float z1 = v2.z - v1.z;
|
|
float z2 = v3.z - v1.z;
|
|
|
|
float s1 = w2.x - w1.x;
|
|
float s2 = w3.x - w1.x;
|
|
float t1 = w2.y - w1.y;
|
|
float t2 = w3.y - w1.y;
|
|
|
|
float div = s1 * t2 - s2 * t1;
|
|
float r = div == 0.0f ? 0.0f : 1.0f / div;
|
|
Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
|
|
Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
|
|
|
|
tan1[i1] += sdir;
|
|
tan1[i2] += sdir;
|
|
tan1[i3] += sdir;
|
|
|
|
tan2[i1] += tdir;
|
|
tan2[i2] += tdir;
|
|
tan2[i3] += tdir;
|
|
|
|
tri += 3;
|
|
}
|
|
|
|
for (int i = 0; i < (vertexCount); i++) {
|
|
Vector3 n = normals[i];
|
|
Vector3 t = tan1[i];
|
|
|
|
// Gram-Schmidt orthogonalize
|
|
Vector3.OrthoNormalize(ref n, ref t );
|
|
|
|
tangents[i].x = t.x;
|
|
tangents[i].y = t.y;
|
|
tangents[i].z = t.z;
|
|
|
|
// Calculate handedness
|
|
tangents[i].w = ( Vector3.Dot(Vector3.Cross(n, t), tan2[i]) < 0.0f ) ? -1.0f : 1.0f;
|
|
}
|
|
mesh.tangents = tangents;
|
|
}
|
|
|
|
public static Mesh ScaledRotatedTranslatedMesh(this Mesh mesh, Vector3 scale, Quaternion rotate, Vector3 translate) {
|
|
Mesh newMesh = (Mesh)Mesh.Instantiate(mesh);
|
|
Vector3[] vertices = newMesh.vertices;
|
|
Vector3[] normals = newMesh.normals;
|
|
bool rotateNormals = true;
|
|
if(normals == null || normals.Length < vertices.Length || rotate == Quaternion.identity) rotateNormals = false;
|
|
for(int i=0;i<vertices.Length;i++) {
|
|
vertices[i].x *= scale.x;
|
|
vertices[i].y *= scale.y;
|
|
vertices[i].z *= scale.z;
|
|
vertices[i] = rotate * vertices[i];
|
|
if(rotateNormals) normals[i] = rotate * normals[i];
|
|
vertices[i] += translate;
|
|
}
|
|
newMesh.vertices = vertices;
|
|
if(rotateNormals) newMesh.normals = normals;
|
|
newMesh.RecalculateBounds();
|
|
return newMesh;
|
|
}
|
|
|
|
public static bool IsSkinnedMesh(this Mesh mesh) {
|
|
return mesh.blendShapeCount > 0 || (mesh.bindposes != null && mesh.bindposes.Length > 0);
|
|
}
|
|
public static int GetTriangleCount(this Mesh orig) {
|
|
return orig.triangles.Length / 3;
|
|
}
|
|
public static Mesh MakeLODMesh(this Mesh orig, float aMaxWeight, bool recalcNormals, float removeSmallParts = 1f, float protectNormals = 1f, float protectUvs = 1f, float protectSubMeshesAndSharpEdges = 1f, float smallTrianglesFirst = 1f) {
|
|
return LODMaker.MakeLODMesh(orig, aMaxWeight, removeSmallParts, protectNormals, protectUvs, protectSubMeshesAndSharpEdges, smallTrianglesFirst, recalcNormals);
|
|
}
|
|
|
|
#if UNITY_WP8
|
|
#elif UNITY_WP_8_1
|
|
#elif UNITY_WSA
|
|
#elif UNITY_WSA_8_0
|
|
#elif UNITY_WSA_8_1
|
|
#elif UNITY_WINRT
|
|
#elif UNITY_WINRT_8_0
|
|
#elif UNITY_WINRT_8_1
|
|
#elif NETFX_CORE
|
|
#else
|
|
public static IEnumerator MakeLODMeshInBackground(this Mesh mesh, float maxWeight, bool recalcNormals, float removeSmallParts, System.Action<Mesh> result) {
|
|
Hashtable lodInfo = new Hashtable();
|
|
lodInfo["maxWeight"] = maxWeight;
|
|
lodInfo["removeSmallParts"] = removeSmallParts;
|
|
Vector3[] vs = mesh.vertices;
|
|
if(vs.Length <= 0) throw new ApplicationException("Mesh was empty");
|
|
Vector3[] ns = mesh.normals;
|
|
if(ns.Length == 0) { // mesh has no normals
|
|
mesh.RecalculateNormals();
|
|
ns = mesh.normals;
|
|
}
|
|
Vector2[] uv1s = mesh.uv;
|
|
Vector2[] uv2s = mesh.uv2;
|
|
#if UNITY_4_3
|
|
Vector2[] uv3s = new Vector2[0];
|
|
Vector2[] uv4s = new Vector2[0];
|
|
#elif UNITY_4_4
|
|
Vector2[] uv3s = new Vector2[0];
|
|
Vector2[] uv4s = new Vector2[0];
|
|
#elif UNITY_4_5
|
|
Vector2[] uv3s = new Vector2[0];
|
|
Vector2[] uv4s = new Vector2[0];
|
|
#elif UNITY_4_6
|
|
Vector2[] uv3s = new Vector2[0];
|
|
Vector2[] uv4s = new Vector2[0];
|
|
#else
|
|
Vector2[] uv3s = mesh.uv3;
|
|
Vector2[] uv4s = mesh.uv4;
|
|
#endif
|
|
Color32[] colors32 = mesh.colors32;
|
|
int[] ts = mesh.triangles;
|
|
Matrix4x4[] bindposes = mesh.bindposes;
|
|
BoneWeight[] bws = mesh.boneWeights;
|
|
int[] subMeshOffsets = new int[mesh.subMeshCount];
|
|
if(mesh.subMeshCount > 1) { // read triangles of submeshes 1 by 1 because I dont know the internal order of the mesh
|
|
for(int s=0;s<mesh.subMeshCount;s++) {
|
|
int[] subTs = mesh.GetTriangles(s);
|
|
int t=0;
|
|
for(;t<subTs.Length;t++) ts[subMeshOffsets[s] + t] = subTs[t];
|
|
if(s+1 < mesh.subMeshCount) subMeshOffsets[s+1] = subMeshOffsets[s] + t;
|
|
}
|
|
}
|
|
Bounds meshBounds = mesh.bounds;
|
|
lodInfo["vertices"] = vs;
|
|
lodInfo["normals"] = ns;
|
|
lodInfo["uv1s"] = uv1s;
|
|
lodInfo["uv2s"] = uv2s;
|
|
lodInfo["uv3s"] = uv3s;
|
|
lodInfo["uv4s"] = uv4s;
|
|
lodInfo["colors32"] = colors32;
|
|
lodInfo["triangles"] = ts;
|
|
lodInfo["bindposes"] = bindposes;
|
|
lodInfo["boneWeights"] = bws;
|
|
lodInfo["subMeshOffsets"] = subMeshOffsets;
|
|
lodInfo["meshBounds"] = meshBounds;
|
|
|
|
Thread thread = new Thread(LODMaker.MakeLODMeshInBackground);
|
|
thread.Start(lodInfo);
|
|
while(!lodInfo.ContainsKey("ready")) {
|
|
yield return new WaitForSeconds(0.2f);
|
|
}
|
|
result(LODMaker.CreateNewMesh((Vector3[])lodInfo["vertices"], (Vector3[])lodInfo["normals"], (Vector2[])lodInfo["uv1s"], (Vector2[])lodInfo["uv2s"], (Vector2[])lodInfo["uv3s"], (Vector2[])lodInfo["uv4s"], (Color32[])lodInfo["colors32"], (int[])lodInfo["triangles"], (BoneWeight[])lodInfo["boneWeights"], (Matrix4x4[])lodInfo["bindposes"], (int[])lodInfo["subMeshOffsets"], recalcNormals));
|
|
}
|
|
#endif
|
|
|
|
public static Mesh[] MakeLODMeshes(this Mesh mesh, float[] maxWeights, bool recalcNormals, float removeSmallParts = 1f, float protectNormals = 1f, float protectUvs = 1f, float protectSubMeshesAndSharpEdges = 1f, float smallTrianglesFirst = 1f, int nrOfSteps = 1) {
|
|
if(maxWeights.Length < 1) {
|
|
Debug.LogError("Mesh.GetLODLevelMeshes: maxWeights arrays is empty");
|
|
return null;
|
|
}
|
|
|
|
// Create LODs
|
|
Mesh[] lodMeshes = new Mesh[maxWeights.Length];
|
|
float prevWeight = 0f;
|
|
for(int i=0;i<maxWeights.Length;i++) {
|
|
if(nrOfSteps < 1) nrOfSteps = 1;
|
|
for(int s=0;s<nrOfSteps;s++) {
|
|
float weight = (maxWeights[i] - prevWeight);
|
|
mesh = mesh.MakeLODMesh(((float)(s+1) * (weight / nrOfSteps)) + prevWeight, recalcNormals, removeSmallParts, protectNormals, protectUvs, protectSubMeshesAndSharpEdges, smallTrianglesFirst);
|
|
}
|
|
prevWeight = maxWeights[i];
|
|
lodMeshes[i] = mesh;
|
|
}
|
|
return lodMeshes;
|
|
}
|
|
|
|
public static Vector4 GetUvRange(this Mesh mesh) {
|
|
Vector4 range = new Vector4(0,0,1,1);
|
|
Vector2[] uvs = mesh.uv;
|
|
for(int i=0;i<uvs.Length;i++) {
|
|
Vector2 uv = uvs[i];
|
|
if(uv.x < range.x) range.x = uv.x;
|
|
if(uv.y < range.y) range.y = uv.y;
|
|
if(uv.x > range.z) range.z = uv.x;
|
|
if(uv.y > range.w) range.w = uv.y;
|
|
}
|
|
return range;
|
|
}
|
|
|
|
public static bool CheckUvsWithin01Range(this Mesh mesh) {
|
|
Vector2[] uvs = mesh.uv;
|
|
for(int i=0;i<uvs.Length;i++) {
|
|
Vector2 uv = uvs[i];
|
|
if(uv.x<0f || uv.x > 1f || uv.y < 0f || uv.y > 1f) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void ClampUvs(this Mesh mesh) {
|
|
Vector2[] uvs = mesh.uv;
|
|
for(int i=0;i<uvs.Length;i++) {
|
|
Vector2 uv = uvs[i];
|
|
uv.x = Mathf.Clamp01(uv.x);
|
|
uv.y = Mathf.Clamp01(uv.y);
|
|
uvs[i] = uv;
|
|
}
|
|
mesh.uv = uvs;
|
|
}
|
|
public static void WrapUvs(this Mesh mesh) {
|
|
Vector2[] uvs = mesh.uv;
|
|
for(int i=0;i<uvs.Length;i++) {
|
|
Vector2 uv = uvs[i];
|
|
while(uv.x>1f) uv.x-=1f;
|
|
while(uv.x<0f) uv.x+=1f;
|
|
while(uv.y>1f) uv.y-=1f;
|
|
while(uv.y<0f) uv.y+=1f;
|
|
uvs[i] = uv;
|
|
}
|
|
mesh.uv = uvs;
|
|
}
|
|
|
|
public static void SetAtlasRectForSubmesh(this Mesh mesh, Rect atlasRect, int submeshIndex) {
|
|
if(submeshIndex >= mesh.subMeshCount) return;
|
|
int[] tris = mesh.GetTriangles(submeshIndex);
|
|
List<int> uvsToMove = new List<int>();
|
|
for(int i=0;i<tris.Length;i++) {
|
|
int j = 0;
|
|
for(;j<uvsToMove.Count;j++) {
|
|
if(uvsToMove[j] == tris[i]) break;
|
|
}
|
|
if(j>=uvsToMove.Count) {
|
|
uvsToMove.Add(tris[i]);
|
|
}
|
|
}
|
|
|
|
Vector2[] uvs = mesh.uv;
|
|
for(int i=0;i<uvsToMove.Count;i++) {
|
|
Vector2 uv = uvs[uvsToMove[i]];
|
|
// when uv coordinates are outside of 0-1, the uv moves to a neighbouring texture
|
|
uv.x = (Mathf.Clamp01(uv.x) * atlasRect.width) + atlasRect.x;
|
|
uv.y = (Mathf.Clamp01(uv.y) * atlasRect.height) + atlasRect.y;
|
|
uvs[uvsToMove[i]] = uv;
|
|
}
|
|
mesh.uv = uvs;
|
|
}
|
|
|
|
public static void MergeSubmeshInto(this Mesh mesh, int from, int to) {
|
|
int[] fromTris = mesh.GetTriangles(from);
|
|
int[] toTris = mesh.GetTriangles(to);
|
|
List<int> newTris = new List<int>();
|
|
for(int i=0;i<toTris.Length;i++) newTris.Add(toTris[i]);
|
|
for(int i=0;i<fromTris.Length;i++) newTris.Add(fromTris[i]);
|
|
mesh.SetTriangles(newTris.ToArray(), to);
|
|
// move all submeshes 1 up
|
|
for(int i=from+1;i<mesh.subMeshCount;i++) {
|
|
mesh.SetTriangles(mesh.GetTriangles(i), i-1);
|
|
}
|
|
mesh.SetTriangles((int[])null, mesh.subMeshCount-1);
|
|
mesh.subMeshCount = mesh.subMeshCount-1;
|
|
}
|
|
|
|
public static Mesh CopyAndRemoveSubmeshes(this Mesh orig, int[] submeshesToRemove) {
|
|
Mesh mesh = (Mesh)Mesh.Instantiate(orig);
|
|
List<List<int>> submeshes = new List<List<int>>(mesh.subMeshCount);
|
|
List<Vector3> vs = new List<Vector3>(orig.vertices);
|
|
List<Vector3> ns = new List<Vector3>(orig.vertexCount);
|
|
List<Vector2> uv1s = new List<Vector2>(orig.vertexCount);
|
|
List<Vector2> uv2s = new List<Vector2>();
|
|
List<Vector2> uv3s = new List<Vector2>();
|
|
List<Vector2> uv4s = new List<Vector2>();
|
|
List<Color32> colors32 = new List<Color32>();
|
|
List<BoneWeight> bws = new List<BoneWeight>();
|
|
ns.AddRange(orig.normals);
|
|
uv1s.AddRange(orig.uv);
|
|
uv2s.AddRange(orig.uv2);
|
|
#if UNITY_4_3
|
|
#elif UNITY_4_4
|
|
#elif UNITY_4_5
|
|
#elif UNITY_4_6
|
|
#else
|
|
uv3s.AddRange(orig.uv3);
|
|
uv4s.AddRange(orig.uv4);
|
|
#endif
|
|
colors32.AddRange(orig.colors32);
|
|
bws.AddRange(orig.boneWeights);
|
|
|
|
for(int s=0;s<mesh.subMeshCount;s++) {
|
|
bool remove = false;
|
|
for(int i=0;i<submeshesToRemove.Length;i++) {
|
|
if(submeshesToRemove[i] == s) remove = true;
|
|
}
|
|
if(!remove) {
|
|
List<int> submesh = new List<int>();
|
|
submesh.AddRange(mesh.GetTriangles(s));
|
|
submeshes.Add(submesh);
|
|
}
|
|
}
|
|
|
|
LODMaker.RemoveUnusedVertices(vs, ns, uv1s, uv2s, uv3s, uv4s, colors32, bws, submeshes);
|
|
|
|
#if UNITY_4_3
|
|
#elif UNITY_4_4
|
|
#elif UNITY_4_5
|
|
#elif UNITY_4_6
|
|
#else
|
|
mesh.uv4 = null;
|
|
mesh.uv3 = null;
|
|
#endif
|
|
mesh.uv2 = null;
|
|
mesh.uv2 = null;
|
|
mesh.boneWeights = null;
|
|
mesh.colors32 = null;
|
|
mesh.normals = null;
|
|
mesh.tangents = null;
|
|
mesh.triangles = null;
|
|
mesh.vertices = vs.ToArray();
|
|
if(ns.Count>0) mesh.normals = ns.ToArray();
|
|
if(uv1s.Count>0) mesh.uv = uv1s.ToArray();
|
|
if(uv2s.Count>0) mesh.uv2 = uv2s.ToArray();
|
|
#if UNITY_4_3
|
|
#elif UNITY_4_4
|
|
#elif UNITY_4_5
|
|
#elif UNITY_4_6
|
|
#else
|
|
if(uv3s.Count>0) mesh.uv3 = uv3s.ToArray();
|
|
if(uv4s.Count>0) mesh.uv4 = uv4s.ToArray();
|
|
#endif
|
|
if(colors32.Count>0) mesh.colors32 = colors32.ToArray();
|
|
if(bws.Count>0) mesh.boneWeights = bws.ToArray();
|
|
|
|
mesh.subMeshCount = submeshes.Count;
|
|
for(int s=0;s<submeshes.Count;s++) {
|
|
mesh.SetTriangles(submeshes[s].ToArray(), s);
|
|
}
|
|
|
|
if(ns == null || ns.Count <= 0) mesh.RecalculateNormals();
|
|
RecalculateTangents(mesh);
|
|
mesh.RecalculateBounds();
|
|
return mesh;
|
|
}
|
|
|
|
public static Mesh CopyAndRemoveHiddenTriangles(this Mesh orig, int subMeshIdx, Matrix4x4 localToWorldMatrix, Mesh[] hidingMeshes, int[] hidingSubMeshes, Matrix4x4[] hidingLocalToWorldMatrices, float maxRemoveDistance = 0.01f) {
|
|
if(subMeshIdx >= orig.subMeshCount) return null;
|
|
if(hidingMeshes.Length <= 0) return null;
|
|
if(hidingMeshes.Length != hidingSubMeshes.Length || hidingMeshes.Length != hidingLocalToWorldMatrices.Length) return null;
|
|
// copy orig mesh and get everything in Lists
|
|
Mesh mesh = (Mesh)Mesh.Instantiate(orig);
|
|
List<List<int>> submeshes = new List<List<int>>(mesh.subMeshCount);
|
|
List<Vector3> vs = new List<Vector3>(orig.vertices);
|
|
List<Vector3> ns = new List<Vector3>(orig.vertexCount);
|
|
List<Vector2> uv1s = new List<Vector2>(orig.vertexCount);
|
|
List<Vector2> uv2s = new List<Vector2>();
|
|
List<Vector2> uv3s = new List<Vector2>();
|
|
List<Vector2> uv4s = new List<Vector2>();
|
|
List<Color32> colors32 = new List<Color32>();
|
|
List<BoneWeight> bws = new List<BoneWeight>();
|
|
ns.AddRange(orig.normals);
|
|
if(ns == null || ns.Count <= 0) {
|
|
orig.RecalculateNormals();
|
|
ns.AddRange(orig.normals);
|
|
}
|
|
uv1s.AddRange(orig.uv);
|
|
uv2s.AddRange(orig.uv2);
|
|
#if UNITY_4_3
|
|
#elif UNITY_4_4
|
|
#elif UNITY_4_5
|
|
#elif UNITY_4_6
|
|
#else
|
|
uv3s.AddRange(orig.uv3);
|
|
uv4s.AddRange(orig.uv4);
|
|
#endif
|
|
colors32.AddRange(orig.colors32);
|
|
bws.AddRange(orig.boneWeights);
|
|
for(int s=0;s<orig.subMeshCount;s++) {
|
|
List<int> submesh = new List<int>();
|
|
submesh.AddRange(orig.GetTriangles(s));
|
|
submeshes.Add(submesh);
|
|
}
|
|
List<int> ts = submeshes[subMeshIdx];
|
|
|
|
// Make combined arrays for triangles/vertices/normals in hiding meshes
|
|
List<Vector3> hidingVs = new List<Vector3>();
|
|
List<int> hidingTs = new List<int>();
|
|
Mesh prevMesh = null;
|
|
int triOffset = 0;
|
|
int prevHvsCount = 0;
|
|
for(int h=0;h<hidingMeshes.Length;h++) {
|
|
Mesh hidingMesh = hidingMeshes[h];
|
|
|
|
int[] hts = hidingMesh.GetTriangles(hidingSubMeshes[h]);
|
|
if(prevMesh != hidingMesh) triOffset += prevHvsCount;
|
|
for(int i=0;i<hts.Length;i++) {
|
|
hidingTs.Add(hts[i]+triOffset);
|
|
}
|
|
|
|
if(prevMesh != hidingMesh) {
|
|
Matrix4x4 hidingMatrix = hidingLocalToWorldMatrices[h];
|
|
Vector3[] hvs = hidingMesh.vertices;
|
|
for(int i=0;i<hvs.Length;i++) {
|
|
hidingVs.Add(hidingMatrix.MultiplyPoint3x4(hvs[i])); // vertex in world coordinates
|
|
}
|
|
prevHvsCount = hvs.Length;
|
|
prevMesh = hidingMesh;
|
|
}
|
|
}
|
|
|
|
// get bounding box per triangle
|
|
List<Vector3> triMinCorners = new List<Vector3>();
|
|
List<Vector3> triMaxCorners = new List<Vector3>();
|
|
for(int t=0;t<hidingTs.Count;t+=3) {
|
|
Vector3 v0 = hidingVs[hidingTs[t]];
|
|
Vector3 v1 = hidingVs[hidingTs[t+1]];
|
|
Vector3 v2 = hidingVs[hidingTs[t+2]];
|
|
triMinCorners.Add(new Vector3(Mathf.Min(Mathf.Min(v0.x, v1.x), v2.x), Mathf.Min(Mathf.Min(v0.y, v1.y), v2.y), Mathf.Min(Mathf.Min(v0.z, v1.z), v2.z)));
|
|
triMaxCorners.Add(new Vector3(Mathf.Max(Mathf.Max(v0.x, v1.x), v2.x), Mathf.Max(Mathf.Max(v0.y, v1.y), v2.y), Mathf.Max(Mathf.Max(v0.z, v1.z), v2.z)));
|
|
}
|
|
|
|
List<int> newTs = new List<int>();
|
|
for(int t=0;t<ts.Count;t+=3) {
|
|
// we use vertices in world coordinates
|
|
Vector3 v0 = localToWorldMatrix.MultiplyPoint3x4(vs[ts[t]]);
|
|
Vector3 v1 = localToWorldMatrix.MultiplyPoint3x4(vs[ts[t+1]]);
|
|
Vector3 v2 = localToWorldMatrix.MultiplyPoint3x4(vs[ts[t+2]]);
|
|
if(!IsTriangleHidden(v0, v1, v2, maxRemoveDistance, triMinCorners, triMaxCorners, hidingVs, hidingTs)) {
|
|
newTs.Add(ts[t]);
|
|
newTs.Add(ts[t+1]);
|
|
newTs.Add(ts[t+2]);
|
|
}
|
|
}
|
|
|
|
// remove unused if anything deleted
|
|
submeshes[subMeshIdx] = newTs;
|
|
LODMaker.RemoveUnusedVertices(vs, ns, uv1s, uv2s, uv3s, uv4s, colors32, bws, submeshes);
|
|
|
|
// Fill new mesh
|
|
#if UNITY_4_3
|
|
#elif UNITY_4_4
|
|
#elif UNITY_4_5
|
|
#elif UNITY_4_6
|
|
#else
|
|
mesh.uv4 = null;
|
|
mesh.uv3 = null;
|
|
#endif
|
|
mesh.uv2 = null;
|
|
mesh.uv2 = null;
|
|
mesh.boneWeights = null;
|
|
mesh.colors32 = null;
|
|
mesh.normals = null;
|
|
mesh.tangents = null;
|
|
mesh.triangles = null;
|
|
mesh.vertices = vs.ToArray();
|
|
if(ns.Count>0) mesh.normals = ns.ToArray();
|
|
if(uv1s.Count>0) mesh.uv = uv1s.ToArray();
|
|
if(uv2s.Count>0) mesh.uv2 = uv2s.ToArray();
|
|
#if UNITY_4_5
|
|
#elif UNITY_4_6
|
|
#else
|
|
if(uv3s.Count>0) mesh.uv3 = uv3s.ToArray();
|
|
if(uv4s.Count>0) mesh.uv4 = uv4s.ToArray();
|
|
#endif
|
|
if(colors32.Count>0) mesh.colors32 = colors32.ToArray();
|
|
if(bws.Count>0) mesh.boneWeights = bws.ToArray();
|
|
|
|
mesh.subMeshCount = submeshes.Count;
|
|
for(int s=0;s<submeshes.Count;s++) {
|
|
if(s == subMeshIdx) mesh.SetTriangles(newTs.ToArray(), s);
|
|
else mesh.SetTriangles(submeshes[s].ToArray(), s);
|
|
}
|
|
|
|
if(ns == null || ns.Count <= 0) mesh.RecalculateNormals();
|
|
RecalculateTangents(mesh);
|
|
mesh.RecalculateBounds();
|
|
return mesh;
|
|
}
|
|
|
|
private static bool IsTriangleHidden(Vector3 v0, Vector3 v1, Vector3 v2, float maxDistance, List<Vector3> triMinCorners, List<Vector3> triMaxCorners, List<Vector3> hidingVs, List<int> hidingTs) {
|
|
Vector3 n = GetNormal(v0, v1, v2); // compute the normal rather than using the existing one. Because I want it square to the triangle plane
|
|
List<int> trianglesToCheck = GetTrianglesWithinRange(v0, v1, v2, maxDistance, triMinCorners, triMaxCorners);
|
|
if(!IsHidden((v0 + v1 + v2) / 3f, n, maxDistance, hidingVs, hidingTs, trianglesToCheck)) {
|
|
return false;
|
|
}
|
|
if(!IsHidden(v0, n, maxDistance, hidingVs, hidingTs, trianglesToCheck)) {
|
|
return false;
|
|
}
|
|
if(!IsHidden(v1, n, maxDistance, hidingVs, hidingTs, trianglesToCheck)) {
|
|
return false;
|
|
}
|
|
if(!IsHidden(v2, n, maxDistance, hidingVs, hidingTs, trianglesToCheck)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
private static bool IsHidden(Vector3 v, Vector3 n, float maxDistance, List<Vector3> hidingVs, List<int> hidingTs, List<int> trianglesToCheck) {
|
|
|
|
for(int i=0;i<trianglesToCheck.Count;i++) {
|
|
int t = trianglesToCheck[i] * 3;
|
|
Vector3 hc0 = hidingVs[hidingTs[t]];
|
|
Vector3 hc1 = hidingVs[hidingTs[t+1]];
|
|
Vector3 hc2 = hidingVs[hidingTs[t+2]];
|
|
Vector3 hn = GetNormal(hc0, hc1, hc2);
|
|
float angle = Vector3.Angle(n, hn);
|
|
if(angle < 60f) {
|
|
float dist = DistanceToPlane(v, n, hc0, hn);
|
|
if(dist > 0f && dist <= maxDistance) {
|
|
Vector3 point = v + (n * dist);
|
|
Vector2 bar = point.Barycentric(hc0, hc1, hc2);
|
|
if(bar.IsBarycentricInTriangle()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static List<int> GetTrianglesWithinRange(Vector3 v0, Vector3 v1, Vector3 v2, float maxDistance, List<Vector3> triMinCorners, List<Vector3> triMaxCorners) {
|
|
List<int> idxs = new List<int>();
|
|
Vector3 from = new Vector3(Mathf.Min(Mathf.Min(v0.x, v1.x), v2.x) - maxDistance, Mathf.Min(Mathf.Min(v0.y, v1.y), v2.y) - maxDistance, Mathf.Min(Mathf.Min(v0.z, v1.z), v2.z) - maxDistance);
|
|
Vector3 to = new Vector3(Mathf.Max(Mathf.Max(v0.x, v1.x), v2.x) + maxDistance, Mathf.Max(Mathf.Max(v0.y, v1.y), v2.y) + maxDistance, Mathf.Max(Mathf.Max(v0.z, v1.z), v2.z) + maxDistance);
|
|
for(int i=0;i<triMaxCorners.Count;i++) {
|
|
Vector3 maxCorner = triMaxCorners[i];
|
|
if(maxCorner.x > from.x && maxCorner.y > from.y && maxCorner.z > from.z) {
|
|
Vector3 minCorner = triMinCorners[i];
|
|
if(minCorner.x < to.x && minCorner.y < to.y && minCorner.z < to.z) {
|
|
idxs.Add(i);
|
|
}
|
|
}
|
|
}
|
|
return idxs;
|
|
}
|
|
|
|
public static float DistanceToPlane(Vector3 fromPos, Vector3 direction, Vector3 pointOnPlane, Vector3 normalPlane) {
|
|
float dist = Mathf.Infinity;
|
|
float divideBy = direction.InProduct(normalPlane);
|
|
if(divideBy != 0f) dist = (pointOnPlane - fromPos).InProduct(normalPlane) / direction.InProduct(normalPlane);
|
|
return dist;
|
|
}
|
|
|
|
public static Vector3 GetNormal(Vector3 v0, Vector3 v1, Vector3 v2) {
|
|
return Vector3.Cross(v1 - v0, v2 - v0).normalized;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|