327 lines
10 KiB
C#
327 lines
10 KiB
C#
![]() |
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
namespace RayFire
|
|||
|
{
|
|||
|
[Serializable]
|
|||
|
public class RFMeshExport
|
|||
|
{
|
|||
|
public enum MeshExportType
|
|||
|
{
|
|||
|
LastFragments = 0,
|
|||
|
Children = 3
|
|||
|
}
|
|||
|
|
|||
|
public MeshExportType source;
|
|||
|
public string suffix = "_frags";
|
|||
|
|
|||
|
// by path, by window
|
|||
|
// public string path = "RayFireFragments";
|
|||
|
|
|||
|
// all, last
|
|||
|
// generate colliders
|
|||
|
}
|
|||
|
|
|||
|
[Serializable]
|
|||
|
public class RFShatterAdvanced
|
|||
|
{
|
|||
|
public int seed;
|
|||
|
public bool decompose;
|
|||
|
public bool removeCollinear;
|
|||
|
public bool copyComponents;
|
|||
|
public bool inputPrecap;
|
|||
|
public bool outputPrecap;
|
|||
|
public bool removeDoubleFaces;
|
|||
|
public int elementSizeThreshold;
|
|||
|
public bool combineChildren;
|
|||
|
public bool smooth;
|
|||
|
public bool postWeld;
|
|||
|
public bool inner;
|
|||
|
public bool planar;
|
|||
|
public int relativeSize;
|
|||
|
public float absoluteSize;
|
|||
|
public bool sizeLimitation;
|
|||
|
public float sizeAmount;
|
|||
|
public bool vertexLimitation;
|
|||
|
public int vertexAmount;
|
|||
|
public bool triangleLimitation;
|
|||
|
public int triangleAmount;
|
|||
|
//public bool bake;
|
|||
|
|
|||
|
// Planar mesh vert offset threshold
|
|||
|
public static float planarThreshold = 0.01f;
|
|||
|
public static Vector3[] vertices;
|
|||
|
public static Plane plane;
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Constructor
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Constructor
|
|||
|
public RFShatterAdvanced()
|
|||
|
{
|
|||
|
seed = 0;
|
|||
|
decompose = true;
|
|||
|
removeCollinear = false;
|
|||
|
copyComponents = false;
|
|||
|
inputPrecap = true;
|
|||
|
outputPrecap = false;
|
|||
|
removeDoubleFaces = true;
|
|||
|
elementSizeThreshold = 5;
|
|||
|
combineChildren = false;
|
|||
|
smooth = false;
|
|||
|
postWeld = false;
|
|||
|
inner = false;
|
|||
|
planar = false;
|
|||
|
absoluteSize = 0.1f;
|
|||
|
relativeSize = 4;
|
|||
|
sizeLimitation = false;
|
|||
|
sizeAmount = 5f;
|
|||
|
vertexLimitation = false;
|
|||
|
vertexAmount = 300;
|
|||
|
triangleLimitation = false;
|
|||
|
triangleAmount = 300;
|
|||
|
//bake = true;
|
|||
|
}
|
|||
|
|
|||
|
// Constructor
|
|||
|
public RFShatterAdvanced (RFShatterAdvanced src)
|
|||
|
{
|
|||
|
seed = src.seed;
|
|||
|
decompose = src.decompose;
|
|||
|
removeCollinear = src.removeCollinear;
|
|||
|
copyComponents = src.copyComponents;
|
|||
|
inputPrecap = src.inputPrecap;
|
|||
|
outputPrecap = src.outputPrecap;
|
|||
|
removeDoubleFaces = src.removeDoubleFaces;
|
|||
|
elementSizeThreshold = src.elementSizeThreshold;
|
|||
|
combineChildren = src.combineChildren;
|
|||
|
smooth = src.smooth;
|
|||
|
postWeld = src.postWeld;
|
|||
|
inner = src.inner;
|
|||
|
planar = src.planar;
|
|||
|
absoluteSize = src.absoluteSize;
|
|||
|
relativeSize = src.relativeSize;
|
|||
|
sizeLimitation = src.sizeLimitation;
|
|||
|
sizeAmount = src.sizeAmount;
|
|||
|
vertexLimitation = src.vertexLimitation;
|
|||
|
vertexAmount = src.vertexAmount;
|
|||
|
triangleLimitation = src.triangleLimitation;
|
|||
|
triangleAmount = src.triangleAmount;
|
|||
|
//bake = src.bake;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Static
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Check if mesh is coplanar. All verts on a plane
|
|||
|
public static bool IsCoplanar(Mesh mesh, float threshold)
|
|||
|
{
|
|||
|
// Coplanar 3 verts
|
|||
|
if (mesh.vertexCount <= 3)
|
|||
|
return true;
|
|||
|
|
|||
|
// Get first plane vertex index
|
|||
|
int index1 = 0;
|
|||
|
int index2 = 0;
|
|||
|
int index3 = 0;
|
|||
|
|
|||
|
// Set array of vertices
|
|||
|
vertices = mesh.vertices;
|
|||
|
|
|||
|
// Get second plane vertex index
|
|||
|
int ind = 1;
|
|||
|
for (int i = ind; i < vertices.Length; i++)
|
|||
|
{
|
|||
|
if (Vector3.Distance (vertices[index1], vertices[i]) > threshold)
|
|||
|
{
|
|||
|
index2 = i;
|
|||
|
ind = i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// No second vert
|
|||
|
if (index2 == 0)
|
|||
|
return true;
|
|||
|
|
|||
|
// Second vert is the last ver
|
|||
|
if (ind == vertices.Length - 1)
|
|||
|
return true;
|
|||
|
|
|||
|
// Get third vert
|
|||
|
ind++;
|
|||
|
float distance;
|
|||
|
Vector3 vector2;
|
|||
|
Vector3 vector1 = (vertices[index2] - vertices[index1]).normalized;
|
|||
|
for (int i = ind; i < vertices.Length; i++)
|
|||
|
{
|
|||
|
if (Vector3.Distance (vertices[index1], vertices[i]) > threshold)
|
|||
|
{
|
|||
|
vector2 = (vertices[i] - vertices[index1]).normalized;
|
|||
|
distance = Vector3.Cross (vector1, vector2).magnitude;
|
|||
|
if (distance > threshold)
|
|||
|
{
|
|||
|
index3 = i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// No third vert
|
|||
|
if (index3 == 0)
|
|||
|
return true;
|
|||
|
|
|||
|
// Create plane and check other verts for coplanar
|
|||
|
plane = new Plane(vertices[index1], vertices[index2], vertices[index3]);
|
|||
|
for (int i = 0; i < vertices.Length; i++)
|
|||
|
{
|
|||
|
if (i != index1 && i != index2 && i != index3)
|
|||
|
{
|
|||
|
distance = plane.GetDistanceToPoint (vertices[i]);
|
|||
|
if (Math.Abs (distance) > threshold)
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Filters
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Filter out planar meshes
|
|||
|
public static void RemovePlanar(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] origSubMeshIdsRf, RayfireShatter scrShatter)
|
|||
|
{
|
|||
|
if (scrShatter.advanced.planar == true)
|
|||
|
{
|
|||
|
List<Mesh> newMeshes = new List<Mesh>();
|
|||
|
List<Vector3> newPivots = new List<Vector3>();
|
|||
|
List<RFDictionary> newIds = new List<RFDictionary>();
|
|||
|
for (int i = 0; i < meshes.Length; i++)
|
|||
|
{
|
|||
|
if (RFShatterAdvanced.IsCoplanar (meshes[i], RFShatterAdvanced.planarThreshold) == false)
|
|||
|
{
|
|||
|
newMeshes.Add (meshes[i]);
|
|||
|
newPivots.Add (pivots[i]);
|
|||
|
newIds.Add (origSubMeshIdsRf[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
if (newMeshes.Count > 0)
|
|||
|
{
|
|||
|
meshes = newMeshes.ToArray();
|
|||
|
pivots = newPivots.ToArray();
|
|||
|
origSubMeshIdsRf = newIds.ToArray();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Filter out meshes by size
|
|||
|
public static void RemoveBySize(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] origSubMeshIdsRf, RayfireShatter scr)
|
|||
|
{
|
|||
|
if (scr.advanced.absoluteSize > 0 || scr.advanced.relativeSize > 0)
|
|||
|
{
|
|||
|
List<Mesh> newMeshes = new List<Mesh>();
|
|||
|
List<Vector3> newPivots = new List<Vector3>();
|
|||
|
List<RFDictionary> newIds = new List<RFDictionary>();
|
|||
|
|
|||
|
// Size
|
|||
|
float size = scr.advanced.relativeSize / 100f;
|
|||
|
if (scr.meshRenderer != null)
|
|||
|
size *= scr.meshRenderer.bounds.size.magnitude;
|
|||
|
if (scr.skinnedMeshRend != null)
|
|||
|
size *= scr.skinnedMeshRend.bounds.size.magnitude;
|
|||
|
|
|||
|
// Filter
|
|||
|
for (int i = 0; i < meshes.Length; i++)
|
|||
|
{
|
|||
|
if (scr.advanced.absoluteSize > 0)
|
|||
|
if (meshes[i].bounds.size.magnitude > scr.advanced.absoluteSize)
|
|||
|
{
|
|||
|
newMeshes.Add (meshes[i]);
|
|||
|
newPivots.Add (pivots[i]);
|
|||
|
newIds.Add (origSubMeshIdsRf[i]);
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (scr.advanced.relativeSize > 0)
|
|||
|
if (meshes[i].bounds.size.magnitude > size)
|
|||
|
{
|
|||
|
newMeshes.Add (meshes[i]);
|
|||
|
newPivots.Add (pivots[i]);
|
|||
|
newIds.Add (origSubMeshIdsRf[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (newMeshes.Count > 0)
|
|||
|
{
|
|||
|
meshes = newMeshes.ToArray();
|
|||
|
pivots = newPivots.ToArray();
|
|||
|
origSubMeshIdsRf = newIds.ToArray();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Limitations
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Limitations ops
|
|||
|
public static void Limitations(RayfireShatter sh)
|
|||
|
{
|
|||
|
SizeLimitation(sh);
|
|||
|
SizeLimitation(sh);
|
|||
|
SizeLimitation(sh);
|
|||
|
VertexLimitation(sh);
|
|||
|
VertexLimitation(sh);
|
|||
|
VertexLimitation(sh);
|
|||
|
TriangleLimitation(sh);
|
|||
|
TriangleLimitation(sh);
|
|||
|
TriangleLimitation(sh);
|
|||
|
}
|
|||
|
|
|||
|
// Size limitation
|
|||
|
static void SizeLimitation(RayfireShatter sh)
|
|||
|
{
|
|||
|
if (sh.advanced.sizeLimitation != true)
|
|||
|
return;
|
|||
|
|
|||
|
for (int i = sh.fragmentsLast.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
MeshRenderer mr = sh.fragmentsLast[i].GetComponent<MeshRenderer>();
|
|||
|
if (mr.bounds.size.magnitude > sh.advanced.sizeAmount)
|
|||
|
sh.LimitationFragment (i);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Vertex limitation
|
|||
|
static void VertexLimitation(RayfireShatter sh)
|
|||
|
{
|
|||
|
if (sh.advanced.vertexLimitation != true)
|
|||
|
return;
|
|||
|
|
|||
|
for (int i = sh.fragmentsLast.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
MeshFilter mf = sh.fragmentsLast[i].GetComponent<MeshFilter>();
|
|||
|
if (mf.sharedMesh.vertexCount > sh.advanced.vertexAmount)
|
|||
|
sh.LimitationFragment (i);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Triangle limitation
|
|||
|
static void TriangleLimitation(RayfireShatter sh)
|
|||
|
{
|
|||
|
if (sh.advanced.triangleLimitation != true)
|
|||
|
return;
|
|||
|
|
|||
|
for (int i = sh.fragmentsLast.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
MeshFilter mf = sh.fragmentsLast[i].GetComponent<MeshFilter>();
|
|||
|
if (mf.sharedMesh.triangles.Length / 3 > sh.advanced.triangleAmount)
|
|||
|
sh.LimitationFragment (i);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|