private void Start() { menuAudio = GetComponent <AudioSource>(); LeftHand = new HandContact(); RightHand = new HandContact(); PlayerHead = Camera.main.gameObject.transform; PlayerPositionTracker = new GameObject().transform; //gameMgr = FindTaggedObject("GameController").GetComponent<GameManager>(); //transform.right = GameManager.Instance.BoardForward; // remove this and it works fine transform.eulerAngles = new Vector3(0, GameManager.Instance.calibratedObject.eulerAngles.y - 90, 0); RightHand.handTransform = FindTaggedObject("HandR").transform; LeftHand.handTransform = FindTaggedObject("HandL").transform; //AlbumTiles = new Album[SongLibrary.Length]; AlbumTiles = new Album[GameManager.Instance.songLoader.songLibrary.songs.Count]; for (int i = 0; i < AlbumTiles.Length; i++) { AlbumTiles[i] = new Album(); AlbumTiles[i].AlbumObject = GameObject.Instantiate(AlbumPrefab, transform); Material NewAlbumCover = new Material(AlbumCoverMat); NewAlbumCover.SetTexture("_MainTex", GameManager.Instance.songLoader.songLibrary.songs[i].albumArt); AlbumTiles[i].AlbumMat = AlbumTiles[i].AlbumObject.GetComponentInChildren <Renderer>(); AlbumTiles[i].AlbumMat.material = NewAlbumCover; //NewAlbumCover.SetTexture("_MainTex", SongLibrary[i].AlbumCover); } }
//public HighscoreManager highscoreMgr; private void Start() { MenuRatchetAudio = GetComponent <AudioSource>(); LeftHand = new HandContact(); RightHand = new HandContact(); PlayerHead = Camera.main.gameObject.transform; PlayerPositionTracker = new GameObject().transform; //transform.right = GameManager.Instance.BoardForward; // remove this and it works fine transform.eulerAngles = new Vector3(0, GameManager.Instance.calibratedObject.eulerAngles.y - 90, 0); RightHand.handTransform = ArmPositioning.RightHandInstance.transform; LeftHand.handTransform = ArmPositioning.LeftHandInstance.transform; GenerateTiles(); }
void CheckHandSlider(HandContact handContact) { if (WithinDonut(handContact.handTransform.position, transform.position, MenuRadius, MenuRadius + 5, MenuHeight)) { handContact.currentContactVector = handContact.handTransform.position - transform.position; handContact.currentContactVector.Normalize(); if (!handContact.inContact) { handContact.inContact = true; handContact.startingContactVector = handContact.currentContactVector; handContact.menuSliderValueOnContact = MenuSlider; } else { handContact.contactAngle = Vector3.SignedAngle(handContact.startingContactVector, handContact.currentContactVector, Vector3.up); } } else { handContact.inContact = false; } }
public bool IsConnected(HandContact other) { return(Vector3.Distance(targetWorldPos, other.targetWorldPos) <= Vector3.Distance(objectUnscaledLocalPos, other.objectUnscaledLocalPos)); }
public void ProposeContacts(HandState state) { lastPos = thisPos; thisPos = state.GetBonePosition(b); deltaPos = thisPos - lastPos; lastRot = thisRot; thisRot = state.GetBoneAngle(b); deltaRot = Quaternion.Inverse(lastRot) * thisRot; contactsAccepted = new Dictionary <GameObject, List <HandContact> >(); for (int c = 0; c < HandState.BONE_CAPSULEPART_COUNT[b]; c++) { CapsulePart part = state.boneCapsules[b][c]; capsules[c].transform.localPosition = part.boneOffsetPos; capsules[c].transform.localRotation = part.boneOffsetAng; CapsuleCollider capc = capsules[c].GetComponent <CapsuleCollider>(); capc.height = part.length + (part.radius - TrueHandlingPhysics.kinematicBoneRetraction) * 2.0f; capc.radius = part.radius - TrueHandlingPhysics.kinematicBoneRetraction; } kinematicRoot.GetComponent <Rigidbody>().MovePosition(lastPos); kinematicRoot.GetComponent <Rigidbody>().MoveRotation(lastRot); main.boneMaterialOverride[h, b] = null; contactProposals = new Dictionary <GameObject, HandContact[]>(); for (int p = 0; p < HandState.BONE_CAPSULEPART_COUNT[b]; p++) { Dictionary <Collider, HandContact> lastPersistence = contactPersistence[p]; Dictionary <Collider, HandContact> nextPersistence = new Dictionary <Collider, HandContact>(); // USING CURRENT RADIUS/LENGTH/OFFSETPOS/OFFSETANG INSTEAD OF LAST, MIGHT BE WRONG BY A TINY BIT CapsulePart part = state.boneCapsules[b][p]; Vector3 lastCapsulePos = lastPos + (lastRot * part.boneOffsetPos); Quaternion lastCapsuleRot = lastRot * part.boneOffsetAng; Vector3 thisCapsulePos = thisPos + (thisRot * part.boneOffsetPos); Quaternion thisCapsuleRot = thisRot * part.boneOffsetAng; Vector3 lastOffset = lastCapsuleRot * (Vector3.forward * part.length * 0.5f); int hits = Physics.OverlapCapsuleNonAlloc(lastCapsulePos + lastOffset, lastCapsulePos - lastOffset, part.radius, main.triggerBuffer, main.handCollisionLayerCollideMask); for (int i = 0; i < hits; i++) { Collider other = main.triggerBuffer[i]; if (other.attachedRigidbody == null) { continue; } GameObject obj = other.attachedRigidbody == null ? other.gameObject : other.attachedRigidbody.gameObject; HandContact contact; if (lastPersistence.ContainsKey(other)) { //pen = CapsulePenetration.TestFixedNormal(lastCapsulePos, lastCapsuleRot, part.length, part.radius, other, other.transform.position, other.transform.rotation, other.transform.rotation * lastPersistence[other].objectLocalNormal); contact = lastPersistence[other]; } else { CapsulePenetrationData pen = CapsulePenetration.Test(lastCapsulePos, lastCapsuleRot, part.length, part.radius, other, other.transform.position, other.transform.rotation); if (pen == null) { continue; } // If the contact point is inside another capsule, skip it // This is only running to prevent the contact from being created, but the finger can bend/object can move such that // an existing contact violates this. To fix that is hard though, because the target point on the capsule surface // can move when fingers rotate bool pinched = false; for (int b2 = 0; b2 < HandState.NUM_BONES; b2++) { Vector3 bp = state.GetBonePosition(b2); Quaternion ba = state.GetBoneAngle(b2); for (int p2 = 0; p2 < HandState.BONE_CAPSULEPART_COUNT[b2]; p2++) { if (b2 == b && p2 == p) { continue; } CapsulePart otherPart = state.boneCapsules[b2][p2]; Vector3 cp = bp + (ba * otherPart.boneOffsetPos); Quaternion ca = ba * otherPart.boneOffsetAng; Vector3 localHit = Quaternion.Inverse(ca) * (pen.hitPos - cp); // Intersection with the endcap doesn't count, so you can grab with outside of bent fingers if (localHit.z < -otherPart.length * 0.5f || localHit.z > otherPart.length * 0.5f) { continue; } Vector3 axPos = new Vector3(0, 0, localHit.z); if (Vector3.Distance(localHit, axPos) < otherPart.radius) { pinched = true; break; } } if (pinched) { break; } } if (pinched) { continue; } contact = new HandContact(); contact.capsuleAxisFraction = pen.capsuleHitFraction; contact.objectLocalNormal = Quaternion.Inverse(other.transform.rotation) * pen.hitNorm; contact.objectSurfaceUnscaledLocalPos = Quaternion.Inverse(other.transform.rotation) * (pen.hitPos - other.transform.position); contact.objectUnscaledLocalPos = contact.objectSurfaceUnscaledLocalPos + contact.objectLocalNormal * part.radius; contact.h = h; contact.b = b; contact.p = p; contact.otherCollider = other; } //project the capsule pos onto the capsule axis Vector3 capsuleLocalHitPos = new Vector3(0f, 0f, (contact.capsuleAxisFraction - 0.5f) * part.length); contact.targetWorldPos = thisCapsulePos + (thisCapsuleRot * capsuleLocalHitPos); contact.boneRotationDelta = deltaRot; nextPersistence[other] = contact; //Gizmoz.DrawLine(pen.hitPos, pen.hitPos - pen.capsuleDepenetrationTranslation, Color.red); //main.boneMaterialOverride[h, b] = main.touchingMaterial; HandContact[] contacts; if (contactProposals.ContainsKey(obj)) { HandContact[] oldContacts = contactProposals[obj]; contacts = new HandContact[oldContacts.Length + 1]; for (int i2 = 0; i2 < oldContacts.Length; i2++) { contacts[i2] = oldContacts[i2]; } } else { contacts = new HandContact[1]; } contacts[contacts.Length - 1] = contact; contactProposals[obj] = contacts; } contactPersistence[p] = nextPersistence; } }
private void Update() { CheckHandSlider(LeftHand); CheckHandSlider(RightHand); if (LeftHand.inContact && MenuSliderHand != UsingHand.rightHand) { MenuSliderHand = UsingHand.leftHand; } else if (RightHand.inContact && MenuSliderHand != UsingHand.leftHand) { MenuSliderHand = UsingHand.rightHand; } else { MenuSliderHand = UsingHand.noHand; } if (MenuSliderHand != UsingHand.noHand) { HandContact HandTouch = new HandContact(); if (MenuSliderHand == UsingHand.leftHand) { HandTouch = LeftHand; } else if (MenuSliderHand == UsingHand.rightHand) { HandTouch = RightHand; } float ContactAngle = HandTouch.contactAngle; if (!MovingMenuSlider) { MovingMenuSlider = true; PreContactMenuSlider = MenuSlider; } else { MenuSlider = PreContactMenuSlider + ContactAngle / 18; } } else { MovingMenuSlider = false; } /* * SliderVelocity = Input.GetAxis("Horizontal")/5; * * SliderVelocity = Mathf.Lerp(SliderVelocity, 0, Time.deltaTime*(10/SliderVelocity)); * * MenuSlider += SliderVelocity;*/ if (MenuSlider < 0) { MenuSlider = 0; } else if (MenuSlider > AlbumTiles.Length - 1) { MenuSlider = AlbumTiles.Length - 1; } currentlySelected = (int)(MenuSlider + 0.5f); if (!LeftHand.inContact && !RightHand.inContact) { MenuSlider = Mathf.Lerp(MenuSlider, currentlySelected, Time.deltaTime * 5); } float ConvertToRadians = (Mathf.PI / 180f); float selectedAngle = (startangle - transform.eulerAngles.y) * ConvertToRadians; for (int i = 0; i < AlbumTiles.Length; i++) { float TileOffsetRad = TileOffsetDegrees * ConvertToRadians; float radRotationY = transform.eulerAngles.y * ConvertToRadians; //Debug.Log("rad" + TileOffsetRad); float angleRad = TileOffsetRad * i - MenuSlider * TileOffsetRad; angleRad -= radRotationY; /* * angleRad *= 180f / Mathf.PI; * * angleRad -= transform.eulerAngles.y; * * angleRad *= (Mathf.PI / 180f);*/ float transparency = 1 - Mathf.Abs(MenuSlider - i) / 4f; float ScaleValue = MenuRadius; if (transparency < 0) { transparency = 0; } if (i == currentlySelected) { ScaleValue = 1.5f * MenuRadius; transparency = 1; angleRad = selectedAngle; } AlbumTiles[i].AlbumObject.transform.position = new Vector3(transform.position.x + MenuRadius * Mathf.Cos(angleRad), transform.position.y, transform.position.z + MenuRadius * Mathf.Sin(angleRad)); AlbumTiles[i].AlbumMat.material.color = new Color(1, 1, 1, transparency); AlbumTiles[i].AlbumObject.transform.LookAt(transform); AlbumTiles[i].AlbumObject.transform.localScale = Vector3.Lerp(AlbumTiles[i].AlbumObject.transform.localScale, Vector3.one * ScaleValue, Time.deltaTime * 5); if (transparency == 0) { AlbumTiles[i].AlbumMat.enabled = false; } else if (!AlbumTiles[i].AlbumMat.enabled) { AlbumTiles[i].AlbumMat.enabled = true; } } //AlbumTiles[currentlySelected].AlbumObject.transform.localPosition += AlbumTiles[currentlySelected].AlbumObject.transform.forward * 0.08f * MenuRadius; AlbumTiles[currentlySelected].AlbumObject.transform.position += AlbumTiles[currentlySelected].AlbumObject.transform.forward * 0.08f * MenuRadius; //AlbumTiles[currentlySelected].AlbumObject.transform.localPosition += -transform.right * 0.08f * MenuRadius; }
void FixedUpdatePropagation(object sender, object noArgs) { HandState[] states = { source.GetHandState(false), source.GetHandState(true) }; Dictionary <GameObject, List <HandContact> > objContacts = new Dictionary <GameObject, List <HandContact> >(); for (int h = 0; h < 2; h++) { HandState state = states[h]; if (state.active) { if (boneManager[h, 0] == null) { for (int b = 0; b < HandState.NUM_BONES; b++) { boneManager[h, b] = new PhysicsBoneManager(this, state, b); } } for (int b = 0; b < HandState.NUM_BONES; b++) { boneManager[h, b].ProposeContacts(state); //add contacts to dataset to prune stretched ones foreach (var kv in boneManager[h, b].contactProposals) { GameObject obj = kv.Key; if (!objContacts.ContainsKey(obj)) { objContacts[obj] = new List <HandContact>(); } foreach (HandContact contact in kv.Value) { objContacts[obj].Add(contact); } } } } else { if (boneManager[h, 0] != null) { for (int b = 0; b < HandState.NUM_BONES; b++) { boneManager[h, b].Cleanup(); boneManager[h, b] = null; } } } } Dictionary <GameObject, HashSet <HandContact> > filteredHandContacts = new Dictionary <GameObject, HashSet <HandContact> >(); // Find contact pairs that have "stretched" meaning the bones are farther apart than when they touched the object, and cluster them. // TODO: Instead of this, break connections when the contact point on the finger is "above" the contact point on the object // based on the normal. that way you can pick up concave objects from the inside foreach (var kv in objContacts) { GameObject obj = kv.Key; HandContact[] contacts = kv.Value.ToArray(); List <HashSet <HandContact> > connectedComponents = new List <HashSet <HandContact> >(); for (int a = 0; a < contacts.Length; a++) { HashSet <HandContact> ourSet = new HashSet <HandContact>(); ourSet.Add(contacts[a]); connectedComponents.Add(ourSet); } for (int a = 0; a < contacts.Length - 1; a++) { HandContact first = contacts[a]; HashSet <HandContact> ourSet = null; foreach (HashSet <HandContact> comp in connectedComponents) { if (comp.Contains(first)) { ourSet = comp; } } Debug.Assert(ourSet != null); for (int b = a + 1; b < contacts.Length; b++) { HandContact second = contacts[b]; HashSet <HandContact> theirSet = null; foreach (HashSet <HandContact> comp in connectedComponents) { if (comp.Contains(second)) { theirSet = comp; } } if (ourSet == theirSet) { continue; } Debug.Assert(theirSet != null); if (first.IsConnected(second)) { ourSet.UnionWith(theirSet); connectedComponents.Remove(theirSet); } } } List <HashSet <HandContact> > fullyConstrainedConnectedComponents = new List <HashSet <HandContact> >(); foreach (HashSet <HandContact> component in connectedComponents) { HandContact[] componentArray = new HandContact[component.Count]; component.CopyTo(componentArray); bool fullyConstrained = false; // Decides if object is fully constrained ("held"), TODO try globally reasoning about all contacts for (int a = 0; a < componentArray.Length - 1; a++) { for (int b = a + 1; b < componentArray.Length; b++) { HandContact ca = componentArray[a]; HandContact cb = componentArray[b]; if (ca.h == cb.h) { if (ca.b == cb.b || HandState.POINT_PARENT[ca.b] == cb.b || HandState.POINT_PARENT[cb.b] == ca.b) { continue; } } if (Vector3.Dot(ca.objectLocalNormal, cb.objectLocalNormal) < 0.01) { // Skip points where the object could easily rotate out of grip Vector3 offset = Vector3.Normalize(ca.objectSurfaceUnscaledLocalPos - cb.objectSurfaceUnscaledLocalPos); float thresh = 0.5f; if (Mathf.Abs(Vector3.Dot(ca.objectLocalNormal, offset)) < thresh || Mathf.Abs(Vector3.Dot(cb.objectLocalNormal, offset)) < thresh) { continue; } fullyConstrained = true; } } } // Don't hold objects unless one of the bones is a fingertip, TODO make the system better so this isn't necessary bool hasFingertip = false; for (int a = 0; a < componentArray.Length; a++) { //hasFingertip |= componentArray[a].b == 2; //second from thumbtip hasFingertip |= componentArray[a].b == 3; hasFingertip |= componentArray[a].b == 7; hasFingertip |= componentArray[a].b == 11; //hasFingertip |= componentArray[a].b == 15; //hasFingertip |= componentArray[a].b == 19; } if (fullyConstrained && hasFingertip) { fullyConstrainedConnectedComponents.Add(component); } } if (fullyConstrainedConnectedComponents.Count > 0) { //TODO: prioritize better fullyConstrainedConnectedComponents.Sort((x, y) => y.Count.CompareTo(x.Count)); filteredHandContacts[obj] = fullyConstrainedConnectedComponents[0]; } } Dictionary <GameObject, Vector3> movedObjectPos = new Dictionary <GameObject, Vector3>(); Dictionary <GameObject, Quaternion> movedObjectAng = new Dictionary <GameObject, Quaternion>(); foreach (var kv in filteredHandContacts) { GameObject obj = kv.Key; Rigidbody rigid = obj.GetComponent <Rigidbody>(); if (rigid == null) { continue; } HashSet <HandContact> contacts = kv.Value; List <ObjectMotionSolutionUnit> solveUnits = new List <ObjectMotionSolutionUnit>(); Vector3 objectLocalAxisPositionCentroid = Vector3.zero; Vector3 targetWorldAxisPositionCentroid = Vector3.zero; foreach (HandContact contact in contacts) { ObjectMotionSolutionUnit piece = new ObjectMotionSolutionUnit(contact, obj.transform.rotation); // states[h].boneCapsules[b][contact.capsuleIndex], bonePos, boneAng, oldBoneAng, obj.transform); solveUnits.Add(piece); objectLocalAxisPositionCentroid += piece.objectLocalAxisPosition; targetWorldAxisPositionCentroid += piece.targetWorldAxisPosition; //Vector3 p1 = obj.transform.position + obj.transform.rotation * contact.objectUnscaledLocalPos; //Gizmoz.DrawLine(p1, p1 + obj.transform.TransformDirection(contact.objectLocalNormal)*0.01f, Color.green); //Gizmoz.DrawLine(p1, piece.targetWorldAxisPosition, Color.white); //Vector3 p2 = obj.transform.position + obj.transform.rotation * contact.objectSurfaceUnscaledLocalPos; //Gizmoz.DrawLine(p2, piece.targetWorldAxisPosition, Color.cyan); } objectLocalAxisPositionCentroid /= solveUnits.Count; targetWorldAxisPositionCentroid /= solveUnits.Count; //world axis position + 4 for tetrahetron for rotation alignment int l = solveUnits.Count * 5; double[,] A = new double[3, l]; double[,] B = new double[3, l]; int cur = 0; float mainScale = 20f; foreach (ObjectMotionSolutionUnit unit in solveUnits) { FillMatrixColumn(A, cur, mainScale * (unit.objectLocalAxisPosition - objectLocalAxisPositionCentroid)); FillMatrixColumn(B, cur, mainScale * (unit.targetWorldAxisPosition - targetWorldAxisPositionCentroid)); cur++; for (int t = 0; t < 4; t++) { FillMatrixColumn(A, cur, unit.GetFromTetrahedron(t)); FillMatrixColumn(B, cur, unit.GetToTetrahedron(t)); cur++; } } Debug.Assert(cur == l); double[,] BAT = new double[3, 3]; alglib.rmatrixgemm(3, 3, l, 1, B, 0, 0, 0, A, 0, 0, 1, 0, ref BAT, 0, 0); double[] W = new double[3]; double[,] U = new double[3, 3]; double[,] VT = new double[3, 3]; alglib.rmatrixsvd(BAT, 3, 3, 2, 2, 2, out W, out U, out VT); double[,] UVT = new double[3, 3]; alglib.rmatrixgemm(3, 3, 3, 1, U, 0, 0, 0, VT, 0, 0, 0, 0, ref UVT, 0, 0); double sqrtThing = 1 + UVT[0, 0] + UVT[1, 1] + UVT[2, 2]; if (sqrtThing <= 0) { Debug.Log("matrix solution error"); sqrtThing = 0.0001; } double w = System.Math.Sqrt(sqrtThing) / 2.0; double iw4 = 1.0 / (w * 4); Quaternion rotation = new Quaternion((float)((UVT[2, 1] - UVT[1, 2]) * iw4), (float)((UVT[0, 2] - UVT[2, 0]) * iw4), (float)((UVT[1, 0] - UVT[0, 1]) * iw4), (float)w); rotation.Normalize(); Vector3 pos = targetWorldAxisPositionCentroid - rotation * objectLocalAxisPositionCentroid; movedObjectPos[obj] = pos; movedObjectAng[obj] = rotation; } //setup kinematic carriers LinkedList <GameObject> carriersToRemove = new LinkedList <GameObject>(); foreach (var kv in objectCarriers) { if (!movedObjectPos.ContainsKey(kv.Key)) { carriersToRemove.AddLast(kv.Key); } } foreach (GameObject obj in carriersToRemove) { objectCarriers[obj].GetComponent <FixedJoint>().connectedBody = null; //NECESSARY BECAUSE IT WONT DESTROY TIL AFTER THE PHYSICS UPDATE Destroy(objectCarriers[obj]); objectCarriers.Remove(obj); //if (objectCarrierProxies.ContainsKey(obj)) //{ // Destroy(objectCarrierProxies[obj]); // objectCarrierProxies.Remove(obj); // } } foreach (var kv in movedObjectPos) { GameObject obj = kv.Key; Vector3 pos = kv.Value; Quaternion ang = movedObjectAng[obj]; if (!objectCarriers.ContainsKey(obj)) { GameObject car = objectCarriers[obj] = new GameObject("car"); car.transform.parent = transform; car.transform.position = obj.transform.position; car.transform.rotation = obj.transform.rotation; Rigidbody r = car.AddComponent <Rigidbody>(); r.isKinematic = true; FixedJoint f = car.AddComponent <FixedJoint>(); f.enablePreprocessing = false; f.autoConfigureConnectedAnchor = false; f.connectedBody = obj.GetComponent <Rigidbody>(); f.anchor = Vector3.zero; f.connectedAnchor = Vector3.zero; } Rigidbody rig = objectCarriers[obj].GetComponent <Rigidbody>(); rig.MovePosition(pos); rig.MoveRotation(ang); } // Was used for IK /* * List<IKPointTarget> pointTargetsList = new List<IKPointTarget>(); * foreach (var objList in stretching) * { * GameObject obj = objList.Key; * * for (int h = 0; h < 2; h++) * { * if (!states[h].active) * { * continue; * } * * for (int b = 0; b < HandState.NUM_BONES; b++) * { * Dictionary<GameObject, CapsuleContactPoint[]> proposal = boneManager[h, b].contactJointProposals; * * //only ik constrain fingertips FINGERFILTER * if (b % 4 != 3 || b>7) * { * continue; * } * * if (proposal.ContainsKey(objList.Key)) * { * CapsuleContactPoint[] contacts = proposal[objList.Key]; * Debug.Assert(contacts.Length > 0); * * foreach (CapsuleContactPoint contact in contacts) * { * IKPointTarget next = new IKPointTarget(); * next.h = h; * next.b = b; * next.localPos = states[h].boneCapsules[b][contact.capsuleIndex].AxisFractionToBonePosition(contact.axisFraction); * Vector3 unscaledLocal = obj.transform.InverseTransformDirection(obj.transform.TransformVector(contact.otherPos)) + contact.otherNormal* states[h].boneCapsules[b][contact.capsuleIndex].radius; * next.worldTargetPos = estimatedObjectPos[obj] + estimatedObjectAng[obj] * unscaledLocal; * pointTargetsList.Add(next); * } * } * } * } * } * IKGapTarget[] gapTargets = new IKGapTarget[0]; * IKPointTarget[] pointTargets = pointTargetsList.ToArray(); * FABRIK.Solve(states, pointTargets, gapTargets); */ for (int h = 0; h < 2; h++) { HandState state = states[h]; if (state.active) { for (int b = 0; b < HandState.NUM_BONES; b++) { boneManager[h, b].UpdateNoCollides(state, movedObjectPos, movedObjectAng); } } } }
public ObjectMotionSolutionUnit(HandContact ccp_, Quaternion currentAngle) { objectLocalAxisPosition = ccp_.objectUnscaledLocalPos; targetWorldAxisPosition = ccp_.targetWorldPos; objectRotation = ccp_.boneRotationDelta * currentAngle; }