void FixHand(HandModel handModel, Side side, Transform wristOffset) { // Check errors if (handModel.fingers.Length == 0) { Debug.LogError("Fingers array is empty!"); return; } // Not all hands need an offset if (!wristOffset) { wristOffset = handModel.wrist.transformRef; } // Pinch center if (!handModel.pinchCenter) { GameObject pinchCenter = BasicHelpers.InstantiateEmptyChild(handModel.wrist.transformRef.parent.gameObject); pinchCenter.name = "PinchCenter"; PositionConstraint pinchPosConstraint = pinchCenter.AddComponent <PositionConstraint>(); ConstraintSource indexTipSource = new ConstraintSource(); indexTipSource.sourceTransform = handModel.index.fingerTip; indexTipSource.weight = 1.0f; ConstraintSource thumbTipSource = new ConstraintSource(); thumbTipSource.sourceTransform = handModel.thumb.fingerTip; thumbTipSource.weight = 1.0f; pinchPosConstraint.AddSource(indexTipSource); pinchPosConstraint.AddSource(thumbTipSource); pinchPosConstraint.translationOffset = Vector3.zero; pinchPosConstraint.constraintActive = true; handModel.pinchCenter = pinchCenter.transform; } // Throat center if (!handModel.throatCenter) { GameObject throatCenter = BasicHelpers.InstantiateEmptyChild(handModel.wrist.transformRef.parent.gameObject); throatCenter.name = "ThroatCenter"; PositionConstraint throatPosConstraint = throatCenter.AddComponent <PositionConstraint>(); ConstraintSource indexBaseSource = new ConstraintSource(); indexBaseSource.sourceTransform = handModel.index.fingerBase; indexBaseSource.weight = 1.0f; ConstraintSource thumbBaseSource = new ConstraintSource(); thumbBaseSource.sourceTransform = handModel.thumb.fingerBase; thumbBaseSource.weight = 1.0f; throatPosConstraint.AddSource(indexBaseSource); throatPosConstraint.AddSource(thumbBaseSource); throatPosConstraint.translationOffset = Vector3.zero; throatPosConstraint.constraintActive = true; handModel.throatCenter = throatCenter.transform; } // meanPoint meanPoint = Vector3.zero; for (int f = 0; f < handModel.fingers.Length; f++) { meanPoint += handModel.fingers[f].fingerBase.position; } meanPoint = meanPoint / handModel.fingers.Length; // palmRadius float meanDistance = 0.0f; for (int f = 0; f < handModel.fingers.Length; f++) { meanDistance += Vector3.Distance(meanPoint, handModel.fingers[f].fingerBase.position); } meanDistance = meanDistance / handModel.fingers.Length; palmRadius = meanDistance; // Palm center if (!handModel.palmCenter) { GameObject palmCenter = BasicHelpers.InstantiateEmptyChild(wristOffset.gameObject); palmCenter.name = "PalmCenter"; palmCenter.transform.position = meanPoint; if (side == Side.L) { palmCenter.transform.position += new Vector3(0.0f, fingerRadius, 0.0f); palmCenter.transform.localRotation = Quaternion.Euler(new Vector3(-90.0f, 0.0f, 0.0f)); } else { palmCenter.transform.position -= new Vector3(0.0f, fingerRadius, 0.0f); palmCenter.transform.localRotation = Quaternion.Euler(new Vector3(-90.0f, 0.0f, 180.0f)); } handModel.palmCenter = palmCenter.transform; } // Palm normal (depends on palmCenter) if (!handModel.palmNormal) { GameObject palmNormal = BasicHelpers.InstantiateEmptyChild(wristOffset.gameObject); palmNormal.name = "PalmNormal"; palmNormal.transform.position = handModel.palmCenter.position; if (side == Side.L) { palmNormal.transform.localRotation = Quaternion.Euler(new Vector3(-90.0f, 0.0f, 0.0f)); } else { palmNormal.transform.localRotation = Quaternion.Euler(new Vector3(90.0f, 0.0f, 0.0f)); } handModel.palmNormal = palmNormal.transform; } // Palm interior/exterior (depend on PalmCenter and palmRadius) if (!handModel.palmInterior) { GameObject palmInterior = BasicHelpers.InstantiateEmptyChild(wristOffset.gameObject); palmInterior.name = "PalmInterior"; palmInterior.transform.position = handModel.palmCenter.position; palmInterior.transform.rotation = handModel.palmCenter.rotation; palmInterior.transform.position += handModel.palmCenter.up * palmRadius; handModel.palmInterior = palmInterior.transform; } if (!handModel.palmExterior) { GameObject palmExterior = BasicHelpers.InstantiateEmptyChild(wristOffset.gameObject); palmExterior.name = "PalmExterior"; palmExterior.transform.position = handModel.palmCenter.position; palmExterior.transform.rotation = handModel.palmCenter.rotation; palmExterior.transform.position -= handModel.palmCenter.up * palmRadius; handModel.palmExterior = palmExterior.transform; } // Ray line (depend on PalmCenter) if (!handModel.ray) { GameObject ray = BasicHelpers.InstantiateEmptyChild(wristOffset.gameObject); ray.name = "Ray"; ray.transform.position = handModel.palmCenter.position; LineRenderer lineRenderer = ray.AddComponent <LineRenderer>(); lineRenderer.useWorldSpace = false; lineRenderer.SetPositions(new Vector3[] { Vector3.zero, new Vector3(0.0f, 0.0f, 0.5f) }); lineRenderer.material = rayMat; lineRenderer.startWidth = rayWidth; lineRenderer.endWidth = rayWidth; handModel.ray = ray.transform; } if (handModel is SlaveHandModel) { SlaveHandModel slaveHandModel = handModel as SlaveHandModel; // Palm trigger (depend on PalmCenter and palmRadius) if (!slaveHandModel.palmTrigger) { GameObject palmTrigger = BasicHelpers.InstantiateEmptyChild(wristOffset.gameObject); palmTrigger.name = "PalmTrigger"; palmTrigger.transform.position = handModel.palmCenter.position; SphereCollider trigger = palmTrigger.AddComponent <SphereCollider>(); trigger.isTrigger = true; trigger.radius = palmRadius; TriggerNotifier notifier = palmTrigger.AddComponent <TriggerNotifier>(); notifier.ignoreChildren = handModel.wrist.transformRef.parent; slaveHandModel.palmTrigger = notifier; } // Hand trigger (depend on PalmCenter and palmRadius) if (!slaveHandModel.handTrigger) { GameObject handTrigger = BasicHelpers.InstantiateEmptyChild(wristOffset.gameObject); handTrigger.name = "HandTrigger"; handTrigger.transform.position = handModel.palmCenter.position; SphereCollider trigger = handTrigger.AddComponent <SphereCollider>(); trigger.isTrigger = true; trigger.radius = Vector3.Distance(meanPoint, BasicHelpers.FurthestPoint(meanPoint, GetFingerTips(slaveHandModel))) + 0.02f; TriggerNotifier notifier = handTrigger.AddComponent <TriggerNotifier>(); notifier.ignoreChildren = handModel.wrist.transformRef.parent; slaveHandModel.handTrigger = notifier; } } // Colliders, Rigidbodies and Joitsn if needed if (handModel is SlaveHandModel) { // Setup colliders, rbs and joints for slave SetupPhysics(handModel as SlaveHandModel, wristOffset, meanPoint, palmRadius, fingerRadius); } }