private void Slice(GameObject subject, Vector4 planeInLocalSpace, int shatterStep, bool destroyOriginal) { if (subject == null) { throw new System.ArgumentNullException(); } //Sanity check: are we already slicing this? foreach (var jobState in jobStates) { if (object.ReferenceEquals(jobState.Specification.Subject, subject)) { return; // Debug.Log ("Turbo Slicer was asked to slice '{0}' but this target is already enqueued.", subject.name); } } //If names in the hierarchy are replicated anywhere than we have a problem. transformBuffer.Clear(); concatenateHierarchy(subject.transform, transformBuffer); nameBuffer.Clear(); foreach (var t in transformBuffer) { nameBuffer.Add(t.gameObject.name); } if (nameBuffer.Count != transformBuffer.Count) { Debug.LogWarning("Turbo Slicer needs each object under its hierarchy to have a unique name.", subject); return; } var sliceable = subject.GetComponent <Sliceable> (); bool channelTangents, channelNormals, channelUV2; if (sliceable != null) { channelNormals = sliceable.channelNormals; channelTangents = sliceable.channelTangents; channelUV2 = sliceable.channelUV2; } else { channelTangents = false; channelNormals = true; channelUV2 = false; } var renderers = subject.GetComponentsInChildren <Renderer>(); IEnumerable <MeshSnapshot> snapshots; var forwardPassAgent = subject.GetComponent <ForwardPassAgent> (); if (forwardPassAgent != null) { snapshots = forwardPassAgent.Snapshots; } else { var snapshotsBuilder = new List <MeshSnapshot>(); foreach (var renderer in renderers) { Mesh mesh; bool meshIsABufferMesh; if (renderer is MeshRenderer) { var filter = renderer.GetComponent <MeshFilter> (); mesh = filter.sharedMesh; meshIsABufferMesh = false; } else if (renderer is SkinnedMeshRenderer) { var smr = (SkinnedMeshRenderer)renderer; meshIsABufferMesh = true; mesh = new Mesh(); smr.BakeMesh(mesh); } else { throw new System.NotImplementedException("Turbo Slicer encountered a Renderer that is neither a MeshRenderer nor a SkinnedMeshRenderer"); } var rootToLocalTransform = renderer.transform.worldToLocalMatrix * subject.transform.localToWorldMatrix; var unitRect = new Rect(0.0f, 0.0f, 1.0f, 1.0f); var infillRects = new Rect[mesh.subMeshCount]; for (int i = 0; i < infillRects.Length; i++) { Rect?rect = null; if (renderer.sharedMaterials.Length > i) { var mat = renderer.sharedMaterials [i]; if (sliceable != null) { for (int j = 0; j < sliceable.infillers.Length; j++) { var ifc = sliceable.infillers [j]; if (object.ReferenceEquals(ifc.material, mat)) { rect = ifc.regionForInfill; } } } infillRects [i] = rect.GetValueOrDefault(unitRect); } } var isThisTheRoot = renderer.gameObject == subject; var key = isThisTheRoot ? MeshSnapshot.RootKey : renderer.gameObject.name; MeshSnapshot snapshot; if (preloadedMeshes.TryGetValue(mesh.GetInstanceID(), out snapshot) == false) { if (mesh.isReadable == false) { Debug.LogErrorFormat(subject, "Turbo Slicer needs to read mesh '{0}' on object '{1}', but cannot. If this object is " + "an original, go to its mesh and enable readability. If this object is a slice result, go to the " + "sliceable configuration on the original and turn on 'shreddable.", mesh.name, subject.name); return; } var indices = new int[mesh.subMeshCount][]; for (int i = 0; i < mesh.subMeshCount; i++) { indices [i] = mesh.GetIndices(i); } var coords = mesh.uv; if (coords == null || coords.Length < mesh.vertexCount) { //These might be null or empty but the core doesn't have a branch for UVs. So we'll put some junk in there if we need to. coords = new Vector2[mesh.vertexCount]; } snapshot = new MeshSnapshot( key, mesh.vertices, channelNormals ? mesh.normals : new Vector3[0], coords, channelUV2 ? mesh.uv2 : new Vector2[0], channelTangents ? mesh.tangents : new Vector4[0], indices, infillRects, rootToLocalTransform); } else { snapshot = new MeshSnapshot( key, snapshot.vertices, channelNormals ? snapshot.normals : new Vector3[0], snapshot.coords, channelUV2 ? snapshot.coords2 : new Vector2[0], channelTangents ? snapshot.tangents : new Vector4[0], snapshot.indices, infillRects, rootToLocalTransform); } if (meshIsABufferMesh) { GameObject.DestroyImmediate(mesh); } snapshotsBuilder.Add(snapshot); } snapshots = snapshotsBuilder; } var jobSpec = new JobSpecification(subject, snapshots, planeInLocalSpace, channelTangents, channelNormals, channelUV2, shatterStep, destroyOriginal); try { var jobState = new JobState(jobSpec); switch (workerThreadMode) { case WorkerThreadMode.Asynchronous: jobStates.Add(jobState); #if NETFX_CORE && !UNITY_EDITOR System.Threading.Tasks.Task.Factory.StartNew(ThreadSafeSlice.Slice, jobState); #else System.Threading.ThreadPool.QueueUserWorkItem(ThreadSafeSlice.Slice, jobState); #endif break; case WorkerThreadMode.Synchronous: ThreadSafeSlice.Slice(jobState); if (jobState.HasYield) { ConsumeJobYield(jobState.Specification, jobState.Yield); } else if (jobState.HasException) { throw jobState.Exception; } break; default: throw new System.NotImplementedException(); } } catch (System.Exception ex) { Debug.LogException(ex, subject); } }
private void Slice(GameObject subject, Vector4 planeInLocalSpace, int shatterStep, bool destroyOriginal) { bool passSanityCheck = true; if (subject == null) { throw new System.ArgumentNullException(); } //Sanity check: are we already slicing this? foreach (var jobState in jobStates) { if (object.ReferenceEquals(jobState.Specification.Subject, subject)) { passSanityCheck = false; Debug.LogErrorFormat("Turbo Slicer was asked to slice '{0}' but this target is already enqueued.", subject.name); } } if (passSanityCheck) { var sliceable = subject.GetComponent <Sliceable> (); GameObject meshHolder; bool channelTangents, channelNormals, channelUV2; if (sliceable != null) { channelNormals = sliceable.channelNormals; channelTangents = sliceable.channelTangents; channelUV2 = sliceable.channelUV2; } else { channelTangents = false; channelNormals = true; channelUV2 = false; } if (sliceable != null && sliceable.explicitlySelectedMeshHolder != null) { meshHolder = sliceable.explicitlySelectedMeshHolder; } else { meshHolder = subject; } var renderer = meshHolder.GetComponent <Renderer> (); MeshSnapshot snapshot; var forwardPassAgent = meshHolder.GetComponent <ForwardPassAgent> (); if (forwardPassAgent != null) { snapshot = forwardPassAgent.Snapshot; } else { Mesh mesh; bool meshIsABufferMesh; if (renderer is MeshRenderer) { var filter = meshHolder.GetComponent <MeshFilter> (); mesh = filter.sharedMesh; meshIsABufferMesh = false; } else if (renderer is SkinnedMeshRenderer) { var smr = (SkinnedMeshRenderer)renderer; meshIsABufferMesh = true; mesh = new Mesh(); smr.BakeMesh(mesh); } else { throw new System.NotImplementedException("Turbo Slicer encountered a Renderer that is neither a MeshRenderer nor a SkinnedMeshRenderer"); } var unitRect = new Rect(0.0f, 0.0f, 1.0f, 1.0f); var infillRects = new Rect[mesh.subMeshCount]; for (int i = 0; i < infillRects.Length; i++) { Rect?rect = null; if (renderer.sharedMaterials.Length > i) { var mat = renderer.sharedMaterials [i]; if (sliceable != null) { for (int j = 0; j < sliceable.infillers.Length; j++) { var ifc = sliceable.infillers [j]; if (object.ReferenceEquals(ifc.material, mat)) { rect = ifc.regionForInfill; } } } infillRects [i] = rect.GetValueOrDefault(unitRect); } } if (preloadedMeshes.TryGetValue(mesh.GetInstanceID(), out snapshot) == false) { var indices = new int[mesh.subMeshCount][]; for (int i = 0; i < mesh.subMeshCount; i++) { indices [i] = mesh.GetIndices(i); } //Not that we don't pull the tangents at all. snapshot = new MeshSnapshot( mesh.vertices, channelNormals ? mesh.normals : new Vector3[0], mesh.uv, channelUV2 ? mesh.uv2 : new Vector2[0], channelTangents ? mesh.tangents : new Vector4[0], indices, infillRects); } else { snapshot = new MeshSnapshot( snapshot.vertices, channelNormals ? snapshot.normals : new Vector3[0], snapshot.coords, channelUV2 ? snapshot.coords2 : new Vector2[0], channelTangents ? snapshot.tangents : new Vector4[0], snapshot.indices, infillRects); } if (meshIsABufferMesh) { GameObject.DestroyImmediate(mesh); } } var jobSpec = new JobSpecification(subject, snapshot, planeInLocalSpace, channelTangents, channelNormals, channelUV2, shatterStep, destroyOriginal); try { var jobState = new JobState(jobSpec); switch (workerThreadMode) { case WorkerThreadMode.Asynchronous: jobStates.Add(jobState); System.Threading.ThreadPool.QueueUserWorkItem(ThreadSafeSlice.Slice, jobState); break; case WorkerThreadMode.Synchronous: ThreadSafeSlice.Slice(jobState); if (jobState.HasYield) { ConsumeJobYield(jobState.Specification, jobState.Yield); } else if (jobState.HasException) { throw jobState.Exception; } break; default: throw new System.NotImplementedException(); } } catch (System.Exception ex) { Debug.LogException(ex, subject); } } }