743 lines
25 KiB
C#
743 lines
25 KiB
C#
|
using System;
|
|||
|
using System.Linq;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
#if (UNITY_EDITOR || UNITY_STANDALONE || UNITY_IOS || UNITY_ANDROID || UNITY_XBOXONE)
|
|||
|
using RayFire.DotNet;
|
|||
|
#endif
|
|||
|
|
|||
|
namespace RayFire
|
|||
|
{
|
|||
|
[AddComponentMenu ("RayFire/Rayfire Shatter")]
|
|||
|
[HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-shatter-component/")]
|
|||
|
public class RayfireShatter : MonoBehaviour
|
|||
|
{
|
|||
|
public enum RFEngineType
|
|||
|
{
|
|||
|
Max = 0,
|
|||
|
UnityBeta = 1
|
|||
|
}
|
|||
|
|
|||
|
public enum FragLastMode
|
|||
|
{
|
|||
|
New = 0,
|
|||
|
ToLast = 1
|
|||
|
}
|
|||
|
|
|||
|
// UI
|
|||
|
public RFEngineType engine = RFEngineType.Max;
|
|||
|
public FragType type = FragType.Voronoi;
|
|||
|
public RFVoronoi voronoi = new RFVoronoi();
|
|||
|
public RFSplinters splinters = new RFSplinters();
|
|||
|
public RFSplinters slabs = new RFSplinters();
|
|||
|
public RFRadial radial = new RFRadial();
|
|||
|
public RFHexagon hexagon = new RFHexagon();
|
|||
|
public RFCustom custom = new RFCustom();
|
|||
|
public RFMirrored mirrored = new RFMirrored();
|
|||
|
public RFSlice slice = new RFSlice();
|
|||
|
public RFBricks bricks = new RFBricks();
|
|||
|
public RFVoxels voxels = new RFVoxels();
|
|||
|
public RFTets tets = new RFTets();
|
|||
|
public RFSurface material = new RFSurface();
|
|||
|
public RFShatterCluster clusters = new RFShatterCluster();
|
|||
|
public FragmentMode mode = FragmentMode.Editor;
|
|||
|
public RFShatterAdvanced advanced = new RFShatterAdvanced();
|
|||
|
public RFMeshExport export = new RFMeshExport();
|
|||
|
|
|||
|
// Center
|
|||
|
public bool showCenter;
|
|||
|
public Vector3 centerPosition;
|
|||
|
public Quaternion centerDirection;
|
|||
|
|
|||
|
// Components
|
|||
|
public Transform transForm;
|
|||
|
public MeshFilter meshFilter;
|
|||
|
public MeshRenderer meshRenderer;
|
|||
|
public SkinnedMeshRenderer skinnedMeshRend;
|
|||
|
public List<MeshFilter> meshFilters;
|
|||
|
|
|||
|
// Vars
|
|||
|
[NonSerialized] public Mesh[] meshes;
|
|||
|
[NonSerialized] public Vector3[] pivots;
|
|||
|
[NonSerialized] public RFDictionary[] rfOrigSubMeshIds;
|
|||
|
public List<Transform> rootChildList = new List<Transform>();
|
|||
|
public List<GameObject> fragmentsAll = new List<GameObject>();
|
|||
|
public List<GameObject> fragmentsLast = new List<GameObject>();
|
|||
|
public Material[] materials;
|
|||
|
|
|||
|
// Hidden
|
|||
|
public int shatterMode = 1;
|
|||
|
public bool colorPreview;
|
|||
|
public bool scalePreview = true;
|
|||
|
public float previewScale;
|
|||
|
public float size;
|
|||
|
public float rescaleFix = 1f;
|
|||
|
public Vector3 originalScale;
|
|||
|
public Bounds bound;
|
|||
|
public bool resetState;
|
|||
|
|
|||
|
// Interactive
|
|||
|
public bool interactive;
|
|||
|
public RFShatter shatterInt;
|
|||
|
public GameObject intGo;
|
|||
|
public MeshFilter intMf;
|
|||
|
public MeshRenderer intMr;
|
|||
|
|
|||
|
// Static
|
|||
|
static float minSize = 0.01f;
|
|||
|
public string fragAddStr = "_sh_";
|
|||
|
public string shatterStr = "RayFire Shatter: ";
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Common
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Reset
|
|||
|
private void Reset()
|
|||
|
{
|
|||
|
InteractiveStop();
|
|||
|
ResetCenter();
|
|||
|
}
|
|||
|
|
|||
|
// Set default vars before fragment
|
|||
|
void SetVariables()
|
|||
|
{
|
|||
|
size = 0f;
|
|||
|
rescaleFix = 1f;
|
|||
|
originalScale = transForm.localScale;
|
|||
|
rfOrigSubMeshIds = null;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Checks
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Basic proceed check
|
|||
|
bool MainCheck()
|
|||
|
{
|
|||
|
// Check if prefab
|
|||
|
if (gameObject.scene.rootCount == 0)
|
|||
|
{
|
|||
|
Debug.Log (shatterStr + name + " Can't fragment prefab because prefab unable to store Unity mesh. Fragment prefab in scene.", gameObject);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Single mesh mode
|
|||
|
if (advanced.combineChildren == false)
|
|||
|
if (SingleMeshCheck() == false)
|
|||
|
return false;
|
|||
|
|
|||
|
// Multiple mesh mode
|
|||
|
if (advanced.combineChildren == true)
|
|||
|
{
|
|||
|
// Has no children meshes
|
|||
|
if (meshFilters.Count == 1)
|
|||
|
if (SingleMeshCheck() == false)
|
|||
|
return false;
|
|||
|
|
|||
|
// Remove no meshes
|
|||
|
if (meshFilters.Count > 0)
|
|||
|
for (int i = meshFilters.Count - 1; i >= 0; i--)
|
|||
|
if (meshFilters[i].sharedMesh == null)
|
|||
|
{
|
|||
|
Debug.Log (shatterStr + meshFilters[i].name + " MeshFilter has no Mesh, object excluded.", meshFilters[i].gameObject);
|
|||
|
meshFilters.RemoveAt (i);
|
|||
|
}
|
|||
|
|
|||
|
// Remove no readable meshes
|
|||
|
if (meshFilters.Count > 0)
|
|||
|
for (int i = meshFilters.Count - 1; i >= 0; i--)
|
|||
|
if (meshFilters[i].sharedMesh.isReadable == false)
|
|||
|
{
|
|||
|
Debug.Log (shatterStr + meshFilters[i].name + " Mesh is not Readable, object excluded.", meshFilters[i].gameObject);
|
|||
|
meshFilters.RemoveAt (i);
|
|||
|
}
|
|||
|
|
|||
|
// No meshes left
|
|||
|
if (meshFilters.Count == 0)
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Single mesh mode checks
|
|||
|
bool SingleMeshCheck()
|
|||
|
{
|
|||
|
// No mesh storage components
|
|||
|
if (meshFilter == null && skinnedMeshRend == null)
|
|||
|
{
|
|||
|
Debug.Log (shatterStr + name + " Object has no mesh to fragment.", gameObject);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Has mesh filter
|
|||
|
if (meshFilter != null)
|
|||
|
{
|
|||
|
// No shared mesh
|
|||
|
if (meshFilter.sharedMesh == null)
|
|||
|
{
|
|||
|
Debug.Log (shatterStr + name + " Object has no mesh to fragment.", gameObject);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Not readable mesh
|
|||
|
if (meshFilter.sharedMesh.isReadable == false)
|
|||
|
{
|
|||
|
Debug.Log (shatterStr + name + "Mesh is not readable. Open Import Settings and turn On Read/Write Enabled", gameObject);
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Has skinned mesh
|
|||
|
if (skinnedMeshRend != null && skinnedMeshRend.sharedMesh == null)
|
|||
|
{
|
|||
|
Debug.Log (shatterStr + name + " Object has no mesh to fragment.", gameObject);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Methods
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Cache variables
|
|||
|
bool DefineComponents()
|
|||
|
{
|
|||
|
// Mesh storage
|
|||
|
transForm = GetComponent<Transform>();
|
|||
|
meshFilter = GetComponent<MeshFilter>();
|
|||
|
meshRenderer = GetComponent<MeshRenderer>();
|
|||
|
skinnedMeshRend = GetComponent<SkinnedMeshRenderer>();
|
|||
|
|
|||
|
// Multymesh fragmentation
|
|||
|
meshFilters = new List<MeshFilter>();
|
|||
|
if (advanced.combineChildren == true)
|
|||
|
meshFilters = GetComponentsInChildren<MeshFilter>().ToList();
|
|||
|
|
|||
|
// Basic proceed check
|
|||
|
if (MainCheck() == false)
|
|||
|
return false;
|
|||
|
|
|||
|
// Mesh renderer
|
|||
|
if (skinnedMeshRend == null)
|
|||
|
{
|
|||
|
if (meshRenderer == null)
|
|||
|
meshRenderer = gameObject.AddComponent<MeshRenderer>();
|
|||
|
bound = meshRenderer.bounds;
|
|||
|
}
|
|||
|
|
|||
|
// Skinned mesh
|
|||
|
if (skinnedMeshRend != null)
|
|||
|
bound = skinnedMeshRend.bounds;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Get bounds
|
|||
|
public Bounds GetBound()
|
|||
|
{
|
|||
|
// Mesh renderer
|
|||
|
if (meshRenderer == null)
|
|||
|
{
|
|||
|
meshRenderer = GetComponent<MeshRenderer>();
|
|||
|
if (meshRenderer != null)
|
|||
|
return meshRenderer.bounds;
|
|||
|
}
|
|||
|
else
|
|||
|
return meshRenderer.bounds;
|
|||
|
|
|||
|
// Skinned mesh
|
|||
|
if (skinnedMeshRend == null)
|
|||
|
{
|
|||
|
skinnedMeshRend = GetComponent<SkinnedMeshRenderer>();
|
|||
|
if (skinnedMeshRend != null)
|
|||
|
return skinnedMeshRend.bounds;
|
|||
|
}
|
|||
|
|
|||
|
return new Bounds();
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Methods
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Fragment this object by shatter properties List<GameObject>
|
|||
|
public void Fragment(FragLastMode fragmentMode = FragLastMode.New)
|
|||
|
{
|
|||
|
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
|
|||
|
stopWatch.Start();
|
|||
|
|
|||
|
// Engine
|
|||
|
if (engine == RFEngineType.Max)
|
|||
|
FragmentMax(fragmentMode);
|
|||
|
if (engine == RFEngineType.UnityBeta)
|
|||
|
FragmentUnity();
|
|||
|
|
|||
|
stopWatch.Stop();
|
|||
|
Debug.Log("Total Time == " + stopWatch.Elapsed.TotalMilliseconds + " ms)");
|
|||
|
}
|
|||
|
|
|||
|
// New Unity fragmentation engine
|
|||
|
void FragmentUnity()
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Original 3dsMax engine fragmentation
|
|||
|
void FragmentMax(FragLastMode fragmentMode)
|
|||
|
{
|
|||
|
// Prepare to cache fragments
|
|||
|
if (PreCache() == false)
|
|||
|
return;
|
|||
|
|
|||
|
// Cache
|
|||
|
RFFragment.CacheMeshes (ref meshes, ref pivots, ref rfOrigSubMeshIds, this);
|
|||
|
|
|||
|
// Stop
|
|||
|
if (meshes == null)
|
|||
|
return;
|
|||
|
|
|||
|
// Create fragments
|
|||
|
if (fragmentMode == FragLastMode.ToLast)
|
|||
|
{
|
|||
|
if (rootChildList[rootChildList.Count - 1] != null)
|
|||
|
fragmentsLast = CreateFragments (rootChildList[rootChildList.Count - 1]);
|
|||
|
else
|
|||
|
fragmentMode = FragLastMode.New;
|
|||
|
}
|
|||
|
|
|||
|
// Create new fragments
|
|||
|
if (fragmentMode == FragLastMode.New)
|
|||
|
fragmentsLast = CreateFragments();
|
|||
|
|
|||
|
// Post create fragments operations
|
|||
|
PostFragments();
|
|||
|
}
|
|||
|
|
|||
|
// Prepare and cache fragments
|
|||
|
public bool PreCache()
|
|||
|
{
|
|||
|
// Cache variables
|
|||
|
if (DefineComponents() == false)
|
|||
|
return false;
|
|||
|
|
|||
|
// Cache default vars
|
|||
|
SetVariables();
|
|||
|
|
|||
|
// Check if object is too small
|
|||
|
ScaleCheck();
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Create fragments by mesh and pivots array
|
|||
|
List<GameObject> CreateFragments(Transform root = null)
|
|||
|
{
|
|||
|
// No mesh were cached
|
|||
|
if (meshes == null)
|
|||
|
return null;
|
|||
|
|
|||
|
// Clear array for new fragments
|
|||
|
GameObject[] fragArray = new GameObject[meshes.Length];
|
|||
|
|
|||
|
// Create root object
|
|||
|
if (root == null)
|
|||
|
{
|
|||
|
GameObject rootGo = new GameObject (gameObject.name + "_root");
|
|||
|
rootGo.transform.position = transForm.position;
|
|||
|
rootGo.transform.rotation = transForm.rotation;
|
|||
|
rootGo.tag = gameObject.tag;
|
|||
|
rootGo.layer = gameObject.layer;
|
|||
|
root = rootGo.transform;
|
|||
|
rootChildList.Add (root);
|
|||
|
}
|
|||
|
|
|||
|
// Create instance for fragments
|
|||
|
GameObject fragInstance;
|
|||
|
if (advanced.copyComponents == true)
|
|||
|
{
|
|||
|
fragInstance = Instantiate (gameObject);
|
|||
|
fragInstance.transform.rotation = Quaternion.identity;
|
|||
|
fragInstance.transform.localScale = Vector3.one;
|
|||
|
|
|||
|
// Destroy shatter
|
|||
|
DestroyImmediate (fragInstance.GetComponent<RayfireShatter>());
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fragInstance = new GameObject();
|
|||
|
fragInstance.AddComponent<MeshFilter>();
|
|||
|
fragInstance.AddComponent<MeshRenderer>();
|
|||
|
}
|
|||
|
|
|||
|
// Get original mats. in case of combined meshes it is already defined in CombineShatter()
|
|||
|
if (advanced.combineChildren == false)
|
|||
|
materials = skinnedMeshRend != null
|
|||
|
? skinnedMeshRend.sharedMaterials
|
|||
|
: meshRenderer.sharedMaterials;
|
|||
|
|
|||
|
// Vars
|
|||
|
string baseName = gameObject.name + fragAddStr;
|
|||
|
|
|||
|
// Create fragment objects
|
|||
|
MeshFilter mf;
|
|||
|
GameObject go;
|
|||
|
MeshCollider mc;
|
|||
|
MeshRenderer rn;
|
|||
|
for (int i = 0; i < meshes.Length; ++i)
|
|||
|
{
|
|||
|
// Rescale mesh
|
|||
|
if (rescaleFix != 1f)
|
|||
|
RFFragment.RescaleMesh (meshes[i], rescaleFix);
|
|||
|
|
|||
|
// Instantiate. IMPORTANT do not parent when Instantiate
|
|||
|
go = Instantiate (fragInstance);
|
|||
|
go.transform.localScale = Vector3.one;
|
|||
|
|
|||
|
// Set multymaterial
|
|||
|
rn = go.GetComponent<MeshRenderer>();
|
|||
|
RFSurface.SetMaterial (rfOrigSubMeshIds, materials, material, rn, i, meshes.Length);
|
|||
|
|
|||
|
// Set fragment object name and tm
|
|||
|
go.name = baseName + (i + 1);
|
|||
|
go.transform.position = root.transform.position + (pivots[i] / rescaleFix);
|
|||
|
go.transform.parent = root.transform;
|
|||
|
go.tag = gameObject.tag;
|
|||
|
go.layer = gameObject.layer;
|
|||
|
|
|||
|
// Set fragment mesh
|
|||
|
mf = go.GetComponent<MeshFilter>();
|
|||
|
mf.sharedMesh = meshes[i];
|
|||
|
mf.sharedMesh.name = go.name;
|
|||
|
|
|||
|
// Set mesh collider
|
|||
|
mc = go.GetComponent<MeshCollider>();
|
|||
|
if (mc != null)
|
|||
|
mc.sharedMesh = meshes[i];
|
|||
|
|
|||
|
// Add in array
|
|||
|
fragArray[i] = go;
|
|||
|
}
|
|||
|
|
|||
|
// Root back to original parent
|
|||
|
root.transform.parent = transForm.parent;
|
|||
|
|
|||
|
// Reset scale for mesh fragments. IMPORTANT: skinned mesh fragments root should not be rescaled
|
|||
|
if (skinnedMeshRend == null)
|
|||
|
root.transform.localScale = Vector3.one;
|
|||
|
|
|||
|
// Destroy instance
|
|||
|
DestroyImmediate (fragInstance);
|
|||
|
|
|||
|
// Empty lists
|
|||
|
meshes = null;
|
|||
|
pivots = null;
|
|||
|
rfOrigSubMeshIds = null;
|
|||
|
|
|||
|
return fragArray.ToList();
|
|||
|
}
|
|||
|
|
|||
|
// Post create fragments operations
|
|||
|
void PostFragments()
|
|||
|
{
|
|||
|
// Limitation fragment
|
|||
|
RFShatterAdvanced.Limitations (this);
|
|||
|
|
|||
|
// Collect to all fragments
|
|||
|
fragmentsAll.AddRange (fragmentsLast);
|
|||
|
|
|||
|
// Reset original object back if it was scaled
|
|||
|
transForm.localScale = originalScale;
|
|||
|
}
|
|||
|
|
|||
|
// Fragment by limitations
|
|||
|
public void LimitationFragment(int ind)
|
|||
|
{
|
|||
|
RayfireShatter shat = fragmentsLast[ind].AddComponent<RayfireShatter>();
|
|||
|
shat.voronoi.amount = 10;
|
|||
|
|
|||
|
shat.Fragment();
|
|||
|
|
|||
|
if (shat.fragmentsLast.Count > 0)
|
|||
|
{
|
|||
|
fragmentsLast.AddRange (shat.fragmentsLast);
|
|||
|
DestroyImmediate (shat.gameObject);
|
|||
|
fragmentsLast.RemoveAt (ind);
|
|||
|
|
|||
|
// Parent and destroy root
|
|||
|
foreach (var frag in shat.fragmentsLast)
|
|||
|
frag.transform.parent = rootChildList[rootChildList.Count - 1];
|
|||
|
DestroyImmediate (shat.rootChildList[rootChildList.Count - 1].gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Deleting
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Delete fragments from last Fragment method
|
|||
|
public void DeleteFragmentsLast(int destroyMode = 0)
|
|||
|
{
|
|||
|
// Destroy last fragments
|
|||
|
if (destroyMode == 1)
|
|||
|
for (int i = fragmentsLast.Count - 1; i >= 0; i--)
|
|||
|
if (fragmentsLast[i] != null)
|
|||
|
DestroyImmediate (fragmentsLast[i]);
|
|||
|
|
|||
|
// Clean fragments list pre
|
|||
|
fragmentsLast.Clear();
|
|||
|
for (int i = fragmentsAll.Count - 1; i >= 0; i--)
|
|||
|
if (fragmentsAll[i] == null)
|
|||
|
fragmentsAll.RemoveAt (i);
|
|||
|
|
|||
|
// Check for all roots
|
|||
|
for (int i = rootChildList.Count - 1; i >= 0; i--)
|
|||
|
if (rootChildList[i] == null)
|
|||
|
rootChildList.RemoveAt (i);
|
|||
|
|
|||
|
// No roots
|
|||
|
if (rootChildList.Count == 0)
|
|||
|
return;
|
|||
|
|
|||
|
// Destroy with root
|
|||
|
if (destroyMode == 0)
|
|||
|
{
|
|||
|
// Destroy root with fragments
|
|||
|
DestroyImmediate (rootChildList[rootChildList.Count - 1].gameObject);
|
|||
|
|
|||
|
// Remove from list
|
|||
|
rootChildList.RemoveAt (rootChildList.Count - 1);
|
|||
|
}
|
|||
|
|
|||
|
// Clean all fragments list post
|
|||
|
for (int i = fragmentsAll.Count - 1; i >= 0; i--)
|
|||
|
if (fragmentsAll[i] == null)
|
|||
|
fragmentsAll.RemoveAt (i);
|
|||
|
}
|
|||
|
|
|||
|
// Delete all fragments and roots
|
|||
|
public void DeleteFragmentsAll()
|
|||
|
{
|
|||
|
// Clear lists
|
|||
|
fragmentsLast.Clear();
|
|||
|
fragmentsAll.Clear();
|
|||
|
|
|||
|
// Check for all roots
|
|||
|
for (int i = rootChildList.Count - 1; i >= 0; i--)
|
|||
|
if (rootChildList[i] != null)
|
|||
|
DestroyImmediate (rootChildList[i].gameObject);
|
|||
|
rootChildList.Clear();
|
|||
|
}
|
|||
|
|
|||
|
// Reset center helper
|
|||
|
public void ResetCenter()
|
|||
|
{
|
|||
|
centerPosition = Vector3.zero;
|
|||
|
centerDirection = Quaternion.identity;
|
|||
|
|
|||
|
Renderer rend = GetComponent<Renderer>();
|
|||
|
if (rend != null)
|
|||
|
centerPosition = transform.InverseTransformPoint (rend.bounds.center);
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Scale
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Check if object is too small
|
|||
|
void ScaleCheck()
|
|||
|
{
|
|||
|
// Geе size from renderers
|
|||
|
if (meshRenderer != null)
|
|||
|
size = meshRenderer.bounds.size.magnitude;
|
|||
|
if (skinnedMeshRend != null)
|
|||
|
size = skinnedMeshRend.bounds.size.magnitude;
|
|||
|
|
|||
|
// Get rescaleFix if too small
|
|||
|
if (size != 0f && size < minSize)
|
|||
|
{
|
|||
|
// Get rescaleFix factor
|
|||
|
rescaleFix = 1f / size;
|
|||
|
|
|||
|
// Scale small object up to shatter
|
|||
|
Vector3 newScale = transForm.localScale * rescaleFix;
|
|||
|
transForm.localScale = newScale;
|
|||
|
|
|||
|
// Warning
|
|||
|
Debug.Log ("Warning. Object " + name + " is too small.");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Reset original object and fragments scale
|
|||
|
public void ResetScale(float scaleValue)
|
|||
|
{
|
|||
|
// Reset scale
|
|||
|
if (resetState == true && scaleValue == 0f)
|
|||
|
{
|
|||
|
if (skinnedMeshRend != null)
|
|||
|
skinnedMeshRend.enabled = true;
|
|||
|
|
|||
|
if (meshRenderer != null)
|
|||
|
meshRenderer.enabled = true;
|
|||
|
|
|||
|
if (fragmentsLast.Count > 0)
|
|||
|
foreach (GameObject fragment in fragmentsLast)
|
|||
|
if (fragment != null)
|
|||
|
fragment.transform.localScale = Vector3.one;
|
|||
|
|
|||
|
resetState = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Copy
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Copy shatter component
|
|||
|
public static void CopyRootMeshShatter(RayfireRigid source, List<RayfireRigid> targets)
|
|||
|
{
|
|||
|
// No shatter
|
|||
|
if (source.mshDemol.sht == null)
|
|||
|
return;
|
|||
|
|
|||
|
// Copy shatter
|
|||
|
for (int i = 0; i < targets.Count; i++)
|
|||
|
{
|
|||
|
targets[i].mshDemol.sht = targets[i].gameObject.AddComponent<RayfireShatter>();
|
|||
|
targets[i].mshDemol.sht.CopyFrom (source.mshDemol.sht);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Copy from
|
|||
|
void CopyFrom(RayfireShatter shatter)
|
|||
|
{
|
|||
|
type = shatter.type;
|
|||
|
|
|||
|
voronoi = new RFVoronoi (shatter.voronoi);
|
|||
|
splinters = new RFSplinters (shatter.splinters);
|
|||
|
slabs = new RFSplinters (shatter.slabs);
|
|||
|
radial = new RFRadial (shatter.radial);
|
|||
|
custom = new RFCustom (shatter.custom);
|
|||
|
slice = new RFSlice (shatter.slice);
|
|||
|
tets = new RFTets (shatter.tets);
|
|||
|
|
|||
|
mode = shatter.mode;
|
|||
|
material.CopyFrom (shatter.material);
|
|||
|
clusters = new RFShatterCluster (shatter.clusters);
|
|||
|
advanced = new RFShatterAdvanced (shatter.advanced);
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Interactive
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Create Interactive object
|
|||
|
public void InteractiveCreate()
|
|||
|
{
|
|||
|
if (intGo == null)
|
|||
|
{
|
|||
|
intGo = new GameObject (name + "_Interactive");
|
|||
|
intMf = intGo.AddComponent<MeshFilter>();
|
|||
|
}
|
|||
|
|
|||
|
if (intMf == null)
|
|||
|
{
|
|||
|
intMf = intGo.GetComponent<MeshFilter>();
|
|||
|
if (intMf == null)
|
|||
|
intMf = intGo.AddComponent<MeshFilter>();
|
|||
|
}
|
|||
|
|
|||
|
// Copy tm
|
|||
|
intGo.transform.position = transForm.position;
|
|||
|
|
|||
|
intGo.tag = gameObject.tag;
|
|||
|
intGo.layer = gameObject.layer;
|
|||
|
|
|||
|
if (meshRenderer != null)
|
|||
|
{
|
|||
|
if (intMr == null)
|
|||
|
{
|
|||
|
intMr = intGo.AddComponent<MeshRenderer>();
|
|||
|
intMr.sharedMaterials = meshRenderer.sharedMaterials;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (skinnedMeshRend != null)
|
|||
|
{
|
|||
|
// TODO skinned mesh renderer support
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Fragment all meshes into own mesh
|
|||
|
public void InteractiveStart()
|
|||
|
{
|
|||
|
RFFragment.InteractiveStart (this);
|
|||
|
}
|
|||
|
|
|||
|
// Property changed
|
|||
|
public void InteractiveChange()
|
|||
|
{
|
|||
|
RFFragment.InteractiveChange (this);
|
|||
|
}
|
|||
|
|
|||
|
// Create interactively cached fragments
|
|||
|
public void InteractiveFragment()
|
|||
|
{
|
|||
|
// Create new fragments
|
|||
|
fragmentsLast = CreateFragments();
|
|||
|
|
|||
|
// Post create fragments operations
|
|||
|
PostFragments();
|
|||
|
|
|||
|
// Reset original mesh
|
|||
|
InteractiveStop();
|
|||
|
}
|
|||
|
|
|||
|
// Revert original mesh
|
|||
|
public void InteractiveStop()
|
|||
|
{
|
|||
|
// Enable own Renderer
|
|||
|
OriginalRenderer(true);
|
|||
|
|
|||
|
// Destroy interactive object
|
|||
|
if (intGo != null)
|
|||
|
DestroyImmediate (intGo);
|
|||
|
|
|||
|
// Reset
|
|||
|
intGo = null;
|
|||
|
intMf = null;
|
|||
|
intMr = null;
|
|||
|
shatterInt = null;
|
|||
|
interactive = false;
|
|||
|
}
|
|||
|
|
|||
|
// Set original renderer state
|
|||
|
public void OriginalRenderer(bool state)
|
|||
|
{
|
|||
|
if (meshRenderer != null)
|
|||
|
meshRenderer.enabled = state;
|
|||
|
if (skinnedMeshRend != null)
|
|||
|
skinnedMeshRend.enabled = state;
|
|||
|
}
|
|||
|
|
|||
|
public void InteractiveReset()
|
|||
|
{
|
|||
|
if (interactive == true)
|
|||
|
{
|
|||
|
InteractiveStop();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Final preview scale
|
|||
|
public float PreviewScale()
|
|||
|
{
|
|||
|
if (scalePreview == false)
|
|||
|
return 1f;
|
|||
|
return Mathf.Lerp (1f, 0.3f, previewScale);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|