public void FillTempBone(int generalBoneID, int lastActiveID) { int id = tempPreviewBones.Count; CharacterBone characterBone = characterBones[generalBoneID]; if (characterBone.selected) { PreviewBone parentBone = null; if (lastActiveID != -1) { parentBone = tempPreviewBones[lastActiveID]; if (parentBone.childIDs == null) { parentBone.childIDs = new List <int>(); } parentBone.childIDs.Add(id); } tempPreviewBones.Add(new PreviewBone(characterBone.tr, generalBoneID, lastActiveID)); lastActiveID = id; } if (characterBone.childIDs != null) { for (int i = 0; i < characterBone.childIDs.Count; i++) { int childId = characterBone.childIDs[i]; FillTempBone(childId, lastActiveID); } } }
public void CalculateRotationAndBoundsSingleChild(PreviewBone bone, int id) { Vector3 childPos = tempPreviewBones[bone.childIDs[id]].tr.position; bone.direction = childPos - bone.tr.position; bone.rotation = Quaternion.Inverse(transform.rotation) * Quaternion.LookRotation(bone.direction, transform.forward); bone.bounds.center = new Vector3(bone.bounds.center.x, bone.bounds.center.y, bone.direction.magnitude / 2); bone.bounds.size = new Vector3(bone.bounds.size.x, bone.bounds.size.y, bone.direction.magnitude); bone.capsuleBounds.SetSize(bone.bounds.size); }
private void ColliderSettings() { tgt.showColliderSettings = EditorGUILayout.Foldout(tgt.showColliderSettings, "Collider"); tgt.showJointSettings = !tgt.showColliderSettings; if (!tgt.showColliderSettings) { return; } PreviewBone bone = tgt.previewBones[tgt.selectedBoneID]; bone.ColliderType = (ColliderType)EditorGUILayout.EnumPopup("Collider Type", bone.ColliderType); bone.bounds.center = EditorGUILayout.Vector3Field("Center", bone.bounds.center); switch (bone.colliderType) { case ColliderType.Box: bone.bounds.size = EditorGUILayout.Vector3Field("Size", bone.bounds.size); break; case ColliderType.Capsule: bone.capsuleBounds.height = EditorGUILayout.FloatField("Height", bone.capsuleBounds.height); bone.capsuleBounds.radius = EditorGUILayout.FloatField("Radius", bone.capsuleBounds.radius); bone.capsuleBounds.direction = (CapsuleDirection)EditorGUILayout.EnumPopup("Direction", bone.capsuleBounds.direction); bone.bounds.size = bone.capsuleBounds.GetSize(); break; case ColliderType.Sphere: bone.capsuleBounds.radius = EditorGUILayout.FloatField("Radius", bone.capsuleBounds.radius); bone.capsuleBounds.height = bone.capsuleBounds.radius * 2; bone.bounds.size = bone.capsuleBounds.GetSize(); break; } EditorGUILayout.Space(); tgt.rotationHandle = EditorGUILayout.Toggle("Edit Bone Rotation", tgt.rotationHandle); EditorGUI.BeginDisabledGroup(!tgt.rotationHandle); EditorGUI.BeginChangeCheck(); Vector3 rot = bone.rotation.eulerAngles; rot = EditorGUILayout.Vector3Field("Rotation", rot); if (EditorGUI.EndChangeCheck()) { bone.rotation = Quaternion.Euler(rot); } EditorGUI.EndDisabledGroup(); }
private bool CheckAndBeginLineDrag() { //click on bone if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { foreach (PreviewBone bone in tgt.avatar.previewBones) { if (bone.rect.Contains(Event.current.mousePosition)) { lineStartBone = bone; lineDrag = true; return(true); } } } return(false); }
public void CalculateRotationAndBounds(PreviewBone bone) { if (bone.childIDs == null || bone.childIDs.Count == 0) { //end bones without childs (for example: head, hand, foot) bone.direction = bone.IsRoot ? bone.tr.up : tempPreviewBones[bone.parentID].direction; bone.direction = bone.direction.AlignDirectionTo(bone.tr); if (bone.rotation == Quaternion.identity) { bone.rotation = Quaternion.Inverse(transform.rotation) * Quaternion.LookRotation(bone.direction, transform.forward); } if (bone.bounds.center == Vector3.zero) { bone.bounds.center = Vector3.forward * bone.bounds.size.z / 2; } } else if (bone.childIDs.Count == 1) { //intermediate bones with one child(upper/lower arm/leg, stomach) CalculateRotationAndBoundsSingleChild(bone, 0); } else if (bone.childIDs.Count > 1) { //bones with many childs (hip, chest) //main bone search float dot = -1; int id = 0; for (int i = 0; i < bone.childIDs.Count; i++) { Vector3 childPos1 = tempPreviewBones[bone.childIDs[i]].tr.position; Vector3 localAbsDir = bone.tr.InverseTransformDirection(childPos1 - bone.tr.position).Abs(); float tempDot = Mathf.Max(Vector3.Dot(Vector3.up, localAbsDir), Vector3.Dot(Vector3.right, localAbsDir), Vector3.Dot(Vector3.forward, localAbsDir)); if (tempDot > dot) { dot = tempDot; id = i; } } CalculateRotationAndBoundsSingleChild(bone, id); } }
private void MassSettings() { PreviewBone bone = tgt.previewBones[tgt.selectedBoneID]; float fullMassInPercent = 0; for (int i = 0; i < tgt.previewBones.Count; i++) { if (tgt.selectedBoneID == i) { continue; } fullMassInPercent += tgt.previewBones[i].massInPercent; } EditorGUI.BeginDisabledGroup(fullMassInPercent >= 1); bone.massInPercent = EditorGUILayout.Slider("Mass In Percent", bone.massInPercent, 0, 1 - fullMassInPercent); EditorGUILayout.LabelField("Mass " + (tgt.mass * bone.massInPercent).ToString("0.00") + " kg out of " + (tgt.mass * (fullMassInPercent + bone.massInPercent)).ToString("0.00")); EditorGUI.EndDisabledGroup(); }
private void DrawJointHandles() { if (tgt.previewBones[tgt.selectedBoneID].IsRoot || !tgt.showJointSettings) { return; } PreviewBone bone = tgt.previewBones[tgt.selectedBoneID]; Quaternion globalRot = tgt.transform.rotation * bone.rotation; if (tgt.rotationHandle) { Quaternion rot = globalRot * Quaternion.LookRotation(Vector3.Cross(bone.axis, bone.swingAxis), bone.swingAxis); EditorGUI.BeginChangeCheck(); rot = Quaternion.Inverse(globalRot) * Handles.RotationHandle(rot, bone.tr.position); if (EditorGUI.EndChangeCheck()) { bone.axis = -Vector3.Cross(rot * Vector3.forward, bone.swingAxis).Round(2); bone.swingAxis = (rot * Vector3.up).Round(2); } } Matrix4x4 jointMatrix = Matrix4x4.TRS(bone.tr.position, globalRot * Quaternion.LookRotation(Vector3.Cross(bone.axis, bone.swingAxis), bone.swingAxis), Vector3.one); using (new Handles.DrawingScope(jointMatrix)) { jointAngularLimitHandle.xMin = bone.lowTwistLimit; jointAngularLimitHandle.xMax = bone.highTwistLimit; jointAngularLimitHandle.yMin = -bone.swing1Limit; jointAngularLimitHandle.yMax = bone.swing1Limit; jointAngularLimitHandle.zMin = -bone.swing2Limit; jointAngularLimitHandle.zMax = bone.swing2Limit; EditorGUI.BeginChangeCheck(); jointAngularLimitHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { bone.lowTwistLimit = jointAngularLimitHandle.xMin; bone.highTwistLimit = jointAngularLimitHandle.xMax; bone.swing1Limit = jointAngularLimitHandle.yMax == bone.swing1Limit ? -jointAngularLimitHandle.yMin : jointAngularLimitHandle.yMax; bone.swing2Limit = jointAngularLimitHandle.zMax == bone.swing2Limit ? -jointAngularLimitHandle.zMin : jointAngularLimitHandle.zMax; } } }
public void CopyTo(PreviewBone bone, bool mirror) { bone.massInPercent = massInPercent; if (!mirror) { bone.rotation = rotation; } bone.colliderType = colliderType; bone.bounds = bounds; bone.capsuleBounds = capsuleBounds; bone.axis = axis; bone.swingAxis = swingAxis; bone.lowTwistLimit = lowTwistLimit; bone.highTwistLimit = highTwistLimit; bone.swing1Limit = swing1Limit; bone.swing2Limit = swing2Limit; }
public PreviewBone(PreviewBone avatarBone) { characterBoneId = -1; parentID = avatarBone.parentID; childIDs = avatarBone.childIDs; name = avatarBone.name; massInPercent = avatarBone.massInPercent; rotation = avatarBone.rotation; colliderType = avatarBone.colliderType; bounds = avatarBone.bounds; capsuleBounds = avatarBone.capsuleBounds; axis = avatarBone.axis; swingAxis = avatarBone.swingAxis; lowTwistLimit = avatarBone.lowTwistLimit; highTwistLimit = avatarBone.highTwistLimit; swing1Limit = avatarBone.swing1Limit; swing2Limit = avatarBone.swing2Limit; }
private void JointSettings() { tgt.showJointSettings = EditorGUILayout.Foldout(tgt.showJointSettings, "Joint"); tgt.showColliderSettings = !tgt.showJointSettings; if (!tgt.showJointSettings) { return; } PreviewBone bone = tgt.previewBones[tgt.selectedBoneID]; bone.lowTwistLimit = Mathf.Clamp(EditorGUILayout.FloatField("Low Twist Limit", bone.lowTwistLimit), -180, 180); bone.highTwistLimit = Mathf.Clamp(EditorGUILayout.FloatField("High Twist Limit", bone.highTwistLimit), -180, 180); bone.swing1Limit = Mathf.Clamp(EditorGUILayout.FloatField("Swing 1 Limit", bone.swing1Limit), 0, 180); bone.swing2Limit = Mathf.Clamp(EditorGUILayout.FloatField("Swing 2 Limit", bone.swing2Limit), 0, 180); EditorGUILayout.Space(); tgt.rotationHandle = EditorGUILayout.Toggle("Edit Axis Rotation", tgt.rotationHandle); EditorGUI.BeginDisabledGroup(!tgt.rotationHandle); bone.axis = EditorGUILayout.Vector3Field("Axis", bone.axis); bone.swingAxis = EditorGUILayout.Vector3Field("Swing Axis", bone.swingAxis); EditorGUI.EndDisabledGroup(); }
private void DrawAvatarBonesHierarchy(int boneID, bool singleBranch) { if (boneID >= tgt.avatar.previewBones.Count) { Debug.LogError("Ragdoll avatar is damaged. Some bones are lost."); return; } PreviewBone bone = tgt.avatar.previewBones[boneID]; if (!singleBranch && bone.childIDs != null) { GUILayout.BeginVertical(); } //change color if connected bool isConnected = false; int characterBoneID = -1; for (int i = 0; i < tgt.characterBones.Count; i++) { if (bone.name.Equals(tgt.characterBones[i].avatarConnection)) { characterBoneID = i; isConnected = true; break; } } DrawBoneBox(bone.name, out bone.rect, Color.red, !isConnected); if (bone.childIDs != null) { if (bone.childIDs.Count > 1) { GUILayout.BeginHorizontal(); } for (int i = 0; i < bone.childIDs.Count; i++) { int id = bone.childIDs[i]; DrawAvatarBonesHierarchy(id, bone.childIDs.Count == 1); } if (bone.childIDs.Count > 1) { GUILayout.EndHorizontal(); } } if (!singleBranch && bone.childIDs != null) { GUILayout.EndVertical(); } //bottom line to childs if (!bone.IsRoot) { DrawBottomLineToChilds(bone.rect); } Handles.BeginGUI(); if (isConnected) { DrawConnector(bone.rect, tgt.characterBones[characterBoneID].rect, Color.gray, true); } Handles.EndGUI(); }
public override void OnInspectorGUI() { Undo.RecordObject(target, "RagdollConstructor"); if (!tgt.configureBonesMode) { //BEGIN SELECT ACTIVE BONES MODE //BEGIN CHARACTER BONES HIERARCHY EditorGUILayout.BeginVertical(GUILayout.MinHeight(240)); EditorGUILayout.LabelField("Character bones hierarchy."); scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); DrawBonesHierarchy(tgt.characterBones[0], true, false, true); EditorGUILayout.EndScrollView(); scrollRect = GUILayoutUtility.GetLastRect(); foreach (CharacterBone bone in tgt.characterBones) { bone.rect.position += scrollRect.position - scrollPosition; } EditorGUILayout.EndVertical(); if (ClickCharacterBone()) { tgt.FillTempBones(); Repaint(); return; } //END CHARACTER BONES HIERARCHY EditorGUILayout.Space(); EditorGUILayout.BeginVertical("HelpBox"); //BEGIN AVATAR BONES HIERARCHY if (tgt.avatar != null && tgt.avatar.previewBones != null && tgt.avatar.previewBones.Count > 0) { DrawAvatarBonesHierarchy(0, true); EditorGUILayout.LabelField("Connect corresponding bones."); if (CheckAndBeginLineDrag()) { EditorGUILayout.EndVertical(); Repaint(); return; } } //END AVATAR BONES HIERARCHY //BEGIN AVATAR EditorGUI.BeginChangeCheck(); tgt.avatar = (RagdollAvatar)EditorGUILayout.ObjectField("Avatar", tgt.avatar, typeof(RagdollAvatar), false); if (EditorGUI.EndChangeCheck()) { tgt.FindConnectionsWithAvatar(); tgt.FillTempBones(); } //END AVATAR EditorGUILayout.EndVertical(); if (tgt.avatar == null) { return; } if (UpdateLineDrag()) { tgt.FillTempBones(); Repaint(); return; } if (tgt.tempPreviewBones == null || tgt.tempPreviewBones.Count == 0) { return; } EditorGUI.BeginDisabledGroup(tgt.previewBones == null || tgt.previewBones.Count == 0); tgt.restorePreviousConfiguration = EditorGUILayout.ToggleLeft("Restore Previous Configuration", tgt.restorePreviousConfiguration); EditorGUI.EndDisabledGroup(); if (GUILayout.Button("Configure Selected Bones")) { tgt.FillTempBones(); if (tgt.CheckRoot()) { tgt.CompareAndChangePreviewBones(); if (tgt.selectedBoneID < tgt.previewBones.Count) { tgt.previewBones[tgt.selectedBoneID].selected = true; } tgt.configureBonesMode = true; } else { Debug.LogError("The root bone must be single."); } } //END SELECT ACTIVE BONES MODE } else { if (GUILayout.Button("Change Active Bones")) { tgt.FindConnectionsWithAvatar(); tgt.FillTempBones(); tgt.configureBonesMode = false; } DrawBonesHierarchy(tgt.previewBones[0], true, true, false); if (ClickPreviewBone()) { Repaint(); //move camera to bone PreviewBone bone = tgt.previewBones[tgt.selectedBoneID]; Bounds bounds = bone.bounds; bounds.center = bone.tr.position + bone.rotation * bounds.center; if (bone.colliderType != ColliderType.Box) { bounds.size = bone.capsuleBounds.GetSize(); } if (SceneView.lastActiveSceneView != null) { SceneView.lastActiveSceneView.Frame(bounds, false); } return; } ConfigureBonesGUI(); if (tgt.avatar != null && GUILayout.Button("Save Avatar '" + tgt.avatar.name + "'")) { tgt.SaveBonesToAvatar(); EditorUtility.SetDirty(tgt.avatar); } if (GUILayout.Button("Create Ragdoll")) { tgt.CreateRagdoll(); } } if (GUI.changed) { EditorUtility.SetDirty(tgt); EditorSceneManager.MarkSceneDirty(tgt.gameObject.scene); } }
public bool IsSame(PreviewBone bone) { return(characterBoneId == bone.characterBoneId); }
public void CopyBone() { RagdollConstructor.boneCopy = new PreviewBone(previewBones[selectedBoneID]); }
private void DrawColliderHandles() { if (!tgt.showColliderSettings) { return; } PreviewBone bone = tgt.previewBones[tgt.selectedBoneID]; Quaternion globalRot = tgt.transform.rotation * bone.rotation; if (tgt.rotationHandle) { EditorGUI.BeginChangeCheck(); Quaternion rot = Handles.RotationHandle(globalRot, bone.tr.position); if (EditorGUI.EndChangeCheck()) { bone.rotation = Quaternion.Inverse(tgt.transform.rotation) * rot; } } Matrix4x4 handleMatrix = Matrix4x4.TRS(bone.tr.position, globalRot, Vector3.one); using (new Handles.DrawingScope(handleMatrix)) { switch (bone.colliderType) { case ColliderType.Box: boxBoundsHandle.center = bone.bounds.center; boxBoundsHandle.size = bone.bounds.size; EditorGUI.BeginChangeCheck(); boxBoundsHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { bone.bounds.center = boxBoundsHandle.center; bone.bounds.size = boxBoundsHandle.size; } break; case ColliderType.Capsule: capsuleBoundsHandle.center = bone.bounds.center; capsuleBoundsHandle.height = bone.capsuleBounds.height; capsuleBoundsHandle.radius = bone.capsuleBounds.radius; capsuleBoundsHandle.heightAxis = (CapsuleBoundsHandle.HeightAxis)bone.capsuleBounds.direction; EditorGUI.BeginChangeCheck(); capsuleBoundsHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { bone.bounds.center = capsuleBoundsHandle.center; bone.capsuleBounds.height = capsuleBoundsHandle.height; bone.capsuleBounds.radius = capsuleBoundsHandle.radius; bone.capsuleBounds.direction = (CapsuleDirection)capsuleBoundsHandle.heightAxis; } break; case ColliderType.Sphere: sphereBoundsHandle.center = bone.bounds.center; sphereBoundsHandle.radius = bone.capsuleBounds.radius; EditorGUI.BeginChangeCheck(); sphereBoundsHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { bone.bounds.center = sphereBoundsHandle.center; bone.capsuleBounds.radius = sphereBoundsHandle.radius; } break; } } }