protected virtual void OnMouseOver() { if (DungeonManager.instance.mode != DungeonManager.Mode.Move || (Program.selectedProgram && Program.selectedProgram.IsFlying()) || !myTile.isBlocked) { myTile.OnMouseOver(); } if (Input.GetMouseButtonDown(0)) { if (DungeonManager.instance.mode != DungeonManager.Mode.Deploy) { Program.selectedProgram = myProgram; FindObjectOfType <PathPreview>().ClearPreview(); selectedObject = this; } } else if (Input.GetMouseButtonDown(1)) { if (Program.isTargetingBreach && Program.selectedProgram && Program.selectedProgram.IsControlledByPlayer()) { Program.selectedProgram.AttemptBreach(this); } else if ((!Program.isTargetingAttack) && (!Program.isTargetingBreach) && Program.selectedProgram && Program.selectedProgram.IsControlledByPlayer()) { DungeonManager.instance.RightClickTile(myTile); } } }
void Update() { Vector3 dir = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")).normalized; float diff = speed - Vector3.Project(rb.velocity, dir).magnitude; if (diff < 0) { diff = 0; } Vector3 friction = rb.velocity * -0.5f; rb.AddForce(dir * diff * 40 + friction); if (rb.velocity.magnitude > 0) { //transform.rotation = Quaternion.LookRotation(Vector3.Scale(rb.velocity.normalized, new Vector3(1, 0, 1))); } if (Input.GetMouseButtonDown(0)) { RaycastHit hit; if (Physics.Raycast(cam.ScreenPointToRay(Input.mousePosition), out hit)) { Debug.Log("Clicked"); Hackable target = hit.transform.GetComponent <Hackable>(); if (target != null) { ApplyBreakpoint(target); } } } if (rb.velocity.y < 0) { rb.AddForce(Physics.gravity); } }
private void OnTriggerStay2D(Collider2D collision) { if (collision.gameObject.CompareTag(TagManager.GetTagNameByEnum(TagEnum.Hackble))) { currentTarget = collision.gameObject.GetComponent <Hackable>(); } }
private void OnTriggerExit2D(Collider2D collision) { if (collision.gameObject.CompareTag(TagManager.GetTagNameByEnum(TagEnum.Hackble))) { currentTarget = null; } }
//private GameObject instantiatedHackBar; private void Update() { Debug.DrawRay(transform.position, transform.forward * hackRange, Color.red); if (Input.GetButtonDown(hackButton)) { DetectCameraBox(); //if(currentlyHackedObject != null) //instantiatedHackBar = Instantiate(hackProgressBar, GameObject.Find("Canvas").transform); } if (Input.GetButton(hackButton)) { if (currentlyHackedObject != null && !currentlyHackedObject.IsHacked()) { currentlyHackedObject.HackCamera(hackSpeed * Time.deltaTime); } } if (Input.GetButtonUp(hackButton)) { if (currentlyHackedObject != null) { //if (instantiatedHackBar != null) { // Destroy(instantiatedHackBar); //} currentlyHackedObject.StopHacking(); currentlyHackedObject = null; } } }
public GameObject[] severByPointAndNormal(GameObject go, Vector3 pointInWorldSpace, Vector3?normalInWorldSpace) { Hackable hackable = go.GetComponent <Hackable>(); if (hackable == null) { Debug.LogError("GameObject '" + go.name + "' cannot be sliced by point because it has no Hackable component. Please look for the 'slice by point' chapter in the manual."); GameObject[] blankResult = { go }; return(blankResult); } else { string boneName = null; float rootTipProgression = 0f; if (determineSlice(hackable, pointInWorldSpace, ref boneName, ref rootTipProgression)) { return(LimbHacker.instance.severByJoint(go, boneName, rootTipProgression, normalInWorldSpace)); } else { GameObject[] notMuch = { go }; return(notMuch); } } }
private void DetectCameraBox() { RaycastHit hit; if (Physics.Raycast(transform.position, transform.forward, out hit, hackRange, 1 << cameraBoxLayer)) { currentlyHackedObject = hit.transform.gameObject.GetComponent <Hackable>(); return; } currentlyHackedObject = null; }
void Update() { // Check if an object is hackable and if so, set hack. if (Input.GetMouseButtonDown(0)) { RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero); if (hit.collider != null) { var tmpTerm = hit.collider.GetComponent <Terminal>(); var tmpHackable = hit.collider.GetComponent <Hackable>(); // clicked a Hackable if (tmpHackable != null) { if (_hackObj != null && _hackObj != tmpHackable) { _hackObj.isHacked = false; if (_term != null) { _term.isHacked = false; } } _hackObj = tmpHackable; _hackObj.isHacked = !_hackObj.isHacked; Player.ConnectToHackable(_hackObj); } // clicked a Terminal if (tmpTerm != null) { _term = tmpTerm; _term.isHacked = !_term.isHacked; Player.ConnectToTerminal(_term); } } } if (_hackObj != null && !_hackObj.isHacked) { _hackObj = null; Player.ClearHackable(); } if (_term != null && !_term.isHacked) { _term = null; Player.ClearTerminal(); } HackWindow.SetActive(_hackObj != null && _term != null); }
public override void OnInspectorGUI() { Hackable s = (Hackable)target; try { var allBones = LimbHacker.FindBonesInTree(s.gameObject); s.alternatePrefab = EditorGUILayout.ObjectField("Alternate prefab", (Object)s.alternatePrefab, typeof(GameObject), false); s.infillMaterial = (Material)EditorGUILayout.ObjectField("Infill Material", (Object)s.infillMaterial, typeof(Material), false); if (s.infillMaterial != null) { s.infillMode = (LimbHacker.Infill)EditorGUILayout.EnumPopup("Infill Mode", s.infillMode); } EditorGUILayout.LabelField("Select which bones are severable:"); var selectedBones = new List <Transform>(); var selectAll = GUILayout.Button("Select all"); foreach (var bone in allBones) { bool wasSelected = System.Array.IndexOf(s.severables, bone) >= 0; bool isSelected = EditorGUILayout.Toggle(bone.name, wasSelected) || selectAll; if (isSelected) { selectedBones.Add(bone); } } s.severables = selectedBones.ToArray(); if (GUI.changed) { EditorUtility.SetDirty(target); } } catch (LimbHacker.ForestException ex) { Debug.LogError(ex.Message); EditorGUILayout.LabelField("This object must have SkinnedMeshRenderers referring to a single tree."); } }
public JobSpecification(GameObject subject, Hackable hackable, IEnumerable <MeshSnapshot> meshSnapshots, Dictionary <string, NodeMetadata> nodeMetadata, Material infillMaterial, string jointName, float rootTipProgression, Vector3?tiltPlane, InfillMode infillMode, bool destroyOriginal) { Subject = subject; Hackable = hackable; MeshSnapshots = meshSnapshots; InfillMaterial = infillMaterial; NodeMetadata = nodeMetadata; JointName = jointName; RootTipProgression = rootTipProgression; TiltPlane = tiltPlane; InfillMode = infillMode; DestroyOriginal = destroyOriginal; }
void ApplyBreakpoint(Hackable target) { if (breakpoints.Contains(target)) { target.Unhack(); breakpoints.Remove(target); } else { if (breakpoints.Count == numBreakpoints) { breakpoints.First.Value.Unhack(); breakpoints.RemoveFirst(); } breakpoints.AddLast(target); target.Hack(); } }
internal void AttemptBreach(Hackable toHack) { if (!hasUsedAction && GetBreach() > 0 && !toHack.IsHacked()) { int breachRange = 1; if (GetKeywords().Contains("Remote")) { breachRange = GetRange(); } List <DungeonTile> tempPath = DungeonManager.instance.grid.FindPath(myTile, toHack.myTile, breachRange, true); if (tempPath[tempPath.Count - 1] == toHack.myTile) { Breach newBreach = Instantiate(myBreach, gameObject.transform.position, Quaternion.identity).GetComponent <Breach>(); newBreach.breach = GetBreach(); newBreach.SetCourse(tempPath, toHack); Program.isTargetingBreach = false; movesLeft = 0; hasUsedAction = true; } } }
void ConnectHackable(Hackable objToHack) { _hackObj = objToHack; objToHack.isHacked = true; }
public HackStartInfo(NetworkSimulation netSim, SaveManager saveManager, Hackable hackable) { _netSim = netSim; _saveManager = saveManager; _hackable = hackable; }
override internal void Start() { base.Start(); hackable = GetComponent <Hackable>(); lineOfSightIndicators = new List <GameObject>(); }
internal void SetTile(DungeonTile dungeonTile) { myTile = dungeonTile; hackable = GetComponent <Hackable>(); hackable.myTile = dungeonTile; }
public void ConnectToHackable(Hackable hackObj) { Beam2.SetActive(true); _beam2End = hackObj.gameObject; UpdateLines(Beam2, _beam2End); }
public void SeverByJoint(GameObject subject, string jointName, float rootTipProgression, Vector3?planeNormal) { //Sanity check: are we already slicing this? foreach (var extantState in jobStates) { if (ReferenceEquals(extantState.Specification.Subject, subject)) { //Debug.LogErrorFormat("Turbo Slicer was asked to slice '{0}' but this target is already enqueued.", subject.name); return; } } rootTipProgression = Mathf.Clamp01(rootTipProgression); //These here are in local space because they're only used to copy to the resultant meshes; they're not used //to transform the vertices. We expect a world-space slice input. Hackable hackable = null; { var hackables = subject.GetComponentsInChildren <Hackable>(); if (hackables.Length > 0) { if (hackables.Length > 1) { Debug.LogWarning("Limb Hacker found multiple slice configurations on object '" + subject.name + "'! Behavior is undefined."); } hackable = hackables[0]; } else { Debug.LogWarning("Limb Hacker found no slice configuration on object '" + subject.name + "'."); return; } } //We need information about which BONES are getting severed. var metadataByNodeName = new Dictionary <string, NodeMetadata>(); { var childTransformByName = new Dictionary <string, Transform>(); var parentKeyByKey = new Dictionary <string, string>(); foreach (Transform t in GetConcatenatedHierarchy(subject.transform)) { childTransformByName[t.name] = t; var parent = t.parent; if (t == subject.transform) { parent = null; } parentKeyByKey[t.name] = parent == null ? null : parent.name; } var severedByChildName = new Dictionary <string, bool>(); { foreach (string childName in childTransformByName.Keys) { severedByChildName[childName] = childName == jointName; } bool changesMade; do { changesMade = false; foreach (string childKey in childTransformByName.Keys) { bool severed = severedByChildName[childKey]; if (severed) { continue; } string parentKey = parentKeyByKey[childKey]; bool parentSevered; if (severedByChildName.TryGetValue(parentKey, out parentSevered) == false) { continue; } if (parentSevered) { severedByChildName[childKey] = true; changesMade = true; } } }while (changesMade); } foreach (var kvp in severedByChildName) { var t = childTransformByName[kvp.Key]; var isConsideredSevered = kvp.Value; metadataByNodeName[kvp.Key] = new NodeMetadata(t, isConsideredSevered); } } IEnumerable <MeshSnapshot> snapshots; var forwardPassAgent = subject.GetComponent <ForwardPassAgent>(); if (forwardPassAgent == null) { var snapshotBuilder = new List <MeshSnapshot>(); var skinnedMeshRenderers = subject.GetComponentsInChildren <SkinnedMeshRenderer>(true); foreach (var smr in skinnedMeshRenderers) { var mesh = smr.sharedMesh; var boneMetadata = new BoneMetadata[smr.bones.Length]; var bones = smr.bones; var bindPoses = mesh.bindposes; for (int i = 0; i < boneMetadata.Length; i++) { boneMetadata[i] = new BoneMetadata(i, bones[i].name, bindPoses[i]); } int?infillIndex = null; if (hackable.infillMaterial != null) { var mats = smr.sharedMaterials; for (int i = 0; i < mats.Length; i++) { if (hackable.infillMaterial == mats[i]) { infillIndex = i; break; } } } MeshSnapshot snapshot; MeshSnapshot preloadedFragment; if (preloadedMeshes.TryGetValue(mesh.GetInstanceID(), out preloadedFragment)) { //The preloaded fragments are missing data which is particular to the SMR. We'll combine it with such data here. snapshot = preloadedFragment.WithKey(smr.name).WithMaterials(smr.sharedMaterials).WithBoneMetadata(boneMetadata).WithInfillIndex(infillIndex); } else { var indices = new int[mesh.subMeshCount][]; for (int i = 0; i < mesh.subMeshCount; i++) { indices[i] = mesh.GetIndices(i); } snapshot = new MeshSnapshot( smr.name, mesh.vertices, mesh.normals, mesh.uv, mesh.tangents, mesh.boneWeights, smr.sharedMaterials, boneMetadata, infillIndex, indices); } snapshotBuilder.Add(snapshot); } snapshots = snapshotBuilder; } else { snapshots = forwardPassAgent.Snapshot; } var jobSpec = new JobSpecification(subject, hackable, snapshots, metadataByNodeName, hackable.infillMaterial, jointName, rootTipProgression, planeNormal, hackable.infillMode, true); var jobState = new JobState(jobSpec); try { switch (workerThreadMode) { case WorkerThreadMode.Asynchronous: jobStates.Add(jobState); #if NETFX_CORE && !UNITY_EDITOR System.Threading.Tasks.Task.Factory.StartNew(ThreadSafeHack.Slice, jobState); #else System.Threading.ThreadPool.QueueUserWorkItem(ThreadSafeHack.Slice, jobState); #endif break; case WorkerThreadMode.Synchronous: ThreadSafeHack.Slice(jobState); if (jobState.HasYield) { ConsumeJobYield(jobState); } else if (jobState.HasException) { throw jobState.Exception; } break; default: throw new System.NotImplementedException(); } } catch (System.Exception ex) { Debug.LogException(ex, subject); } }
internal void SetCourse(List <DungeonTile> path, Hackable target) { myTile = path[0]; this.target = target; movePath = path; }
public static bool DetermineSlice(Hackable hackable, Vector3 pointInWorldSpace, ref string boneName, ref float rootTipProgression) { const int nothing = -1; var severables = hackable.severables; var indexByObject = new Dictionary <Transform, int>(); for (var i = 0; i < severables.Length; i++) { indexByObject[severables[i]] = i; } var severablesInThreeSpace = new Vector3[severables.Length]; for (var i = 0; i < severables.Length; i++) { severablesInThreeSpace[i] = severables[i].position; } var deltas = new Vector3[severables.Length]; for (var i = 0; i < severables.Length; i++) { deltas[i] = severablesInThreeSpace[i] - pointInWorldSpace; } var mags = new float[severables.Length]; for (var i = 0; i < severables.Length; i++) { mags[i] = deltas[i].magnitude; } var indexOfNearestThing = nothing; var distanceToNearestThing = float.PositiveInfinity; for (var i = 0; i < severables.Length; i++) { if (mags[i] < distanceToNearestThing) { indexOfNearestThing = i; distanceToNearestThing = mags[i]; } } if (indexOfNearestThing != nothing) { var nearestThing = severables[indexOfNearestThing]; if (indexByObject.ContainsKey(nearestThing.parent)) { var parentIndex = indexByObject[nearestThing.parent]; var hereDelta = severablesInThreeSpace[indexOfNearestThing] - severablesInThreeSpace[parentIndex]; var touchDelta = pointInWorldSpace - severablesInThreeSpace[parentIndex]; //If the touch is closer to the parent than the severable is, than it's between them. //We'll use that and then use the root tip progression to slice just the right spot. if (touchDelta.magnitude < hereDelta.magnitude) { indexOfNearestThing = parentIndex; nearestThing = severables[indexOfNearestThing]; } } var childIndices = new List <int>(); for (var i = 0; i < severables.Length; i++) { var candidate = severables[i]; if (candidate.parent == nearestThing) { childIndices.Add(i); } } rootTipProgression = 0f; if (childIndices.Count > 0) { var aggregatedChildPositions = Vector3.zero; foreach (var i in childIndices) { aggregatedChildPositions += severablesInThreeSpace[i]; } var meanChildPosition = aggregatedChildPositions / childIndices.Count; var alfa = (pointInWorldSpace - nearestThing.position).sqrMagnitude; var bravo = (pointInWorldSpace - meanChildPosition).sqrMagnitude; rootTipProgression = Mathf.Clamp(alfa / bravo, 0.0f, 0.99f); } boneName = nearestThing.name; return(true); } else { return(false); } }
public bool determineSlice(Hackable hackable, Vector3 pointInWorldSpace, ref string boneName, ref float rootTipProgression) { const int nothing = -1; Transform[] severables = hackable.severables; Dictionary <Transform, int> indexByObject = new Dictionary <Transform, int>(); for (int i = 0; i < severables.Length; i++) { indexByObject[severables[i]] = i; } Vector3[] severablesInThreeSpace = new Vector3[severables.Length]; for (int i = 0; i < severables.Length; i++) { severablesInThreeSpace[i] = severables[i].position; } Vector3[] deltas = new Vector3 [severables.Length]; for (int i = 0; i < severables.Length; i++) { deltas[i] = severablesInThreeSpace[i] - pointInWorldSpace; } float[] mags = new float[severables.Length]; for (int i = 0; i < severables.Length; i++) { mags[i] = deltas[i].magnitude; } int indexOfNearestThing = nothing; float distanceToNearestThing = float.PositiveInfinity; for (int i = 0; i < severables.Length; i++) { if (mags[i] < distanceToNearestThing) { indexOfNearestThing = i; distanceToNearestThing = mags[i]; } } if (indexOfNearestThing != nothing) { Transform nearestThing = severables[indexOfNearestThing]; if (indexByObject.ContainsKey(nearestThing.parent)) { int parentIndex = indexByObject[nearestThing.parent]; Vector3 hereDelta = severablesInThreeSpace[indexOfNearestThing] - severablesInThreeSpace[parentIndex]; Vector3 touchDelta = pointInWorldSpace - severablesInThreeSpace[parentIndex]; //If the touch is closer to the parent than the severable is, than it's between them. //We'll use that and then use the root tip progression to slice just the right spot. if (touchDelta.magnitude < hereDelta.magnitude) { indexOfNearestThing = parentIndex; nearestThing = severables[indexOfNearestThing]; } } List <int> childIndices = new List <int>(); for (int i = 0; i < severables.Length; i++) { Transform candidate = severables[i]; if (candidate.parent == nearestThing) { childIndices.Add(i); } } rootTipProgression = 0f; if (childIndices.Count > 0) { Vector3 aggregatedChildPositions = Vector3.zero; foreach (int i in childIndices) { aggregatedChildPositions += severablesInThreeSpace[i]; } Vector3 meanChildPosition = aggregatedChildPositions / ((float)childIndices.Count); Matrix4x4 flattenTransform; Vector3 v1 = Vector3.forward; Vector3 v2 = (severablesInThreeSpace[indexOfNearestThing] - meanChildPosition).normalized; Vector3 v3 = Vector3.Cross(v1, v2).normalized; Vector3 v4 = Vector3.Cross(v3, v1); float cos = Vector3.Dot(v2, v1); float sin = Vector3.Dot(v2, v4); Matrix4x4 m1 = Matrix4x4.identity; m1.SetRow(0, (Vector4)v1); m1.SetRow(1, (Vector4)v4); m1.SetRow(2, (Vector4)v3); Matrix4x4 m1i = m1.inverse; Matrix4x4 m2 = Matrix4x4.identity; m2.SetRow(0, new Vector4(cos, sin, 0, 0)); m2.SetRow(1, new Vector4(-sin, cos, 0, 0)); flattenTransform = m1i * m2 * m1; Vector3 transformedChildPosition = flattenTransform.MultiplyPoint(meanChildPosition); Vector3 transformedRootPosition = flattenTransform.MultiplyPoint(severablesInThreeSpace[indexOfNearestThing]); Vector3 transformedTouchPosition = flattenTransform.MultiplyPoint(pointInWorldSpace); rootTipProgression = 1f - Mathf.Clamp((transformedTouchPosition.z - transformedChildPosition.z) / (transformedRootPosition.z - transformedChildPosition.z), 0.05f, 1f); } boneName = nearestThing.name; return(true); } else { return(false); } }
public GameObject[] severByJoint(GameObject go, string jointName, float rootTipProgression, Vector3?planeNormal) { rootTipProgression = Mathf.Clamp01(rootTipProgression); //These here are in local space because they're only used to copy to the resultant meshes; they're not used //to transform the vertices. We expect a world-space slice input. Hackable hackable = null; { Hackable[] hackables = go.GetComponentsInChildren <Hackable>(); if (hackables.Length > 0) { if (hackables.Length > 1) { Debug.LogWarning("Limb Hacker found multiple slice configurations on object '" + go.name + "' in scene '" + Application.loadedLevelName + "'! Behavior is undefined."); } hackable = hackables[0]; } } //We need information about which BONES are getting severed. var allBones = LimbHacker.FindBonesInTree(go); var childTransformByName = new Dictionary <string, Transform>(); var parentKeyByKey = new Dictionary <string, string>(); foreach (Transform t in GetConcatenatedHierarchy(go.transform)) { childTransformByName[t.name] = t; Transform parent = t.parent; if (t == go.transform) { parent = null; } parentKeyByKey[t.name] = parent == null ? null : parent.name; } var severedByChildName = new Dictionary <string, bool>(); { foreach (string childName in childTransformByName.Keys) { severedByChildName[childName] = childName == jointName; } bool changesMade; do { changesMade = false; foreach (string childKey in childTransformByName.Keys) { bool severed = severedByChildName[childKey]; if (severed) { continue; } string parentKey = parentKeyByKey[childKey]; bool parentSevered; if (severedByChildName.TryGetValue(parentKey, out parentSevered) == false) { continue; } if (parentSevered) { severedByChildName[childKey] = true; changesMade = true; } } }while(changesMade); } GameObject frontObject, backObject; { var bonePresenceFront = new Dictionary <string, bool>(); var bonePresenceBack = new Dictionary <string, bool>(); foreach (KeyValuePair <string, bool> kvp in severedByChildName) { bonePresenceFront[kvp.Key] = kvp.Value; bonePresenceBack[kvp.Key] = !kvp.Value; } createResultObjects(go, hackable, childTransformByName, bonePresenceFront, bonePresenceBack, out frontObject, out backObject); } var skinnedMeshRenderers = go.GetComponentsInChildren <SkinnedMeshRenderer>(true); foreach (var smr in skinnedMeshRenderers) { var m = smr.sharedMesh; LoadSkinnedMeshRendererIntoCache(smr, true); var severedByBoneIndex = new Dictionary <int, bool>(); var mandatoryByBoneIndex = new bool[smr.bones.Length]; string severedJointKey = jointName; Dictionary <string, int> boneIndexByName = new Dictionary <string, int>(); List <string> orderedBoneNames = new List <string>(); foreach (Transform bone in smr.bones) { boneIndexByName[bone.name] = orderedBoneNames.Count; orderedBoneNames.Add(bone.name); } for (int boneIndex = 0; boneIndex < orderedBoneNames.Count; boneIndex++) { string boneName = orderedBoneNames[boneIndex]; severedByBoneIndex[boneIndex] = severedByChildName[boneName]; } Vector4 plane = Vector4.zero; bool willSliceThisMesh = boneIndexByName.ContainsKey(severedJointKey); if (willSliceThisMesh) { //We need to create a slice plane in local space. We're going to do that by using the bind poses //from the SEVERED limb, its PARENT and its CHILDREN to create a position and normal. Matrix4x4[] orderedBindPoses = smr.sharedMesh.bindposes; int severedJointIndex = boneIndexByName[severedJointKey]; Matrix4x4 severedJointMatrix = orderedBindPoses[severedJointIndex].inverse; Matrix4x4 severedJointParentMatrix = Matrix4x4.identity; if (parentKeyByKey.ContainsKey(severedJointKey)) { string severedJointParentKey = parentKeyByKey[severedJointKey]; if (boneIndexByName.ContainsKey(severedJointParentKey)) { int severedJointParentIndex = boneIndexByName[severedJointParentKey]; severedJointParentMatrix = orderedBindPoses[severedJointParentIndex].inverse; } } VectorAccumulator meanChildPosition = new VectorAccumulator(); for (int i = 0; i < boneIndexByName.Count; i++) { mandatoryByBoneIndex[i] = false; } if (parentKeyByKey.ContainsKey(severedJointKey)) { string parentKey = parentKeyByKey[severedJointKey]; if (boneIndexByName.ContainsKey(parentKey)) { mandatoryByBoneIndex[boneIndexByName[parentKey]] = true; } } if (rootTipProgression > 0f) { mandatoryByBoneIndex[boneIndexByName[jointName]] = true; List <string> childKeys = new List <string>(); foreach (KeyValuePair <string, string> kvp in parentKeyByKey) { if (kvp.Value == severedJointKey) { childKeys.Add(kvp.Key); } } List <int> childIndices = new List <int>(); foreach (string key in childKeys) { int childIndex; if (boneIndexByName.TryGetValue(key, out childIndex)) { childIndices.Add(childIndex); } } foreach (int index in childIndices) { Matrix4x4 childMatrix = orderedBindPoses[index].inverse; Vector3 childPosition = childMatrix.MultiplyPoint3x4(Vector3.zero); meanChildPosition.addFigure(childPosition); } } Vector3 position0 = severedJointParentMatrix.MultiplyPoint3x4(Vector3.zero); Vector3 position1 = severedJointMatrix.MultiplyPoint3x4(Vector3.zero); Vector3 position2 = meanChildPosition.mean; Vector3 deltaParent = position0 - position1; Vector3 deltaChildren = position1 - position2; Vector3 position = Vector3.Lerp(position1, position2, rootTipProgression); Vector3 normalFromParentToChild = -Vector3.Lerp(deltaParent, deltaChildren, rootTipProgression).normalized; if (planeNormal.HasValue) { Matrix4x4 fromWorldToLocalSpaceOfBone = smr.bones[severedJointIndex].worldToLocalMatrix; Vector3 v = planeNormal.Value; v = fromWorldToLocalSpaceOfBone.MultiplyVector(v); v = severedJointMatrix.MultiplyVector(v); v.Normalize(); if (Vector3.Dot(v, normalFromParentToChild) < 0f) { v = -v; } v = MuffinSliceCommon.clampNormalToBicone(v, normalFromParentToChild, 30f); planeNormal = v; } else { planeNormal = normalFromParentToChild; } plane = (Vector4)planeNormal.Value; plane.w = -(plane.x * position.x + plane.y * position.y + plane.z * position.z); } //We're going to create two new tentative meshes which contain ALL original vertices in order, //plus room for new vertices. Not all of these copied vertices will be addressed, but copying them //over eliminates the need to remove doubles and do an On^2 search. int submeshCount = c.indices.Length; TurboList <int>[] _frontIndices = new TurboList <int> [submeshCount]; TurboList <int>[] _backIndices = new TurboList <int> [submeshCount]; PlaneTriResult[] sidePlanes = new PlaneTriResult[c.vertices.Count]; { BoneWeight[] weights = c.weights.array; Vector3[] vertices = c.vertices.array; int count = c.vertices.Count; bool[] whollySeveredByVertexIndex = new bool[count]; bool[] severableByVertexIndex = new bool[count]; bool[] mandatoryByVertexIndex = new bool[count]; const float minimumWeightForRelevance = 0.1f; for (int i = 0; i < severableByVertexIndex.Length; i++) { BoneWeight weight = weights[i]; bool whollySevered = true; bool severable = false; bool mandatory = false; int[] indices = { weight.boneIndex0, weight.boneIndex1, weight.boneIndex2, weight.boneIndex3 }; float[] scalarWeights = { weight.weight0, weight.weight1, weight.weight2, weight.weight3 }; for (int j = 0; j < 4; j++) { if (scalarWeights[j] > minimumWeightForRelevance) { int index = indices[j]; bool _severable = severedByBoneIndex[index]; bool _mandatory = mandatoryByBoneIndex[index]; whollySevered &= _severable; severable |= _severable; mandatory |= _mandatory; } } whollySeveredByVertexIndex[i] = whollySevered; severableByVertexIndex[i] = severable; mandatoryByVertexIndex[i] = mandatory; } for (int i = 0; i < sidePlanes.Length; i++) { if (willSliceThisMesh && mandatoryByVertexIndex[i]) { sidePlanes[i] = MuffinSliceCommon.getSidePlane(ref vertices[i], ref plane); } else if (whollySeveredByVertexIndex[i]) { sidePlanes[i] = PlaneTriResult.PTR_FRONT; } else if (willSliceThisMesh && severableByVertexIndex[i]) { sidePlanes[i] = MuffinSliceCommon.getSidePlane(ref vertices[i], ref plane); } else { sidePlanes[i] = PlaneTriResult.PTR_BACK; } } } TurboList <int> frontInfill = null; TurboList <int> backInfill = null; for (int j = 0; j < submeshCount; j++) { int initialCapacityIndices = Mathf.RoundToInt((float)c.indices[j].Length * factorOfSafetyIndices); _frontIndices[j] = new TurboList <int>(initialCapacityIndices); _backIndices[j] = new TurboList <int>(initialCapacityIndices); if (hackable.infillMaterial != null && c.mats[j] == hackable.infillMaterial) { frontInfill = _frontIndices[j]; backInfill = _backIndices[j]; } } if (hackable.infillMaterial != null && frontInfill == null) { frontInfill = new TurboList <int>(1024); backInfill = new TurboList <int>(1024); } for (int j = 0; j < submeshCount; j++) { int initialCapacityIndices = Mathf.RoundToInt((float)c.indices[j].Length * factorOfSafetyIndices); int[] _indices = c.indices[j]; TurboList <int> frontIndices = _frontIndices[j]; TurboList <int> backIndices = _backIndices[j]; TurboList <int> splitPending = new TurboList <int>(initialCapacityIndices); int[] indices = new int[3]; for (int i = 0; i < _indices.Length;) { indices[0] = _indices[i++]; indices[1] = _indices[i++]; indices[2] = _indices[i++]; // compute the side of the plane each vertex is on PlaneTriResult r1 = sidePlanes[indices[0]]; PlaneTriResult r2 = sidePlanes[indices[1]]; PlaneTriResult r3 = sidePlanes[indices[2]]; if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane. { if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle. { frontIndices.AddArray(indices); } else { backIndices.AddArray(indices); } } else if (willSliceThisMesh) { splitPending.AddArray(indices); } } if (willSliceThisMesh) { splitTrianglesLH(plane, c.vertices.array, sidePlanes, splitPending.ToArray(), c, frontIndices, backIndices, hackable.infillMode, frontInfill, backInfill); } } if (hackable.infillMaterial != null) { bool alreadyPresent = System.Array.IndexOf <Material>(c.mats, hackable.infillMaterial) >= 0; if (!alreadyPresent) { int oldLength = c.mats.Length, newLength = c.mats.Length + 1; Material[] newMats = new Material[newLength]; System.Array.Copy(c.mats, newMats, oldLength); newMats[newLength - 1] = hackable.infillMaterial; c.mats = newMats; TurboList <int>[] indexArray; indexArray = new TurboList <int> [newLength]; System.Array.Copy(_backIndices, indexArray, oldLength); indexArray[newLength - 1] = backInfill; _backIndices = indexArray; indexArray = new TurboList <int> [newLength]; System.Array.Copy(_frontIndices, indexArray, oldLength); indexArray[newLength - 1] = frontInfill; _frontIndices = indexArray; submeshCount++; } } Vector3[] geoSubsetOne, geoSubsetTwo; Vector3[] normalsSubsetOne, normalsSubsetTwo; Vector2[] uvSubsetOne, uvSubsetTwo; BoneWeight[] weightSubsetOne, weightSubsetTwo; int[][] indexSubsetOne, indexSubsetTwo; indexSubsetOne = new int[submeshCount][]; indexSubsetTwo = new int[submeshCount][]; targetSubsetOne.Clear(); targetSubsetTwo.Clear(); int transferTableMaximumKey = c.vertices.Count; int[] transferTableOne = new int[transferTableMaximumKey]; int[] transferTableTwo = new int[transferTableMaximumKey]; for (int i = 0; i < transferTableOne.Length; i++) { transferTableOne[i] = -1; } for (int i = 0; i < transferTableTwo.Length; i++) { transferTableTwo[i] = -1; } for (int i = 0; i < submeshCount; i++) { perfectSubsetRD(_frontIndices[i], c.vertices, c.normals, c.UVs, c.weights, out indexSubsetOne[i], targetSubsetOne, ref transferTableOne); } for (int i = 0; i < submeshCount; i++) { perfectSubsetRD(_backIndices[i], c.vertices, c.normals, c.UVs, c.weights, out indexSubsetTwo[i], targetSubsetTwo, ref transferTableTwo); } //Note that we do not explicitly call recalculate bounds because (as per the manual) this is implicit in an //assignment to vertices whenever the vertex count changes from zero to non-zero. Mesh frontMesh = new Mesh(); Mesh backMesh = new Mesh(); var frontSMR = GetSkinnedMeshRendererWithName(frontObject, smr.name); var backSMR = GetSkinnedMeshRendererWithName(backObject, smr.name); if (targetSubsetOne.vertices.Count > 0) { frontSMR.materials = c.mats; frontSMR.sharedMesh = frontMesh; frontMesh.vertices = targetSubsetOne.vertices.ToArray(); frontMesh.normals = targetSubsetOne.normals.ToArray(); frontMesh.uv = targetSubsetOne.UVs.ToArray(); frontMesh.boneWeights = targetSubsetOne.weights.ToArray(); frontMesh.subMeshCount = submeshCount; frontMesh.bindposes = m.bindposes; for (int i = 0; i < submeshCount; i++) { frontMesh.SetTriangles(indexSubsetOne[i], i); } } else { GameObject.DestroyImmediate(frontSMR); } if (targetSubsetTwo.vertices.Count > 0) { backSMR.materials = c.mats; backSMR.sharedMesh = backMesh; backMesh.vertices = targetSubsetTwo.vertices.ToArray(); backMesh.normals = targetSubsetTwo.normals.ToArray(); backMesh.uv = targetSubsetTwo.UVs.ToArray(); backMesh.boneWeights = targetSubsetTwo.weights.ToArray(); backMesh.subMeshCount = submeshCount; backMesh.bindposes = m.bindposes; for (int i = 0; i < submeshCount; i++) { backMesh.SetTriangles(indexSubsetTwo[i], i); } } else { GameObject.DestroyImmediate(backSMR); } } var results = new GameObject[] { frontObject, backObject }; hackable.handleSlice(results); return(results); }
private void createResultObjects(GameObject go, Hackable sliceable, Dictionary <string, Transform> transformByName, Dictionary <string, bool> frontPresence, Dictionary <string, bool> backPresence, out GameObject frontObject, out GameObject backObject) { Transform goTransform = go.transform; bool useAlternateForFront, useAlternateForBack; if (sliceable.alternatePrefab == null) { useAlternateForFront = false; useAlternateForBack = false; } else { useAlternateForFront = sliceable.cloneAlternate(frontPresence); useAlternateForBack = sliceable.cloneAlternate(backPresence); } bool backIsNew = useAlternateForBack; if (backIsNew) { Object backSource = useAlternateForBack ? sliceable.alternatePrefab : go; backObject = (GameObject)GameObject.Instantiate(backSource); } else { backObject = go; } Object frontSource = useAlternateForFront ? sliceable.alternatePrefab : go; frontObject = (GameObject)GameObject.Instantiate(frontSource); handleHierarchy(frontObject.transform, frontPresence, transformByName); handleHierarchy(backObject.transform, backPresence, transformByName); Transform parent = goTransform.parent; Vector3 position = goTransform.localPosition; Vector3 scale = goTransform.localScale; Quaternion rotation = goTransform.localRotation; frontObject.transform.parent = parent; frontObject.transform.localPosition = position; frontObject.transform.localScale = scale; frontObject.transform.localRotation = rotation; frontObject.layer = go.layer; frontObject.name = "LHR Front"; backObject.name = "LHR Back"; if (backIsNew) { backObject.transform.parent = parent; backObject.transform.localPosition = position; backObject.transform.localScale = scale; backObject.transform.localRotation = rotation; backObject.layer = go.layer; GameObject.Destroy(go); } }