// only register when click the "start edit" button void OnUpdate() { if (EditorApplication.isCompiling) { if (ms_Instance != null) { ms_Instance.Close(); } return; } // check target object is still existed, or shutdown if (!m_InEditMF) { _EnsureStopEditing(); } else { GameObject curGO = Selection.activeGameObject; if (curGO != m_InEditMF.gameObject) { Selection.activeGameObject = m_InEditMF.gameObject; EUtil.ShowNotification("GO re-selection is forbidden"); } } }
public override void OnInspectorGUI() { ShrinkWrap cp = (ShrinkWrap)target; EditorGUI.BeginChangeCheck(); EConUtil.DrawActiveLine(cp); //constraint target var newTarget = (Transform)EditorGUILayout.ObjectField("Target Obj", cp.Target, typeof(Transform), true); if (newTarget != null && (newTarget.GetComponent <MeshFilter>() == null || newTarget.GetComponent <Collider>() == null) ) { EUtil.ShowNotification("Target must have MeshFilter & Collider"); } else { cp.Target = newTarget; } EUtil.DrawSplitter(); EUtil.PushGUIEnable(cp.IsActiveConstraint && cp.Target); { cp.Method = (ShrinkWrap.EShrinkWrapMethod)EditorGUILayout.EnumPopup(new GUIContent("ShrinkWrap Method", "select the algorithm for the action"), cp.Method); if (cp.Method == ShrinkWrap.EShrinkWrapMethod.NearestVertex) { EUtil.GetSceneView().renderMode = DrawCameraMode.TexturedWire; } else { EUtil.GetSceneView().renderMode = DrawCameraMode.Textured; } cp.Distance = EditorGUILayout.FloatField(new GUIContent("Distance", "keep distance to the projected point"), cp.Distance); if (cp.Method == ShrinkWrap.EShrinkWrapMethod.Project) { cp.ProjectDir = (EAxisD)EConUtil.DrawEnumBtns(EConUtil.AxisDs, EConUtil.AxisDStrs, cp.ProjectDir, "ProjectDir", "the direction or project ray, from origin of owner"); cp.OwnerSpace = (ESpace)EditorGUILayout.EnumPopup(new GUIContent("OwnerSpace", "the space used for project dir"), cp.OwnerSpace); cp.MaxProjectDistance = Mathf.Max(0, EditorGUILayout.FloatField(new GUIContent("Max Project Dist", "only execute wrap when the projected point is within the dist; 0 means infinite distance"), cp.MaxProjectDistance)); } else if (cp.Method == ShrinkWrap.EShrinkWrapMethod.NearestVertex) { //nothing here } //cp.ModifyInitInfo = EditorGUILayout.Toggle(new GUIContent("Modify InitInfo", "the constraint result will be written back to the initInfo"), cp.ModifyInitInfo); cp.Influence = EUtil.ProgressBar(cp.Influence, 0, 1f, "Influence: {0:F2}"); } EUtil.PopGUIEnable(); if (EditorGUI.EndChangeCheck()) { EditorUtility.SetDirty(cp); //so ConstraintStack.Update can be called in edit-mode } }
void OnGUI() { m_Animator = (Animator)EditorGUILayout.ObjectField("Animator", m_Animator, typeof(Animator), true); m_AnimType = (ModelImporterAnimationType)EditorGUILayout.EnumPopup("AnimType", m_AnimType); if (m_AnimType != ModelImporterAnimationType.Legacy) { m_AnimType = ModelImporterAnimationType.Generic; } bool bSet = (m_Animator != null); EUtil.PushGUIEnable(bSet); if (EUtil.Button("Convert Animation!", bSet ? Color.green : Color.red)) { if (!m_Animator.isHuman) { EUtil.ShowNotification("The model is not in Humanoid rig!"); return; } // save xforms recursively m_SavedPose = EUtil.CacheXformData(m_Animator.transform); m_Animator.Update(0); #if !U5 var ainfos = m_Animator.GetCurrentAnimationClipState(0); //only effect after Update is called #else var ainfos = m_Animator.GetCurrentAnimatorClipInfo(0); //only effect after Update is called #endif if (ainfos.Length == 0) { EUtil.ShowNotification("No clip in AnimationController!"); } else { AnimationClip clip = ainfos[0].clip; string oldClipAssetPath = AssetDatabase.GetAssetPath(clip); string newClipAssetPath = PathUtil.StripExtension(oldClipAssetPath) + NEW_CLIP_POSTFIX + m_AnimType + ".anim"; string filePath = EditorUtility.SaveFilePanel("Select export file path", Path.GetDirectoryName(newClipAssetPath), Path.GetFileNameWithoutExtension(newClipAssetPath), "anim"); if (filePath.Length > 0) { filePath = PathUtil.FullPath2ProjectPath(filePath); _ConvertAnim(filePath); } else { EUtil.ShowNotification("Conversion Cancelled..."); } } //apply the original pose back EUtil.ApplyXformData(m_Animator.transform, m_SavedPose); } EUtil.PopGUIEnable(); }
private void _ToggleCycle(CatmullRomCentripetal spline) { if (!spline.Cycle && spline.PointCount < 3) { EUtil.ShowNotification("Need at least 3 points to make cycle"); return; } spline.Cycle = !spline.Cycle; if (m_curPtIdx >= spline.PointCount) { m_curPtIdx = spline.PointCount - 1; } }
public override void OnInspectorGUI() { serializedObject.Update(); MorphProc proc = (MorphProc)serializedObject.targetObject; EditorGUILayout.ObjectField("Mesh", proc.GetMesh().mesh, typeof(Mesh), true); m_propIndependentMesh.boolValue = EditorGUILayout.Toggle(new GUIContent("Indie Animation", "by default, all instances of one animated prefab will be animated in sync;\nIf you need to make this object animated independently, check this option"), m_propIndependentMesh.boolValue); m_propUseMeshCache.boolValue = EditorGUILayout.Toggle( new GUIContent("Use MeshCache", "This is a very important performance optimization, check this option as long as you don't manipulate this mesh yourself"), m_propUseMeshCache.boolValue); if (proc.MorphCount > 0) { _DrawDeformEntry(proc, 0, true); for (int deformIdx = 1; deformIdx < m_propDeforms.arraySize; ++deformIdx) { _DrawDeformEntry(proc, deformIdx, false); } GUILayout.BeginHorizontal(); { GUILayout.Space(30f); if (GUILayout.Button("New Deform")) { if (proc.MorphCount >= MorphProc.MAX_SHAPEKEY_CNT) { EUtil.ShowNotification("Reached Max Deform Count"); } else { proc.AddCurrentMeshAsNewShapeKeyMorph(); } } GUILayout.Space(30f); } GUILayout.EndHorizontal(); } serializedObject.ApplyModifiedProperties(); }
void OnGUI() { if (m_solver == null) { return; } EditorGUI.BeginChangeCheck(); m_endJoint = (Transform)EditorGUILayout.ObjectField("endJoint", m_endJoint, typeof(Transform), true); m_boneLen = EditorGUILayout.IntField("boneLen", m_boneLen); if (EditorGUI.EndChangeCheck()) { if (m_endJoint == null || m_boneLen <= 0) { return; } m_solver.SetBones(m_endJoint, m_boneLen); m_solver.Target = m_endJoint.position; EUtil.ShowNotification("Set Bones: endJoint: " + m_endJoint.name + ", bonelen: " + m_boneLen); } if (GUILayout.Button("Return To endJoint")) { m_solver.Target = m_endJoint.position; EUtil.RepaintSceneView(); } if (GUILayout.Button("Reset all rotation")) { var joints = m_solver.GetJoints(); foreach (var j in joints) { j.localRotation = Quaternion.identity; } } if (GUILayout.Button("GO")) { m_solver.Execute(); } }
private bool _CheckManualSetJointList(CCDSolverMB cp) { var lst = cp.jointList; for (int i = 0; i < lst.Count; ++i) { if (lst[i] == null) { EUtil.ShowNotification("Joint List has null entry!"); return(false); } } if (lst.Count > 0 && lst[lst.Count - 1] != cp.transform) { EUtil.ShowNotification("Joint List's last entry must be 'this' transform"); return(false); } return(true); }
private void _DelPoint(CatmullRomCentripetal spline) { if (spline.PointCount <= 2) { EUtil.ShowNotification("The spline needs at least 2 points"); return; } if (spline.Cycle && spline.PointCount <= 4) { EUtil.ShowNotification("Cannot delete any points to maintain cycle"); return; } if (m_curPtIdx < 0) { return; } MUndo.RecordObject(target, "del point"); MUndo.RecordObject(this, "del point"); spline.RemovePoint(m_curPtIdx); m_curPtIdx = Mathf.Min(spline.PointCount - 1, m_curPtIdx); }
// public method #endregion "public method" #region "private method" // private method private void _ConvertAnim(string newClipAssetPath) { // 0. prepare if (!m_Animator.isHuman) { Dbg.LogWarn("MuscleClipConverterEditor._ConvertAnim: Need to change to Humanoid rig first!"); return; } m_SMR = m_Animator.GetComponentInChildren <SkinnedMeshRenderer>(); if (m_SMR == null) { Dbg.LogWarn("MuscleClipConverterEditor._ConvertAnim: failed to find SMR under {0}", m_Animator.name); return; } m_Animator.Update(0); #if !U5 var ainfos = m_Animator.GetCurrentAnimationClipState(0); //only effect after Update is called #else var ainfos = m_Animator.GetCurrentAnimatorClipInfo(0); //only effect after Update is called #endif AnimationClip clip = ainfos[0].clip; AnimationClipSettings clipSetting = AnimationUtility.GetAnimationClipSettings(clip); //{//debug // var bindings = AnimationUtility.GetCurveBindings(clip); // foreach( var b in bindings) // { // Dbg.Log("path: {0}, prop: {1}", b.path, b.propertyName); // } //} Transform animatorTr = m_Animator.transform; Transform hipsBone = null; CurveDict curveDict = new CurveDict(); float SAMPLE_RATE = clip.frameRate; float clipLen = clip.length; Matrix4x4 animatorInitW2LMat = animatorTr.worldToLocalMatrix; Matrix4x4 hipsInitW2LMat = Matrix4x4.identity; List <Transform> boneLst = new List <Transform>(); for (HumanBodyBones boneIdx = 0; boneIdx < HumanBodyBones.LastBone; ++boneIdx) { Transform tr = m_Animator.GetBoneTransform(boneIdx); //Dbg.Log("Map: {0}->{1}", boneIdx, tr); if (tr != null) { boneLst.Add(tr); if (boneIdx == HumanBodyBones.Hips) { hipsBone = tr; hipsInitW2LMat = hipsBone.parent.worldToLocalMatrix; //clipSetting.level = -hipsBone.localPosition.y; // set Y offset clipSetting.keepOriginalPositionY = false; //use RootNode position } } } Transform[] bones = boneLst.ToArray(); // init curves for each bone for (int idx = 0; idx < bones.Length; ++idx) { Transform oneBone = bones[idx]; string trPath = AnimationUtility.CalculateTransformPath(oneBone, animatorTr); var curves = new _Curves(); curves.relPath = trPath; curveDict.Add(oneBone, curves); } // init rootmotion curve { var curves = new _Curves(); curveDict.Add(animatorTr, curves); } AnimatorStateInfo curStateInfo = m_Animator.GetCurrentAnimatorStateInfo(0); float nt = curStateInfo.normalizedTime; m_Animator.Update(-nt * clipLen); //revert to 0 time { // 1. bake animation info into curve on all bones transform float time = 0f; float deltaTime = 1f / (SAMPLE_RATE); for (; time <= clipLen || Mathf.Approximately(time, clipLen); ) { //Dbg.Log("nt = {0}", m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime); // bone for (int idx = 0; idx < bones.Length; ++idx) { Transform oneBone = bones[idx]; _Curves curves = curveDict[oneBone]; if (oneBone == hipsBone) { continue; //skip the HipsBone. This is to add rootMotion matrix on hips, so Legacy is right } Vector3 pos = oneBone.localPosition; Quaternion rot = oneBone.localRotation; curves.X.AddKey(time, rot.x); curves.Y.AddKey(time, rot.y); curves.Z.AddKey(time, rot.z); curves.W.AddKey(time, rot.w); curves.PX.AddKey(time, pos.x); curves.PY.AddKey(time, pos.y); curves.PZ.AddKey(time, pos.z); } // root motion process { { //on Animator transform Vector3 pos = /*animatorTr.localPosition*/ animatorTr.position; Vector3 fwd = animatorTr.forward; Vector3 up = animatorTr.up; _Curves rootMotionCurves = curveDict[animatorTr]; Vector3 lpos = animatorInitW2LMat.MultiplyPoint(pos); Vector3 lfwd = animatorInitW2LMat.MultiplyVector(fwd); Vector3 lup = animatorInitW2LMat.MultiplyVector(up); Quaternion rot = Quaternion.LookRotation(lfwd, lup); rootMotionCurves.X.AddKey(time, rot.x); rootMotionCurves.Y.AddKey(time, rot.y); rootMotionCurves.Z.AddKey(time, rot.z); rootMotionCurves.W.AddKey(time, rot.w); rootMotionCurves.PX.AddKey(time, lpos.x); rootMotionCurves.PY.AddKey(time, lpos.y); rootMotionCurves.PZ.AddKey(time, lpos.z); } { //on hips transform if (hipsBone != null) { Vector3 pos = hipsBone.position; Vector3 fwd = hipsBone.forward; Vector3 up = hipsBone.up; _Curves hipsCurves = curveDict[hipsBone]; Vector3 lpos = hipsInitW2LMat.MultiplyPoint(pos); Vector3 lfwd = hipsInitW2LMat.MultiplyVector(fwd); Vector3 lup = hipsInitW2LMat.MultiplyVector(up); //Dbg.Log("time: {0}, lpos: {1}", time, lpos.ToString("F2")); Quaternion rot = Quaternion.LookRotation(lfwd, lup); hipsCurves.X.AddKey(time, rot.x); hipsCurves.Y.AddKey(time, rot.y); hipsCurves.Z.AddKey(time, rot.z); hipsCurves.W.AddKey(time, rot.w); hipsCurves.PX.AddKey(time, lpos.x); hipsCurves.PY.AddKey(time, lpos.y); hipsCurves.PZ.AddKey(time, lpos.z); } } } if (!Mathf.Approximately(time + deltaTime, clipLen)) { m_Animator.Update(deltaTime); time += deltaTime; } else { m_Animator.Update(deltaTime - 0.005f); //keep it in the range, if go beyond, something bad could happen time += deltaTime - 0.005f; } } } //end of 1. { // 2. set animation clip and store in AssetDatabase AnimationClip newClip = new AnimationClip(); newClip.frameRate = SAMPLE_RATE; newClip.localBounds = clip.localBounds; // set bone curves for (var ie = curveDict.GetEnumerator(); ie.MoveNext();) { var curves = ie.Current.Value; if (ie.Current.Key == animatorTr) { //root motion newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.x", curves.PX); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.y", curves.PY); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.z", curves.PZ); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.x", curves.X); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.y", curves.Y); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.z", curves.Z); newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.w", curves.W); } else { newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.x", curves.X); newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.y", curves.Y); newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.z", curves.Z); newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.w", curves.W); newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.x", curves.PX); newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.y", curves.PY); newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.z", curves.PZ); } } // 2.1 copy the unmapped curves to new clip( not mapped by Muscle clip ) _CopyOtherCurves(newClip, clip); // some setting work newClip.EnsureQuaternionContinuity(); #if !U5 AnimationUtility.SetAnimationType(newClip, m_AnimType); RCall.CallMtd("UnityEditor.AnimationUtility", "SetAnimationClipSettings", null, newClip, clipSetting); #else if (m_AnimType == ModelImporterAnimationType.Legacy) { newClip.legacy = true; } AnimationUtility.SetAnimationClipSettings(newClip, clipSetting); #endif EUtil.SaveAnimClip(newClip, newClipAssetPath); EUtil.ShowNotification("Converted to: " + m_AnimType + (hipsBone != null ? ("\nroot=" + AnimationUtility.CalculateTransformPath(hipsBone, animatorTr)) : ""), 3f ); } //end of 2. // 3. clean job curveDict = null; AssetDatabase.SaveAssets(); Dbg.Log("Converted: {0}", newClipAssetPath); }
private void _OnGUI_SMR() { m_RootBone = EditorGUILayout.ObjectField(new GUIContent("Top GO", "fill the topmost GameObject of model"), m_RootBone, typeof(Transform), true) as Transform; GUIUtil.PushGUIEnable(m_RootBone != null); { GUILayout.BeginHorizontal(); GUILayout.Space(60f); if (EUtil.Button("AutoFind", "Automatically collect all SMR & MF on this model", Color.blue)) { _AutoFindRenderers(); } GUILayout.Space(60f); GUILayout.EndHorizontal(); } GUIUtil.PopGUIEnable(); EUtil.DrawSplitter(); //SMR for (int idx = 0; idx < m_SMRs.Count; ++idx) { GUILayout.BeginHorizontal(); if (EUtil.Button("X", "delete", Color.red, GUILayout.Width(30f))) { m_SMRs.RemoveAt(idx); --idx; continue; } Color oc = GUI.backgroundColor; GUI.backgroundColor = Color.green; m_SMRs[idx] = EditorGUILayout.ObjectField(m_SMRs[idx], typeof(SkinnedMeshRenderer), true) as SkinnedMeshRenderer; GUI.backgroundColor = oc; GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); GUILayout.Space(60f); if (GUILayout.Button(new GUIContent("Add SMR Entry", "manually add \"Skinned-Mesh Renderer\""))) { m_SMRs.Add(null); } GUILayout.Space(60f); GUILayout.EndHorizontal(); EUtil.DrawSplitter(); //MF for (int idx = 0; idx < m_MFs.Count; ++idx) { GUILayout.BeginHorizontal(); if (EUtil.Button("X", "delete", Color.red, GUILayout.Width(30f))) { m_MFs.RemoveAt(idx); --idx; continue; } Color oc = GUI.backgroundColor; GUI.backgroundColor = Color.yellow; m_MFs[idx] = EditorGUILayout.ObjectField(m_MFs[idx], typeof(MeshFilter), true) as MeshFilter; GUI.backgroundColor = oc; GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); GUILayout.Space(60f); if (GUILayout.Button(new GUIContent("Add MF Entry", "manually add \"Mesh Filter\""))) { m_MFs.Add(null); } GUILayout.Space(60f); GUILayout.EndHorizontal(); EUtil.DrawSplitter(); //export clips for (int idx = 0; idx < m_Clips.Count; ++idx) { GUILayout.BeginHorizontal(); if (EUtil.Button("X", "delete", Color.red, GUILayout.Width(30f))) { m_Clips.RemoveAt(idx); --idx; continue; } m_Clips[idx] = EditorGUILayout.ObjectField(m_Clips[idx], typeof(AnimationClip), true) as AnimationClip; GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); GUILayout.Space(60f); if (GUILayout.Button(new GUIContent("Add Clip", "add another animation clip to export"))) { m_Clips.Add(null); } GUILayout.Space(60f); GUILayout.EndHorizontal(); EUtil.DrawSplitter(); bool bHasValidEntry = _HasValidEntry(); Color c = (bHasValidEntry) ? Color.green : Color.red; EUtil.PushBackgroundColor(c); GUIUtil.PushGUIEnable(bHasValidEntry); GUILayout.BeginHorizontal(); GUILayout.Space(60f); if (GUILayout.Button("Export!")) { string saveDir = _GetSaveDirectory(); string filePath = EditorUtility.SaveFilePanel("Select export file path", saveDir, "anim", "dae"); if (filePath.Length > 0) { string recDir = System.IO.Path.GetDirectoryName(filePath); _RecordSaveDirectory(recDir); SkinnedMeshRenderer[] smrArr = m_SMRs.TakeWhile(x => x != null).ToArray(); MeshFilter[] mfArr = m_MFs.TakeWhile(x => x != null).ToArray(); m_Clips.RemoveAll(x => x == null); DaeExporter exp = new DaeExporter(smrArr, mfArr, m_RootBone); exp.Export(m_Clips, filePath); AssetDatabase.Refresh(); } else { EUtil.ShowNotification("Export Cancelled..."); } } GUILayout.Space(60f); GUILayout.EndHorizontal(); GUIUtil.PopGUIEnable(); EUtil.PopBackgroundColor(); }
// unity event handlers #endregion "unity event handlers" #region "public method" // public method public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); // Draw label position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); // Don't make child fields be indented var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; // Calculate rects var btnRect = new Rect(position.x, position.y, 25, LINEHEIGHT); var trPathRect = new Rect(position.x + 27, position.y, position.width - 27, LINEHEIGHT); // Draw fields - pass GUIContent.none to each so they are drawn without labels if (GUI.Button(btnRect, "C")) { m_bSelectingTransform = !m_bSelectingTransform; } if (property.FindPropertyRelative(F_VALID).boolValue) { EditorGUI.PropertyField(trPathRect, property.FindPropertyRelative(F_TRPATH), GUIContent.none); } else { EditorGUI.LabelField(trPathRect, "NULL"); } if (m_bSelectingTransform) { var objSelectRect = new Rect(position.x, position.y + LINEHEIGHT, position.width, LINEHEIGHT); Transform selfTr = ((MonoBehaviour)(property.serializedObject.targetObject)).transform; Transform tr = EditorGUI.ObjectField(objSelectRect, selfTr, typeof(Transform), true) as Transform; if (tr != selfTr) { if (tr == null) { _SetTrPath(property, null); } else { Transform ccroot = _FindCCRoot(tr); if (ccroot == null) { string trPath = CCTrPath.SceneRoot + AnimationUtility.CalculateTransformPath(tr, null); _SetTrPath(property, trPath); EUtil.ShowNotification("TrPath: " + trPath, 4.0f); } else { string trPath = AnimationUtility.CalculateTransformPath(tr, ccroot); _SetTrPath(property, trPath); EUtil.ShowNotification("TrPath: " + trPath, 4.0f); } } m_bSelectingTransform = false; } } // Set indent back to what it was EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); }