BITFALL/Assets/Plugins/FImpossible Creations/Plugins - Level Design/Generators Shared/Mesh Generating/FMeshUtils.Generate.cs

426 lines
15 KiB
C#

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
namespace FIMSpace.Generating
{
public static partial class FMeshUtils
{
public static Mesh GetSourceMeshCopy(Mesh SourceMesh, Vector3 rotate, EOrigin origin = EOrigin.Unchanged)
{
return GetSourceMeshCopy(SourceMesh, rotate, Vector3.one, origin);
}
public static Mesh GetSourceMeshCopy(Mesh SourceMesh, Vector3 rotate, Vector3 scale, EOrigin origin = EOrigin.Unchanged)
{
Mesh src = GameObject.Instantiate(SourceMesh);
if (rotate != Vector3.zero || scale != Vector3.one)
{
Matrix4x4 mx = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(rotate), scale);
var verts = src.vertices;
for (int v = 0; v < verts.Length; v++) verts[v] = mx.MultiplyPoint3x4(verts[v]);
src.SetVertices(verts);
}
if (origin != EOrigin.Unchanged) FMeshUtils.AdjustOrigin(src, origin);
return src;
}
public static Mesh GeneratePlaneMesh(List<FMeshUtils.PolyShapeHelpPoint> vGenPoints, Matrix4x4 mx)
{
for (int t = 0; t < vGenPoints.Count; t++) vGenPoints[t].helpIndex = t;
vGenPoints.Reverse();
List<Vector3> verts = new List<Vector3>();
for (int i = 0; i < vGenPoints.Count; i++)
{
verts.Add(mx.MultiplyPoint3x4(new Vector3(vGenPoints[i].vxPos.x, vGenPoints[i].vxPos.z, 0f)));
vGenPoints[i].index = i;
}
var tris = FMeshUtils.TriangulateConcavePolygon(vGenPoints);
tris.Reverse();
Mesh mesh = new Mesh();
mesh.SetVertices(verts);
mesh.SetTriangles(tris, 0);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
RenameMesh(mesh);
return mesh;
}
/// <summary>
/// Requires positions set in x and z axes
/// </summary>
public static Mesh GenerateCoverageMesh(List<FMeshUtils.PolyShapeHelpPoint> vGenPoints, Matrix4x4 mx, float depth)
{
List<Vector3> verts = new List<Vector3>();
for (int i = 0; i < vGenPoints.Count; i++)
{
verts.Add(mx.MultiplyPoint3x4(new Vector3(vGenPoints[i].vxPos.x, vGenPoints[i].vxPos.z, 0f)));
vGenPoints[i].index = i;
}
for (int i = 0; i < vGenPoints.Count; i++)
verts.Add(mx.MultiplyPoint3x4(new Vector3(vGenPoints[i].vxPos.x, vGenPoints[i].vxPos.z, depth)));
var tris = new List<int>();
int depthOff = vGenPoints.Count;
for (int i = 0; i < vGenPoints.Count - 1; i += 1)
{
// generating triangle bridge
// u -> uf uf -> d d -> df
tris.Add(vGenPoints[i].index);
tris.Add(vGenPoints[i].index + depthOff + 1);
tris.Add(vGenPoints[i].index + 1);
tris.Add(vGenPoints[i].index + depthOff + 1);
tris.Add(vGenPoints[i].index);
tris.Add(vGenPoints[i].index + depthOff);
}
// Loop last poly
tris.Add(vGenPoints[vGenPoints.Count - 1].index);
tris.Add(depthOff);
tris.Add(0);
tris.Add(depthOff);
tris.Add(vGenPoints[vGenPoints.Count - 1].index);
tris.Add(vGenPoints[vGenPoints.Count - 1].index + depthOff);
tris.Reverse();
Mesh mesh = new Mesh();
mesh.SetVertices(verts);
mesh.SetTriangles(tris, 0);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
RenameMesh(mesh);
return mesh;
}
public static Mesh ExtractSingleSubmesh(Mesh sourceMesh, int subMeshIndex)
{
if (sourceMesh.subMeshCount < 2) return sourceMesh;
if (subMeshIndex >= sourceMesh.subMeshCount) return sourceMesh;
if (subMeshIndex < 0) return sourceMesh;
var vertices = sourceMesh.vertices;
var normals = sourceMesh.normals;
var uvs = sourceMesh.uv;
var cols = sourceMesh.colors;
var tang = sourceMesh.tangents;
var newVerts = new List<Vector3>();
var newNorms = new List<Vector3>();
var newTangents = new List<Vector4>();
var newTris = new List<int>();
var newUVs = new List<Vector2>();
var newColors = new List<Color>();
var triangles = sourceMesh.GetTriangles(subMeshIndex);
for (var i = 0; i < triangles.Length; i += 3)
{
var A = triangles[i + 0];
var B = triangles[i + 1];
var C = triangles[i + 2];
newVerts.Add(vertices[A]);
newVerts.Add(vertices[B]);
newVerts.Add(vertices[C]);
newNorms.Add(normals[A]);
newNorms.Add(normals[B]);
newNorms.Add(normals[C]);
if (cols.Length > 0)
{
newColors.Add(cols[A]);
newColors.Add(cols[B]);
newColors.Add(cols[C]);
}
newUVs.Add(uvs[A]);
newUVs.Add(uvs[B]);
newUVs.Add(uvs[C]);
if (tang.Length > 0)
{
newTangents.Add(tang[A]);
newTangents.Add(tang[B]);
newTangents.Add(tang[C]);
}
newTris.Add(newTris.Count);
newTris.Add(newTris.Count);
newTris.Add(newTris.Count);
}
var mesh = new Mesh();
mesh.name = sourceMesh.name;
mesh.indexFormat = newVerts.Count > 65536 ? IndexFormat.UInt32 : IndexFormat.UInt16;
mesh.SetVertices(newVerts);
mesh.SetNormals(newNorms);
mesh.SetUVs(0, newUVs);
if (newTangents.Count > 0) mesh.SetTangents(newTangents);
if (newColors.Count > 0) mesh.SetColors(newColors);
mesh.SetTriangles(newTris, 0, true);
return mesh;
}
public static Mesh CombineMeshes(List<CombineInstance> meshes)
{
if (meshes == null) return null;
if (meshes.Count == 0) return null;
Mesh mesh = new Mesh();
mesh.CombineMeshes(meshes.ToArray());
RenameMesh(mesh);
return mesh;
}
public static Mesh CombineMeshes(List<Mesh> meshes)
{
if (meshes == null) return null;
if (meshes.Count == 0) return null;
CombineInstance[] combines = new CombineInstance[meshes.Count];
for (int i = 0; i < meshes.Count; i += 1)
{
CombineInstance comb = new CombineInstance();
comb.mesh = meshes[i];
comb.transform = Matrix4x4.identity;
combines[i] = comb;
}
Mesh mesh = new Mesh();
mesh.CombineMeshes(combines);
RenameMesh(mesh);
return mesh;
}
public static Mesh CombineMeshesForSubMesh(Mesh joinWith, List<CombineInstance> groupToMerge)
{
if (joinWith == null) return null;
if (groupToMerge == null) return joinWith;
CombineInstance[] combines = groupToMerge.ToArray();
Mesh tempMesh = new Mesh();
tempMesh.CombineMeshes(combines, true, true);
combines = new CombineInstance[2];
combines[0] = new CombineInstance();
combines[0].mesh = joinWith;
combines[1] = new CombineInstance();
combines[1].mesh = tempMesh;
Mesh newMesh = new Mesh();
newMesh.CombineMeshes(combines, false, false);
RenameMesh(newMesh);
return newMesh;
}
public static MeshFilter GenerateMeshFilterAndRenderer(Transform parent, List<Material> mats)
{
return GenerateMeshFilterAndRenderer(parent, mats.ToArray());
}
public static GameObject GenerateChildOf(Transform parent)
{
GameObject newO = new GameObject(parent.name + "-Child");
newO.transform.SetParent(parent, true);
newO.transform.position = parent.position;
newO.transform.rotation = parent.rotation;
newO.transform.localScale = Vector3.one;
return newO;
}
public static MeshFilter GenerateMeshFilterAndRenderer(Transform parent, Material[] mats)
{
GameObject newO = GenerateChildOf(parent);
MeshFilter filt = newO.AddComponent<MeshFilter>();
MeshRenderer rend = newO.AddComponent<MeshRenderer>();
rend.sharedMaterials = mats;
return filt;
}
public static MeshFilter GenerateMeshFilterAndRenderer(Transform parent, Material mat)
{
GameObject newO = GenerateChildOf(parent);
MeshFilter filt = newO.AddComponent<MeshFilter>();
MeshRenderer rend = newO.AddComponent<MeshRenderer>();
rend.sharedMaterial = mat;
return filt;
}
public static LODGroup GenerateLODGroupFor(Transform transform)
{
LODGroup lodG = transform.GetComponent<LODGroup>();
if (lodG == null) lodG = transform.gameObject.AddComponent<LODGroup>();
return lodG;
}
public static MeshRenderer AddMeshFilterAndRendererFor(Transform transform)
{
MeshFilter filt = transform.GetComponent<MeshFilter>();
if (filt == null) /*filt = */ transform.gameObject.AddComponent<MeshFilter>();
MeshRenderer rend = transform.GetComponent<MeshRenderer>();
if (rend == null) rend = transform.gameObject.AddComponent<MeshRenderer>();
return rend;
}
public static void ApplyLODMeshesOn(LODGroup group, Renderer rendLOD0, Renderer rendLOD1, Renderer rendLOD2 = null, float cullAtScreenSize = 0.1f, float firstLODAt = 0.9f, float LODBias = 1f)
{
if (group == null) return;
Renderer[] lod0 = new Renderer[1] { rendLOD0 };
Renderer[] lod1 = null;
if (rendLOD1) lod1 = new Renderer[1] { rendLOD1 };
Renderer[] lod2 = null;
if (rendLOD2) lod2 = new Renderer[1] { rendLOD2 };
ApplyLODMeshesOn(group, lod0, lod1, lod2, cullAtScreenSize, firstLODAt, LODBias);
}
/// <summary>
/// Automatically generating/assigning child renderers for parent of rendLOD0
/// </summary>
public static void ApplyLODMeshesOnParentRenderer(LODGroup group, Renderer rendLOD0, Mesh lod1, Mesh lod2 = null, float cullAtScreenSize = 0.1f, float firstLODAt = 0.9f, float LODBias = 1f)
{
if (group == null) return;
Renderer[] lod0r = new Renderer[1] { rendLOD0 };
var rends = rendLOD0.transform.GetComponentsInChildren<Renderer>().ToList();
rends.Remove(rendLOD0);
Renderer rend1;
if (rends.Count >= 1)
{
MeshFilter filter = rends[0].GetComponent<MeshFilter>();
filter.sharedMesh = lod1;
rend1 = rends[0];
}
else
{
MeshFilter filter = GenerateMeshFilterAndRenderer(rendLOD0.transform, rendLOD0.sharedMaterials);
filter.sharedMesh = lod1;
rend1 = filter.GetComponent<Renderer>();
}
Renderer[] lod1r = null;
if (rend1) lod1r = new Renderer[1] { rend1 };
Renderer[] lod2r = null;
if (lod2 != null)
{
Renderer rend2;
if (rends.Count >= 2)
{
MeshFilter filter = rends[1].GetComponent<MeshFilter>();
filter.sharedMesh = lod2;
rend2 = rends[1];
}
else
{
MeshFilter filter = GenerateMeshFilterAndRenderer(rendLOD0.transform, rendLOD0.sharedMaterials);
filter.sharedMesh = lod2;
rend2 = filter.GetComponent<Renderer>();
}
if (rend2) lod2r = new Renderer[1] { rend2 };
}
ApplyLODMeshesOn(group, lod0r, lod1r, lod2r, cullAtScreenSize, firstLODAt, LODBias);
}
public static void DestroyChildRenderers(Transform parent)
{
var rends = parent.transform.GetComponentsInChildren<Renderer>();
for (int r = 0; r < rends.Length; r++)
{
if (rends[r] == null) continue;
if (rends[r].gameObject == null) continue;
if (rends[r].transform == parent) continue;
FGenerators.DestroyObject(rends[r].gameObject);
}
}
public static void ApplyLODMeshesOn(LODGroup group, Renderer[] rendLOD0, Renderer[] rendLOD1, Renderer[] rendLOD2 = null, float cullAtScreenSize = 0.1f, float firstLODAt = 0.9f, float LODBias = 1f)
{
if (group == null) return;
int count = 1;
if (rendLOD1 != null) count += 1;
if (rendLOD2 != null) count += 1;
LOD[] lods = new LOD[count];
if (rendLOD1 == null) firstLODAt = cullAtScreenSize;
lods[0] = new LOD(firstLODAt, rendLOD0);
if (rendLOD1 != null)
{
float lodPerc = (rendLOD2 != null) ? (Mathf.Lerp(Mathf.Max(firstLODAt - 0.1f, cullAtScreenSize), cullAtScreenSize, 0.6f) * LODBias) : (cullAtScreenSize * LODBias);
lods[1] = new LOD(lodPerc, rendLOD1);
if (rendLOD2 != null) lods[2] = new LOD(cullAtScreenSize * LODBias, rendLOD2);
}
group.SetLODs(lods);
group.RecalculateBounds();
}
public static void ApplyLODMeshesOn(LODGroup group, Mesh mesh0, Mesh mesh1, Material[] mats, Mesh mesh2 = null, float cullAtScreenSize = 0.1f, float firstLODAt = 0.9f, float LODBias = 1f)
{
if (group == null) return;
if (!mesh0) return;
List<Renderer> renderers = new List<Renderer>();
if (group.transform.childCount != 0)
{
for (int c = 0; c < group.transform.childCount; c++)
{
Renderer rend = group.transform.GetChild(c).GetComponent<MeshRenderer>();
if (rend) renderers.Add(rend);
}
}
int tgtCount = 1;
if (mesh1) tgtCount++;
if (mesh2) tgtCount++;
for (int i = renderers.Count; i < tgtCount; i++)
{
renderers.Add(FMeshUtils.GenerateMeshFilterAndRenderer(group.transform, mats).GetComponent<MeshRenderer>());
}
renderers[0].GetComponent<MeshFilter>().sharedMesh = mesh0;
if (mesh1) renderers[1].GetComponent<MeshFilter>().sharedMesh = mesh1;
if (mesh2) renderers[2].GetComponent<MeshFilter>().sharedMesh = mesh2;
ApplyLODMeshesOn(group, renderers[0], renderers.Count > 1 ? renderers[1] : null, renderers.Count > 2 ? renderers[2] : null, cullAtScreenSize, firstLODAt, LODBias);
}
}
}