/// <summary> /// Check our cached previous simulations and see if we can skip the simulation process /// </summary> private bool CheckCached(ClippingProtectorSetup Check) { foreach (ClippingProtectorSetup cs in CachedResults.Keys) { if (cs.SetupEqual(Check)) { OriginalMeshes = new Dictionary <SkinnedMeshRenderer, Mesh>(); if (DebugLevel != CharClipDebugLevel.None) { Debug.Log("Existing simulation found!"); } List <Mesh> NewMeshes = CachedResults[cs].FinalMeshes; int Ind = 0; foreach (SkinnedMeshRenderer smr in Meshes) { if (smr == null || smr.sharedMesh == null) { continue; } OriginalMeshes.Add(smr, smr.sharedMesh); smr.sharedMesh = NewMeshes[Ind]; Ind++; } return(true); } } return(false); }
public static CharacterClippingScriptableResult SaveOutToCache(ClippingProtectorSetup Setup, ClippingProtectorResult Result) { CharacterClippingScriptableResult Existing = TryGetExisting(Setup); if (Existing != null) { Debug.Log("Existing save found for Character Clipping Simulation"); return(Existing); } CharacterClippingScriptableResult CCR = CharacterClippingScriptableResult.CreateInstance <CharacterClippingScriptableResult>(); string ScriptableName = "CacheResult_" + System.DateTime.Now.ToString("dd_MM_yyyy_hh_mm_ss_ms"); CheckDirExists(ScriptableName); //Make sure results are saved as proper meshes foreach (Mesh m in Result.FinalMeshes) { AssetDatabase.CreateAsset(m, "Assets/Resources/CharacterClippingCache/" + ScriptableName + "/" + m.name + "_" + ScriptableName + ".asset"); } //Save out the asset UnityEditor.AssetDatabase.CreateAsset(CCR, "Assets/Resources/CharacterClippingCache/" + ScriptableName + "/" + ScriptableName + ".asset"); CCR.Result = Result; CCR.Setup = Setup; UnityEditor.EditorUtility.SetDirty(CCR); UnityEditor.AssetDatabase.SaveAssets(); Debug.Log("Saved out Character Clipping Simulation"); return(CCR); }
public static ClippingProtectorResult TryLoadCachedResult(ClippingProtectorSetup Setup) { CharacterClippingScriptableResult Exist = TryGetExisting(Setup); if (Exist != null) { return(Exist.Result); } return(new ClippingProtectorResult()); }
public static CharacterClippingScriptableResult TryGetExisting(ClippingProtectorSetup Setup) { InitCachedResults(); foreach (CharacterClippingScriptableResult Res in AllRes) { if (Setup.SetupEqual(Res.Setup)) { return(Res); } } return(null); }
public bool SetupEqual(object obj) { if (!(obj is ClippingProtectorSetup)) { return(false); } ClippingProtectorSetup mys = (ClippingProtectorSetup)obj; // Compare setup variables if (OutCheckDistance != mys.OutCheckDistance) { return(false); } if (InCheckDistance != mys.InCheckDistance) { return(false); } if (MarginDistance != mys.MarginDistance) { return(false); } if (LowerChain != mys.LowerChain) { return(false); } //Compare mesh lists if (InputMeshes.Count != mys.InputMeshes.Count) { return(false); } var firstNotSecond = InputMeshes.Except(mys.InputMeshes).ToList(); var secondNotFirst = mys.InputMeshes.Except(InputMeshes).ToList(); if (firstNotSecond.Any() && secondNotFirst.Any()) { return(false); } //Success return(true); }
/// <summary> /// Check our cached previous simulations and see if we can skip the simulation process /// </summary> private bool CheckCached(ClippingProtectorSetup Check) { //Check local cached foreach (ClippingProtectorSetup cs in CachedResults.Keys) { if (cs.SetupEqual(Check)) { List <Mesh> NewMeshes = CachedResults[cs].FinalMeshes; SetFromCachedMeshes(NewMeshes); return(true); } } //Check Saved cache scriptbales ClippingProtectorResult Res = CharacterClippingScriptableResult.TryLoadCachedResult(Check); if (Res.FinalMeshes != null && Res.FinalMeshes.Count > 0) { SetFromCachedMeshes(Res.FinalMeshes); return(true); } return(false); }
/// <summary> /// Main method. Runs a raycast simulation and hides parts of mesh that are obscured. /// NOTE has to be IEnumerator otherwise created collision meshes do not provide any raycast result on same frame. /// </summary> public IEnumerator RunClippingSimulation(Action OnSimulationComplete = null) { //TODO best to run in T or A pose! //TODO make sure that we are fully reset the meshes before re running!! //Make sure we are working with the propper meshes and not already partially hidden ResetMeshesToOriginal(); //Check our cache to see if we have already run if (CacheResults) { List <Mesh> CheckValues = new List <Mesh>(); foreach (SkinnedMeshRenderer smr in Meshes) { if (smr == null || smr.sharedMesh == null) { continue; } CheckValues.Add(smr.sharedMesh); } ClippingProtectorSetup Check = new ClippingProtectorSetup { OutCheckDistance = OutwardCheckDistance, InputMeshes = CheckValues, MarginDistance = MarginDistance, InCheckDistance = InwardCheckDistance, LowerChain = PreventLowerChainItems }; if (CheckCached(Check)) { yield break; } } if (DebugLevel != CharClipDebugLevel.None) { Debug.Log("Could not find cached simulation. Running clipping check."); } //Create collider meshes that we can test against for (int i = 0; i < Colliders.Count; i++) { DestroyImmediate(Colliders[i]); } Colliders = new List <GameObject>(); CreateColliders(Colliders); yield return(null); //REQUIRED! //Foreach mesh in meshes check occlude int Index = 0; List <Mesh> FinalMeshes = new List <Mesh>(); foreach (SkinnedMeshRenderer smr in Meshes) { if (smr == null || smr.sharedMesh == null) { continue; } //Setup so we dont trigger ourselves or any mesh lower down the chain if (PreventLowerChainItems) { Colliders[Index].gameObject.SetActive(false); yield return(null); } //if(Index > 0) { Colliders[Index - 1].gameObject.SetActive(true); } OriginalMeshes.Add(smr, smr.sharedMesh); //Raycast for results bool[] Results = RaycastToFindOverlap(Colliders, Index); //If we have nothing to hide then no point to change the mesh etc! if (!Results.Contains(true)) { FinalMeshes.Add(smr.sharedMesh); continue; } //Identify the triangles that we no longer want and remove them CalculateNewTrisJob newJob = new CalculateNewTrisJob { NewTris = new NativeList <int>(Allocator.TempJob), OriginalTris = new NativeArray <int>(smr.sharedMesh.triangles, Allocator.TempJob), Results = new NativeArray <bool>(Results, Allocator.TempJob) }; newJob.Schedule().Complete(); if (RunAsynch == AsyncHarshness.Harsh) { yield return(null); } //Setup instance mesh ready for hiding elements Mesh newm = Instantiate(smr.sharedMesh); newm.triangles = newJob.NewTris.ToArray(); newm.name = "Clone_" + smr.sharedMesh.name; smr.sharedMesh = newm; FinalMeshes.Add(newm); //Finalise newJob.Cleanup(); Index++; if (RunAsynch == AsyncHarshness.Soft) { yield return(null); } } //Clear up old junk colliders for (int i = 0; i < Colliders.Count; i++) { DestroyImmediate(Colliders[i]); } //Add result to cache for quick rerun of any future meshes if (CacheResults) { LastSetup = new ClippingProtectorSetup { OutCheckDistance = OutwardCheckDistance, InputMeshes = OriginalMeshes.Values.ToList(), MarginDistance = MarginDistance, InCheckDistance = InwardCheckDistance, LowerChain = PreventLowerChainItems }; CachedResults.Add(LastSetup, new ClippingProtectorResult { FinalMeshes = FinalMeshes }); } //Notify of completion if (OnSimulationComplete != null) { OnSimulationComplete.Invoke(); } }