OldBlueWater/BlueWater/Assets/RayFire/Scripts/Classes/Shatter/RFFragment.cs

1170 lines
49 KiB
C#
Raw Normal View History

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
#if (UNITY_EDITOR || UNITY_STANDALONE || UNITY_IOS || UNITY_ANDROID || UNITY_XBOXONE)
using RayFire.DotNet;
namespace RayFire
{
// Static class to handle all shatter methods
public static class RFFragment
{
static bool silentMode = true;
static List<Mesh> meshListStatic = new List<Mesh>();
static List<Vector3> pivotListStatic = new List<Vector3>();
static List<Dictionary<int, int>> subIdsListStatic = new List<Dictionary<int, int>>();
/// /////////////////////////////////////////////////////////
/// Shatter
/// /////////////////////////////////////////////////////////
// Cache for shatter
public static void CacheMeshes(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] rfOrigSubMeshIds, RayfireShatter scrShatter)
{
// TODO check vars by type: slice list, etc
// Min face filter for internal slice ops
int removeMinFaceFilter = 4;
// Turn off fast mode for tets and slices:
// 0:classic: Custom, tets, clustering: old original algorithm.
// 1:voro simple: Decompose type or Rigid without Shatter.
// 2:slice
// 3:bricks
int shatterMode = GetShatterMode (scrShatter);
// Get mesh
Mesh mesh = GetDemolitionMesh (scrShatter);
;
// Decompose in Editor only, slice runtime only
// Runtime = 0,
// Editor = 1
FragmentMode fragmentMode = scrShatter.mode;
if (scrShatter.type == FragType.Decompose) // TODO FIX
fragmentMode = FragmentMode.Editor;
if (scrShatter.type == FragType.Slices)
{
fragmentMode = FragmentMode.Runtime;
removeMinFaceFilter = 1;
}
// Set up shatter
RFShatter shatter = SetShatter (
fragmentMode,
shatterMode,
mesh,
scrShatter.transform,
scrShatter.material,
scrShatter.advanced.decompose,
scrShatter.advanced.removeCollinear,
scrShatter.advanced.seed,
scrShatter.advanced.inputPrecap,
scrShatter.advanced.outputPrecap,
scrShatter.advanced.removeDoubleFaces,
scrShatter.advanced.inner,
scrShatter.advanced.smooth,
scrShatter.advanced.elementSizeThreshold,
removeMinFaceFilter,
scrShatter.advanced.postWeld);
// Failed input
if (shatter == null)
{
meshes = null;
pivots = null;
return;
}
// Get innerSubId
int innerSubId = RFSurface.SetInnerSubId (scrShatter);
// Set fragmentation properties
SetShatterFragmentProperties (shatter, scrShatter);
// Custom/HexGrid points check
if (NoCustomPoints (scrShatter) == true)
{
Debug.Log ("Point Cloud is empty");
meshes = null;
pivots = null;
return;
}
// Calculate fragments
List<Dictionary<int, int>> origSubMeshIds = new List<Dictionary<int, int>>();
bool successState = Compute (
shatterMode,
shatter,
scrShatter.transform,
ref meshes,
ref pivots,
mesh,
innerSubId,
ref origSubMeshIds,
scrShatter);
// Create RF dictionary
if (origSubMeshIds != null)
rfOrigSubMeshIds = RFDictionary.GetRFDictionary (origSubMeshIds);
// Failed fragmentation. Increase bad mesh
if (successState == false)
{
Debug.Log ("Bad shatter output mesh: " + scrShatter.name);
return;
}
// Filter out planar meshes
RFShatterAdvanced.RemovePlanar (ref meshes, ref pivots, ref rfOrigSubMeshIds, scrShatter);
// Filter out meshes by size
RFShatterAdvanced.RemoveBySize (ref meshes, ref pivots, ref rfOrigSubMeshIds, scrShatter);
// Set name
string nameApp = scrShatter.name + "_";
for (int i = 0; i < meshes.Length; i++)
meshes[i].name = nameApp + i;
/*
// Bake collider meshes
if (scrShatter.advanced.bake == true)
{
Debug.Log ("bake");
for (int i = 0; i < meshes.Length; i++)
Physics.BakeMesh (meshes[i].GetInstanceID(), true);
}
*/
}
// Check for no custom or hex grid points
static bool NoCustomPoints(RayfireShatter scrShatter)
{
if (scrShatter.type == FragType.Custom && scrShatter.custom.noPoints == true)
return true;
if (scrShatter.type == FragType.Hexagon && scrShatter.hexagon.noPc == true)
return true;
return false;
}
/// /////////////////////////////////////////////////////////
/// Rigid
/// /////////////////////////////////////////////////////////
// Prepare rigid component to cache fragment meshes
public static bool InputMesh(RayfireRigid scr)
{
// Set up shatter
if (SetRigidShatter (scr) == false)
return false;
// Get innerSubId
scr.meshDemolition.innerSubId = RFSurface.SetInnerSubId (scr);
// Set fragmentation properties
SetRigidFragmentProperties (scr.meshDemolition.rfShatter, scr.meshDemolition.sht, scr);
return true;
}
// Set up rigid shatter
static bool SetRigidShatter(RayfireRigid scr)
{
// Set up shatter
if (scr.meshDemolition.rfShatter == null)
{
// Save rotation at caching to fix fragments rotation at demolition
scr.cacheRotation = scr.transForm.rotation;
// Turn off fast mode for tets and slices
scr.meshDemolition.shatterMode = GetShatterMode (scr.meshDemolition.sht);
// Get innerSubId
scr.meshDemolition.mesh = GetDemolitionMesh (scr);
// Get shatter
scr.meshDemolition.rfShatter = SetShatter (
FragmentMode.Runtime,
scr.meshDemolition.shatterMode,
scr.meshDemolition.mesh,
scr.transform,
scr.materials,
scr.meshDemolition.prp.dec,
scr.meshDemolition.prp.rem,
scr.meshDemolition.sd,
true,
false,
false,
false,
false,
3, // elementSizeThreshold
4, // RemoveMinFaceFilter
true);
}
// Failed input. Instant bad mesh.
if (scr.meshDemolition.rfShatter == null)
{
scr.limitations.demolitionShould = false;
scr.meshDemolition.badMesh += 10;
scr.meshDemolition.mesh = null;
return false;
}
return true;
}
// Cache for rigid
public static void CacheMeshesInst(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] rfOrigSubMeshIds, RayfireRigid scrRigid)
{
// Local data lists
List<Dictionary<int, int>> origSubMeshIds = new List<Dictionary<int, int>>();
// Calculate fragments
bool successState = Compute (
scrRigid.meshDemolition.shatterMode,
scrRigid.meshDemolition.rfShatter,
scrRigid.transform,
ref meshes,
ref pivots,
scrRigid.meshDemolition.mesh,
scrRigid.meshDemolition.innerSubId,
ref origSubMeshIds,
scrRigid);
// Create RF dictionary
if (origSubMeshIds != null)
rfOrigSubMeshIds = RFDictionary.GetRFDictionary (origSubMeshIds);
// Failed fragmentation. Increase bad mesh
if (successState == false)
{
scrRigid.meshDemolition.badMesh++;
Debug.Log ("Bad mesh: " + scrRigid.name);
}
// Mesh naming
else
for (int i = 0; i < meshes.Length; i++)
meshes[i].name = i.ToString();
}
// Cache for rigid
public static void CacheMeshesMult(Transform tmSaved, ref List<Mesh> meshesList, ref List<Vector3> pivotsList, ref List<RFDictionary> subList, RayfireRigid scrRigid, List<int> batchAmount, int batchInd)
{
// Get list of meshes to calc
List<int> markedElements = RFRuntimeCaching.GetMarkedElements (batchInd, batchAmount);
// Local iteration data lists
Mesh[] meshesLocal = new Mesh[batchAmount.Count];
Vector3[] pivotsLocal = new Vector3[batchAmount.Count];
List<Dictionary<int, int>> origSubMeshIds = new List<Dictionary<int, int>>();
// Compute
bool state = scrRigid.meshDemolition.rfShatter.SimpleCompute (
tmSaved,
ref meshesLocal,
ref pivotsLocal,
scrRigid.meshDemolition.mesh,
scrRigid.meshDemolition.innerSubId,
ref origSubMeshIds,
markedElements,
batchInd == 0);
// Set names
if (state == false || meshesLocal == null || meshesLocal.Length == 0)
return;
// Set names
for (int i = 0; i < meshesLocal.Length; i++)
{
meshesLocal[i].RecalculateTangents();
meshesLocal[i].name = scrRigid.name + "_fr"; // + markedElements[i].ToString();
}
// Add data to main lists
for (int i = 0; i < origSubMeshIds.Count; i++)
subList.Add (new RFDictionary (origSubMeshIds[i]));
meshesList.AddRange (meshesLocal);
pivotsList.AddRange (pivotsLocal);
}
// Get demolition mesh
static Mesh GetDemolitionMesh(RayfireRigid scr)
{
if (scr.skr != null)
return RFMesh.BakeMesh (scr.skr);
return scr.meshFilter.sharedMesh;
}
// Get demolition mesh
static Mesh GetDemolitionMesh(RayfireShatter scr)
{
// Multymesh fragmentation
if (scr.advanced.combineChildren == true && scr.meshFilters.Count > 0)
return RFCombineMesh.CombineShatter (scr, scr.transform, scr.meshFilters);
// Skinned mesh
if (scr.skinnedMeshRend != null)
return RFMesh.BakeMesh (scr.skinnedMeshRend);
return scr.meshFilter.sharedMesh;
}
/// /////////////////////////////////////////////////////////
/// Slice
/// /////////////////////////////////////////////////////////
// Cache for slice
public static void SliceMeshes(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] rfOrigSubMeshIds, RayfireRigid scr, List<Vector3> sliceData)
{
// Get mesh
scr.meshDemolition.mesh = GetDemolitionMesh (scr);
// Set up shatter
RFShatter shatter = SetShatter (
FragmentMode.Runtime,
2,
scr.meshDemolition.mesh,
scr.transform,
scr.materials,
true,
scr.meshDemolition.prp.rem,
scr.meshDemolition.sd,
true,
false,
false,
false,
false,
3, // ElementSizeThreshold
1, // RemoveMinFaceFilter
true);
// Debug.Log ("slice");
// Failed input
if (shatter == null)
{
meshes = null;
pivots = null;
scr.meshDemolition.badMesh++;
return;
}
// Get innerSubId
scr.meshDemolition.innerSubId = RFSurface.SetInnerSubId (scr);
// Get slice data
List<Vector3> points = new List<Vector3> (sliceData.Count / 2);
List<Vector3> norms = new List<Vector3> (sliceData.Count / 2);
for (int i = 0; i < sliceData.Count; i++)
{
points.Add (sliceData[i]);
norms.Add (sliceData[i + 1]);
i++;
}
// Set params
shatter.SetBricksParams (points.ToArray(), norms.ToArray(), scr.transform);
// Calculate fragments
List<Dictionary<int, int>> origSubMeshIds = new List<Dictionary<int, int>>();
bool successState = Compute (
2,
shatter,
scr.transform,
ref meshes,
ref pivots,
scr.meshDemolition.mesh,
scr.meshDemolition.innerSubId,
ref origSubMeshIds,
scr.gameObject);
// Create RF dictionary
if (origSubMeshIds != null)
rfOrigSubMeshIds = RFDictionary.GetRFDictionary (origSubMeshIds);
// Failed fragmentation. Increase bad mesh
if (successState == false)
{
scr.meshes = null;
scr.meshDemolition.badMesh++;
Debug.Log ("Bad mesh: " + scr.name, scr.gameObject);
}
else
{
for (int i = 0; i < meshes.Length; i++)
meshes[i].name = i.ToString();
}
}
/// /////////////////////////////////////////////////////////
/// Compute
/// /////////////////////////////////////////////////////////
// Compute
static bool Compute(int shatterMode, RFShatter shatter, Transform tm, ref Mesh[] meshes, ref Vector3[] pivots,
Mesh mesh, int innerSubId, ref List<Dictionary<int, int>> origSubMeshIDs, Object obj, List<int> markedElements = null)
{
// Compute fragments
bool state = shatterMode == 0
? shatter.Compute (tm, ref meshes, ref pivots, mesh, innerSubId, ref origSubMeshIDs)
: shatter.SimpleCompute (tm, ref meshes, ref pivots, mesh, innerSubId, ref origSubMeshIDs, markedElements);
// Mesh singleMesh = RFShatter.WeldMeshes (ref meshes, ref pivots, ref origSubMeshIDs, 0.5f);
// Failed fragmentation
if (state == false)
{
meshes = null;
pivots = null;
origSubMeshIDs = null;
return false;
}
// Null check
if (meshes == null)
{
Debug.Log ("RFShatter: Null mesh", obj);
meshes = null;
pivots = null;
origSubMeshIDs = null;
return false;
}
// Empty mesh fix
if (EmptyMeshState (meshes) == true)
{
for (int i = 0; i < meshes.Length; i++)
{
if (meshes[i].vertexCount > 2)
{
meshListStatic.Add (meshes[i]);
pivotListStatic.Add (pivots[i]);
subIdsListStatic.Add (origSubMeshIDs[i]);
}
}
pivots = pivotListStatic.ToArray();
meshes = meshListStatic.ToArray();
origSubMeshIDs = subIdsListStatic;
meshListStatic.Clear();
pivotListStatic.Clear();
subIdsListStatic.Clear();
Debug.Log ("RFShatter: Empty Mesh", obj);
}
// Single mesh after mesh fix check
if (meshes.Length <= 1)
{
Debug.Log ("RFShatter: Mesh amount " + meshes.Length, obj);
meshes = null;
pivots = null;
origSubMeshIDs = null;
return false;
}
// Post
for (int i = 0; i < meshes.Length; i++)
{
//Debug.Log(meshes[i].vertexCount);
//meshes[i].indexFormat = IndexFormat.UInt32;
meshes[i].RecalculateTangents();
}
return true;
}
// Get shatter mode
// 0:classic: Custom, tets, clustering: old original algorithm.
// 1:voro simple: Decompose type or Rigid without Shatter.
// 2:slice
// 3:bricks
static int GetShatterMode(RayfireShatter scrShatter = null)
{
// Voro Simple mode: for rigid without shatter
if (scrShatter == null)
return 1;
// Brick Simple mode
if (scrShatter.type == FragType.Slices)
return 2;
// Voro Simple mode
if (scrShatter.type == FragType.Decompose)
return 1;
// Voro Simple mode
if (scrShatter.type == FragType.Bricks || scrShatter.type == FragType.Voxels)
if (scrShatter.type == FragType.Bricks || scrShatter.type == FragType.Voxels)
return 3;
// Classic mode
int shatterMode = scrShatter.shatterMode;
if (scrShatter.type == FragType.Hexagon)
shatterMode = 0;
if (scrShatter.type == FragType.Custom)
shatterMode = 0;
//if (scrShatter.type == FragType.Mirrored)
// shatterMode = 0;
if (scrShatter.type == FragType.Tets)
shatterMode = 0;
// Classic way for clustering. Not for slices
if (scrShatter.clusters.enable == true)
shatterMode = 0;
return shatterMode;
}
// Check for at least one empty mesh in cached meshes
static bool EmptyMeshState(Mesh[] meshes)
{
for (int i = 0; i < meshes.Length; i++)
if (meshes[i].vertexCount <= 2)
return true;
return false;
}
/// /////////////////////////////////////////////////////////
/// Set properties by fragment type
/// /////////////////////////////////////////////////////////
// Set fragmentation properties
static void SetShatterFragmentProperties(RFShatter shatter, RayfireShatter scrSh)
{
// Center position from local to global
Vector3 centerPos = scrSh.transform.TransformPoint (scrSh.centerPosition);
// Clustering
if (scrSh.clusters.enable == true)
SetClusters (shatter, scrSh.clusters);
// Set properties
if (scrSh.type == FragType.Voronoi)
SetVoronoi (shatter, scrSh.voronoi.Amount, scrSh.transform, centerPos, scrSh.voronoi.centerBias);
else if (scrSh.type == FragType.Splinters)
SetSplinters (shatter, scrSh.splinters.Amount, scrSh.splinters, scrSh.transform, centerPos, scrSh.splinters.centerBias);
else if (scrSh.type == FragType.Slabs)
SetSlabs (shatter, scrSh.slabs.Amount, scrSh.slabs, scrSh.transform, centerPos, scrSh.splinters.centerBias);
else if (scrSh.type == FragType.Radial)
SetRadial (shatter, scrSh.radial, scrSh.transform, centerPos, scrSh.centerDirection);
else if (scrSh.type == FragType.Hexagon)
SetHexGrid (shatter, scrSh.hexagon, scrSh.transform, centerPos, scrSh.centerDirection, scrSh.bound, scrSh.advanced.seed);
else if (scrSh.type == FragType.Custom)
SetCustom (shatter, scrSh.custom, scrSh.transform, scrSh.bound, scrSh.advanced.seed);
// else if (scrSh.type == FragType.Mirrored)
// SetMirrored (shatter, scrSh.mirrored, scrSh.transform, scrSh.bound, scrSh.advanced.seed);
else if (scrSh.type == FragType.Slices)
SetSlices (shatter, scrSh.transform, scrSh.slice);
else if (scrSh.type == FragType.Bricks)
SetBricks (shatter, scrSh.transform, scrSh.bricks, scrSh.bound);
else if (scrSh.type == FragType.Voxels)
SetVoxels (shatter, scrSh.transform, scrSh.voxels, scrSh.bound);
else if (scrSh.type == FragType.Tets)
SetTet (shatter, scrSh.bound, scrSh.tets);
else if (scrSh.type == FragType.Decompose)
SetDecompose (shatter);
}
// Set fragmentation properties
static void SetRigidFragmentProperties(RFShatter shatter, RayfireShatter scrSh, RayfireRigid scrRigid)
{
// Rigid demolition without shatter. Set and exit.
if (scrSh == null)
{
// Get final amount
int percVar = Random.Range (0, scrRigid.meshDemolition.am * scrRigid.meshDemolition.var / 100);
scrRigid.meshDemolition.totalAmount = scrRigid.meshDemolition.am + percVar;
// Set Voronoi Uniform properties
SetVoronoi (shatter, scrRigid.meshDemolition.totalAmount, scrRigid.transform, scrRigid.limitations.contactVector3, scrRigid.meshDemolition.bias);
return;
}
// Set shatter center as contact point for awake precache and prefragment
if (scrRigid.limitations.contactVector3.magnitude == 0)
scrRigid.limitations.contactVector3 = scrSh.transform.TransformPoint (scrSh.centerPosition);
// Set total amount by rigid component
if (scrSh.type == FragType.Voronoi)
scrRigid.meshDemolition.totalAmount = scrSh.voronoi.Amount;
else if (scrSh.type == FragType.Splinters)
scrRigid.meshDemolition.totalAmount = scrSh.splinters.Amount;
else if (scrSh.type == FragType.Slabs)
scrRigid.meshDemolition.totalAmount = scrSh.slabs.Amount;
// Get final amount with variation
if (scrRigid.meshDemolition.var > 0)
{
int percVar = Random.Range (0, scrRigid.meshDemolition.totalAmount * scrRigid.meshDemolition.var / 100);
scrRigid.meshDemolition.totalAmount += percVar;
}
// Clustering
if (scrSh.clusters.enable == true)
SetClusters (shatter, scrSh.clusters);
// Set properties
if (scrSh.type == FragType.Voronoi)
SetVoronoi (shatter, scrRigid.meshDemolition.totalAmount, scrSh.transform, scrRigid.limitations.contactVector3, scrSh.voronoi.centerBias);
else if (scrSh.type == FragType.Splinters)
SetSplinters (shatter, scrRigid.meshDemolition.totalAmount, scrSh.splinters, scrSh.transform, scrRigid.limitations.contactVector3, scrSh.splinters.centerBias);
else if (scrSh.type == FragType.Slabs)
SetSlabs (shatter, scrRigid.meshDemolition.totalAmount, scrSh.slabs, scrSh.transform, scrRigid.limitations.contactVector3, scrSh.splinters.centerBias);
else if (scrSh.type == FragType.Radial)
SetRadial (shatter, scrSh.radial, scrSh.transform, scrRigid.limitations.contactVector3, scrSh.centerDirection);
else if (scrSh.type == FragType.Custom)
SetCustom (shatter, scrSh.custom, scrSh.transform, scrSh.bound, scrSh.advanced.seed);
// else if (scrSh.type == FragType.Mirrored)
// SetMirrored (shatter, scrSh.mirrored, scrSh.transform, scrSh.bound, scrSh.advanced.seed);
else if (scrSh.type == FragType.Slices)
SetSlices (shatter, scrSh.transform, scrSh.slice);
else if (scrSh.type == FragType.Bricks)
SetBricks (shatter, scrSh.transform, scrSh.bricks, scrSh.bound);
else if (scrSh.type == FragType.Voxels)
SetVoxels (shatter, scrSh.transform, scrSh.voxels, scrSh.bound);
else if (scrSh.type == FragType.Tets)
SetTet (shatter, scrSh.bound, scrSh.tets);
else if (scrSh.type == FragType.Decompose)
SetDecompose (shatter);
}
/// /////////////////////////////////////////////////////////
/// Properties setup
/// /////////////////////////////////////////////////////////
// Set common fragmentation properties
static RFShatter SetShatter(
FragmentMode fragmentMode,
int shatterMode,
Mesh mesh,
Transform transform,
RFSurface interior,
bool decompose,
bool delete_collinear = false,
int seed = 1,
bool pre_cap = true,
bool remove_cap_faces = false,
bool remove_double_faces = true,
bool exclude_inside = false,
bool post_normals_smooth = false,
int min_bbox_diag_size_filter_perc = 3,
int meshRemoveMinFaceFilter = 4,
bool postWeld = true
)
{
// Creating shatter
RFShatter shatter = new RFShatter ((RFShatter.RFShatterMode)shatterMode, true);
// Safe/unsafe properties
if (fragmentMode == FragmentMode.Editor)
{
float min_bbox_diag_size_filter = mesh.bounds.size.magnitude * min_bbox_diag_size_filter_perc / 100f; // TODO check render bound size
SetShatterEditorMode (shatter, min_bbox_diag_size_filter, pre_cap, remove_cap_faces, remove_double_faces, exclude_inside, meshRemoveMinFaceFilter);
}
else
{
SetShatterRuntimeMode (shatter, pre_cap, meshRemoveMinFaceFilter);
}
// Detach by elements
shatter.DecomposeResultMesh (decompose);
// Set custom UV coordinate for inner surface
SetCustomUV (shatter, interior);
// Set custom vertex color for inner surface
SetCustomColor (shatter, interior);
// Set silent mode
shatter.SilentModeEnable (silentMode);
// Set seed
if (seed == 0)
seed = Random.Range (0, 100);
// Set properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.seed, seed);
shatter.SetGeneralParameter (RFShatter.GeneralParams.pre_weld_threshold, 0.001f);
shatter.SetGeneralParameter (RFShatter.GeneralParams.delete_collinear, delete_collinear);
shatter.SetGeneralParameter (RFShatter.GeneralParams.post_normals_smooth, post_normals_smooth);
shatter.SetGeneralParameter (RFShatter.GeneralParams.post_weld, false);
shatter.SetGeneralParameter (RFShatter.GeneralParams.maping_scale, interior.mScl);
shatter.SetGeneralParameter (RFShatter.GeneralParams.restore_normals, true);
// Setting shatter params
bool inputState = shatter.SetInputMesh (transform, mesh);
// Failed input
if (inputState == false)
{
Debug.Log ("Bad input mesh: " + transform.name, transform.gameObject);
return null;
}
return shatter;
}
// Set Shatter Editor Mode properties
static void SetShatterEditorMode(
RFShatter shatter,
float min_bbox_diag_size_filter,
bool pre_cap,
bool remove_cap_faces,
bool remove_double_faces,
bool exclude_inside,
int meshRemoveMinFaceFilter)
{
shatter.EditorMode (true);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_min_bbox_diag_size_filter, min_bbox_diag_size_filter);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_pre_cap, pre_cap);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_remove_cap_faces, remove_cap_faces);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_remove_double_faces, remove_double_faces);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_remove_inversed_double_faces, remove_double_faces);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_exclude_inside, exclude_inside);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_meshRemoveMinFaceFilter, meshRemoveMinFaceFilter); // Minimum amount of triangles for element to be fragmented, will be removed otherwise
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_elliminateCollinears_maxIterFuse, 150);
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_separate_only, false);
shatter.SetGeneralParameter (RFShatter.GeneralParams.minFacesFilter, 0);
}
// Set Shatter Runtime Mode properties
static void SetShatterRuntimeMode(RFShatter shatter, bool pre_cap, int meshRemoveMinFaceFilter)
{
shatter.EditorMode (false);
shatter.SetGeneralParameter (RFShatter.GeneralParams.pre_shatter, true);
shatter.SetGeneralParameter (RFShatter.GeneralParams.pre_cap, pre_cap);
shatter.SetGeneralParameter (RFShatter.GeneralParams.pre_weld, true);
shatter.SetGeneralParameter (RFShatter.GeneralParams.minFacesFilter, 3);
shatter.SetGeneralParameter (RFShatter.GeneralParams.meshRemoveMinFaceFilter, meshRemoveMinFaceFilter);
}
// Set custom UV coordinate for inner surface
static void SetCustomUV(RFShatter shatter, RFSurface interior)
{
shatter.SetGeneralParameter (RFShatter.GeneralParams.enable_custUVs, interior.uvE);
if (interior.uvE == true)
shatter.SetPoint3Parameter ((int)RFShatter.GeneralParams.cust_UVs, new Vector3 (interior.uvC.x, interior.uvC.y, 0));
}
// Set custom vertex color for inner surface
static void SetCustomColor(RFShatter shatter, RFSurface interior)
{
if (interior.cE == true)
{
Vector3 vc = new Vector3 (interior.cC.r, interior.cC.g, interior.cC.b);
shatter.SetPoint3Parameter ((int)RFShatter.GeneralParams.inner_color, vc);
}
}
/// /////////////////////////////////////////////////////////
/// Fragmentation types
/// /////////////////////////////////////////////////////////
// Set Uniform
static void SetVoronoi(RFShatter shatter, int numFragments, Transform tm, Vector3 centerPos, float centerBias)
{
// Get amount
int amount = numFragments;
if (amount < 1)
amount = 1;
if (amount > 20000)
amount = 2;
// Set properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.irregular);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_irr_num, amount);
// Set bias to center
if (centerBias > 0)
{
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_irr_bias, centerBias);
shatter.SetCenterParameter (centerPos, tm, Vector3.forward);
}
}
// Set Splinters
static void SetSplinters(RFShatter shatter, int numFragments, RFSplinters splint, Transform tm, Vector3 centerPos, float centerBias)
{
// Set properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.irregular);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_irr_num, numFragments);
// Set center
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_irr_bias, centerBias);
shatter.SetCenterParameter (centerPos, tm, Vector3.forward);
// Set Stretching for slabs
SetStretching (shatter, splint.axis, splint.strength, FragType.Splinters);
}
// Set Slabs
static void SetSlabs(RFShatter shatter, int numFragments, RFSplinters slabs, Transform tm, Vector3 centerPos, float centerBias)
{
// Set properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.irregular);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_irr_num, numFragments);
// Set center
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_irr_bias, centerBias);
shatter.SetCenterParameter (centerPos, tm, Vector3.forward);
// Set Stretching for slabs
SetStretching (shatter, slabs.axis, slabs.strength, FragType.Slabs);
}
// Set Radial
static void SetRadial(RFShatter shatter, RFRadial radial, Transform tm, Vector3 centerPos, Quaternion centerDirection)
{
// Set radial properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.radial);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_radius, radial.radius);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_divergence, radial.divergence);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_restrict, radial.restrictToPlane);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_rings_count, radial.rings);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_rings_focus, radial.focus);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_rings_strenght, radial.focusStr);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_rings_random, radial.randomRings);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_rays_count, radial.rays);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_rays_random, radial.randomRays);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_rad_rays_twist, radial.twist);
// Get direction axis
Vector3 directionAxis = DirectionAxis (radial.centerAxis);
Vector3 centerRot = tm.rotation * centerDirection * directionAxis;
shatter.SetCenterParameter (centerPos, tm, centerRot);
}
// Set hexgrid custom point cloud
static void SetHexGrid(RFShatter shatter, RFHexagon hexagon, Transform tm, Vector3 centerPos, Quaternion centerDirection, Bounds bound, int seed)
{
// Set properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.custom);
// Get Point Cloud
List<Vector3> pointCloud = RFHexagon.GetHexPointCLoud (hexagon, tm, centerPos, centerDirection, seed, bound);
// Set points
shatter.SetVoroCustomPoints (pointCloud.ToArray(), tm);
}
// Set custom point cloud
static void SetCustom(RFShatter shatter, RFCustom custom, Transform tm, Bounds bound, int seed)
{
// Set properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.custom);
// Get Point Cloud
List<Vector3> pointCloud = RFCustom.GetCustomPointCLoud (custom, tm, seed, bound);
// Set points
shatter.SetVoroCustomPoints (pointCloud.ToArray(), tm);
// Set Stretching TODO point cloud rescale by transform
// if (custom.modifier == RFCustom.RFModifierType.Splinters)
// SetStretching (shatter, splint.axis, splint.strength, FragType.Splinters);
// else if (custom.modifier == RFCustom.RFModifierType.Slabs)
// SetStretching (shatter, slabs.axis, slabs.strength, FragType.Slabs);
}
// Set custom mirrored point cloud
static void SetMirrored(RFShatter shatter, RFMirrored mirror, Transform tm, Bounds bound, int seed)
{
// Set properties
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi);
shatter.SetFragmentParameter (RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.custom);
// Get Point Cloud
List<Vector3> pointCloud = RFMirrored.GetMirroredPointCLoud (mirror, tm, seed, bound);
// Set points
shatter.SetVoroCustomPoints (pointCloud.ToArray(), tm);
}
// Set slicing objects
static void SetSlices(RFShatter shatter, Transform tm, RFSlice slices)
{
// Filter
List<Transform> list = new List<Transform>();
for (int i = 0; i < slices.sliceList.Count; i++)
if (slices.sliceList[i] != null)
list.Add (slices.sliceList[i]);
// No objects
if (list.Count == 0)
return;
// Get slice data
Vector3[] points = list.Select (t => t.position).ToArray();
Vector3[] norms = list.Select (t => slices.Axis (t)).ToArray();
// Set params
shatter.SetBricksParams (points, norms, tm);
}
// Set bricks properties
static void SetBricks(RFShatter shatter, Transform tm, RFBricks bricks, Bounds bounds)
{
// Amount size
if (bricks.amountType == RFBricks.RFBrickType.ByAmount)
{
float X = bricks.amount_X * bricks.mult;
if (X == 0) X = 1;
float Y = bricks.amount_Y * bricks.mult;
if (Y == 0) Y = 1;
float Z = bricks.amount_Z * bricks.mult;
if (Z == 0) Z = 1;
Vector3 amount = new Vector3 (X, Y, Z);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_num_bricks, amount);
}
else if (bricks.amountType == RFBricks.RFBrickType.BySize)
{
// TODO small size check
Vector3 size = new Vector3 (bricks.size_X * bricks.mult, bricks.size_Y * bricks.mult, bricks.size_Z * bricks.mult);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_num_bricks, Vector3.zero);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_brick_size, size);
}
// Random size
Vector3 random_size = new Vector3 (bricks.sizeVar_X / 100f, bricks.sizeVar_Y / 100f, bricks.sizeVar_Z / 100f);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_random_size, random_size);
// Offset
Vector3 offsets = new Vector3 (bricks.offset_X, bricks.offset_Y, bricks.offset_Z);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_offsets, offsets); // 0-1
// Split
Vector3 random_split = new Vector3 (BoolToFloat (bricks.split_X), BoolToFloat (bricks.split_Y), BoolToFloat (bricks.split_Z));
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_random_split, random_split);
shatter.SetFragmentParameter (RFShatter.FragmentParams.brick_slice_probability, bricks.split_probability * 0.01f);
shatter.SetFragmentParameter (RFShatter.FragmentParams.brick_slice_offset, bricks.split_offset);
shatter.SetFragmentParameter (RFShatter.FragmentParams.brick_slice_rotate, bricks.split_rotation);
}
// Set voxels properties
static void SetVoxels(RFShatter shatter, Transform tm, RFVoxels voxels, Bounds bounds)
{
// TODO small size check
Vector3 size = new Vector3 (voxels.size, voxels.size, voxels.size);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_num_bricks, Vector3.zero);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_brick_size, size);
// Offset
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.bricks_offsets, Vector3.zero);
}
static float BoolToFloat(bool v)
{
if (v == false) return 0;
return 1f;
}
// Set Custom Voronoi properties
static void SetTet(RFShatter shatter, Bounds bounds, RFTets tets)
{
// Main
shatter.SetFragmentParameter (RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.tetra);
shatter.SetFragmentParameter (RFShatter.FragmentParams.tetra_type, (int)tets.lattice);
// Get max
float max = bounds.size.x;
if (bounds.size.y > max)
max = bounds.size.y;
if (bounds.size.z > max)
max = bounds.size.z;
if (max == 0)
max = 0.01f;
// Get density
Vector3Int density = new Vector3Int (
(int)Mathf.Ceil (bounds.size.x / max * tets.density),
(int)Mathf.Ceil (bounds.size.y / max * tets.density),
(int)Mathf.Ceil (bounds.size.z / max * tets.density));
// Limit
if (density.x > 30) density.x = 30;
else if (density.x < 1) density.x = 1;
if (density.y > 30) density.y = 30;
else if (density.y < 1) density.y = 1;
if (density.z > 30) density.z = 30;
else if (density.z < 1) density.z = 1;
// Set density
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.tetra2_density, density);
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.tetra1_density, density);
// Noise
shatter.SetFragmentParameter (RFShatter.FragmentParams.tetra_noise, tets.noise);
}
// Decompose to elements
static void SetDecompose(RFShatter shatter)
{
shatter.SetGeneralParameter (RFShatter.GeneralParams.editor_mode_separate_only, true);
}
/// /////////////////////////////////////////////////////////
/// Clusters
/// /////////////////////////////////////////////////////////
// Set clusters
static void SetClusters(RFShatter shatter, RFShatterCluster gluing)
{
// Set seed
int glueSeed = gluing.seed;
if (glueSeed == 0)
glueSeed = Random.Range (0, 1000);
shatter.InitClustering (true);
shatter.SetClusterParameter (RFShatter.ClusterParams.enabled, true);
shatter.SetClusterParameter (RFShatter.ClusterParams.by_pcloud_count, gluing.count);
shatter.SetClusterParameter (RFShatter.ClusterParams.options_seed, glueSeed);
shatter.SetClusterParameter (RFShatter.ClusterParams.preview_scale, 100f);
// shatter.SetClusterParameter(RFShatter.ClusterParams.clust_center_tm, );
// Debris
shatter.SetClusterParameter (RFShatter.ClusterParams.debris_layers_count, gluing.layers);
shatter.SetClusterParameter (RFShatter.ClusterParams.debris_count, gluing.amount);
shatter.SetClusterParameter (RFShatter.ClusterParams.debris_scale, gluing.scale);
shatter.SetClusterParameter (RFShatter.ClusterParams.debris_min, gluing.min);
shatter.SetClusterParameter (RFShatter.ClusterParams.debris_max, gluing.max);
shatter.SetClusterParameter (RFShatter.ClusterParams.debris_tessellate, false);
shatter.SetClusterParameter (RFShatter.ClusterParams.debris_remove, false);
// Glue
shatter.SetGeneralParameter (RFShatter.GeneralParams.glue, true);
shatter.SetGeneralParameter (RFShatter.GeneralParams.glue_weld_threshold, 0.001f);
shatter.SetGeneralParameter (RFShatter.GeneralParams.relax, gluing.relax);
}
/// /////////////////////////////////////////////////////////
/// Stretching
/// /////////////////////////////////////////////////////////
// Set stretching
static void SetStretching(RFShatter shatter, AxisType axis, float strength, FragType fragType)
{
// Get slab vector
Vector3 stretchDir = DirectionAxis (axis);
// Adjust for slabs
if (fragType == FragType.Slabs)
{
Vector3 vector = new Vector3();
if (stretchDir.x <= 0) vector.x = 1f;
if (stretchDir.x >= 1f) vector.x = 0;
if (stretchDir.y <= 0) vector.y = 1f;
if (stretchDir.y >= 1f) vector.y = 0;
if (stretchDir.z <= 0) vector.z = 1f;
if (stretchDir.z >= 1f) vector.z = 0;
stretchDir = vector;
}
// Set stretch vector
shatter.SetPoint3Parameter ((int)RFShatter.FragmentParams.stretching, stretchDir * Mathf.Lerp (40f, 99f, strength));
}
// Get axis by type
static Vector3 DirectionAxis(AxisType axisType)
{
if (axisType == AxisType.YGreen)
return Vector3.up;
if (axisType == AxisType.ZBlue)
return Vector3.forward;
return Vector3.right;
}
/// /////////////////////////////////////////////////////////
/// Mesh
/// /////////////////////////////////////////////////////////
// Scale mesh
public static void RescaleMesh(Mesh mesh, float scale)
{
Vector3[] verts = mesh.vertices;
for (int j = 0; j < verts.Length; j++)
verts[j] /= scale;
mesh.vertices = verts;
}
}
}
// Static dummy class for other platforms
#else
namespace RayFire
{
public static class RFFragment
{
public static bool PrepareCacheMeshes(RayfireRigid scr)
{
BuildTest(scr);
return false;
}
public static void CacheMeshesMult(Transform tmSaved, ref List<Mesh> meshesList, ref List<Vector3> pivotsList, ref List<RFDictionary> subList, RayfireRigid scrRigid, List<int> batchAmount, int batchInd)
{
BuildTest();
}
public static void CacheMeshesInst(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] origSubMeshIdsRf, RayfireRigid scrRigid)
{
BuildTest();
}
public static void CacheMeshes(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] origSubMeshIdsRf, RayfireShatter scrShatter)
{
BuildTest();
}
public static void SliceMeshes(ref Mesh[] meshes, ref Vector3[] pivots, ref RFDictionary[] origSubMeshIdsRf, RayfireRigid scrRigid, List<Vector3> sliceData)
{
BuildTest();
}
public static void RescaleMesh (Mesh mesh, float scale)
{
BuildTest();
}
public static bool InputMesh(RayfireRigid scr)
{
BuildTest();
scr.meshes = null;
return false;
}
static void BuildTest(RayfireRigid scr)
{
//Debug.Log ("Dummy");
}
static void BuildTest()
{
//Debug.Log ("Dummy");
}
}
public class RFShatter{}
}
#endif