/// <summary> /// Remove the baked export pose of the SceneTrackObject /// </summary> /// <param name="obj">Target SceneTrackObject</param> /// <param name="smr">Target SkinnedMeshRenderer</param> static void RemoveExportPose(SceneTrackObject obj, SkinnedMeshRenderer smr) { String path = AssetDatabase.GetAssetPath(obj.overrideMeshMesh); AssetDatabase.DeleteAsset(path); obj.overrideMeshMesh = null; obj.overrideMesh = false; foreach (Transform transform in smr.bones) { SceneTrackObject child = transform.GetComponent <SceneTrackObject>(); if (child == null) { Debug.LogWarningFormat( "[SceneTrack] Bone '{0}' for Skinned Mesh Renderer '{1}' has no SceneTrack Object attached. This will not record correctly.", transform.name, smr.gameObject.name); continue; } if (child == obj) { continue; } child.overridePose = false; child.overridePosePosition = Vector3.zero; child.overridePoseRotation = Quaternion.identity; child.overridePoseScale = Vector3.one; EditorUtility.SetDirty(child); } }
/// <summary> /// Bake the export pose for the SkinnedMeshRenderer /// </summary> /// <param name="obj">Target Object</param> /// <param name="smr">Target SkinnedMeshRenderer</param> static void SetExportPose(SceneTrackObject obj, SkinnedMeshRenderer smr) { Mesh baked = new Mesh(); smr.BakeMesh(baked); Mesh overrideMesh = global::UnityEngine.Object.Instantiate(smr.sharedMesh); String meshName = smr.sharedMesh.name; String fileName = String.Format("SceneTrackPose_{0:X8}", DJB2Hash(String.Format("{0}_{1}", AssetDatabase.GetAssetPath(smr.sharedMesh), smr.sharedMesh.name))); overrideMesh.name = String.Format("SceneTrackMeshCache_{0}", meshName); overrideMesh.vertices = baked.vertices; overrideMesh.RecalculateBounds(); overrideMesh.RecalculateNormals(); if (AssetDatabase.IsValidFolder("Assets/SceneTrackCache") == false) { AssetDatabase.CreateFolder("Assets", "SceneTrackCache"); } AssetDatabase.CreateAsset(overrideMesh, String.Format("Assets/SceneTrackCache/{0}.asset", fileName)); obj.overrideMesh = true; obj.overrideMeshMesh = overrideMesh; foreach (Transform boneTransform in smr.bones) { SceneTrackObject boneObject = boneTransform.GetComponent <SceneTrackObject>(); if (boneObject == null) { Debug.LogWarningFormat( "[SceneTrack] Bone '{0}' for Skinned Mesh Renderer '{1}' has no SceneTrack Object attached. This will not record correctly.", boneTransform.name, smr.gameObject.name); continue; } if (boneObject == obj) { continue; } boneObject.overridePose = true; boneObject.overridePosePosition = boneTransform.localPosition; boneObject.overridePoseRotation = boneTransform.localRotation; boneObject.overridePoseScale = boneTransform.localScale; EditorUtility.SetDirty(boneObject); } DestroyImmediate(baked); }
/// <summary> /// Check setup for warnings. /// </summary> /// <param name="obj">Target SceneTrackObject</param> static void CheckWarnings(SceneTrackObject obj) { if (_warnings == null) { _warnings = new List <Warnings>(4); } if (_missingObjectsOnBones == null) { _missingObjectsOnBones = new List <Transform>(1); } if (_enabledChildren == null) { _enabledChildren = new List <SceneTrackObject>(1); } _warnings.Clear(); _missingObjectsOnBones.Clear(); _enabledChildren.Clear(); var tr = obj.transform; var mf = obj.GetComponent <MeshFilter>(); var mr = obj.GetComponent <MeshRenderer>(); var smr = obj.GetComponent <SkinnedMeshRenderer>(); var localScale = tr.localScale; // Check SkinnedMeshRenderer if (smr != null) { if (obj.TrackMeshRenderer == false) { PushWarning(Warnings.DisabledMeshRecording); } if (smr.rootBone == null) { PushWarning(Warnings.NoRootBone); } if (smr.sharedMesh == null) { PushWarning(Warnings.NoSkinnedMesh); } if (obj.overrideMesh == true && obj.overrideMeshMesh == null) { PushWarning(Warnings.MissingExportPoseMesh); } if (smr.sharedMaterials.Length == 0) { PushWarning(Warnings.NoMaterial); } else { if (smr.sharedMaterials[0].mainTexture == null) { PushWarning(Warnings.NoMaterialMainTexture); } } if (Mathf.Approximately(localScale.x, 1.0f) == false || Mathf.Approximately(localScale.y, 1.0f) == false || Mathf.Approximately(localScale.z, 1.0f) == false) { PushWarning(Warnings.ScaledSkinnedMeshRenderer); } if (smr.bones != null) { foreach (var boneTr in smr.bones) { SceneTrackObject boneObject = boneTr.GetComponent <SceneTrackObject>(); if (boneObject == null) { PushWarning(Warnings.NotAllBonesHaveObjects); _missingObjectsOnBones.Add(boneTr); } } _missingObjectsOnBones.Sort((x, y) => x.name.CompareTo(y.name)); } else { PushWarning(Warnings.NoBones); } } // Check Mesh Renderer if (mr != null) { Material mat = null; if (mr.sharedMaterial != null) { mat = mr.sharedMaterial; } else if (mr.sharedMaterials != null) { if (mr.sharedMaterials[0] != null) { mat = mr.sharedMaterials[0]; } } if (mat == null) { PushWarning(Warnings.NoMaterial); } else { if (mat.mainTexture == null) { PushWarning(Warnings.NoMaterialMainTexture); } } } else { if (mf != null) { PushWarning(Warnings.NoMeshRenderer); } } // Check MeshFilter if (mf != null) { if (mr != null && obj.TrackMeshRenderer == false) { PushWarning(Warnings.DisabledMeshRecording); } if (mf.sharedMesh == null) { PushWarning(Warnings.NoMesh); } } // Check Tracked Object if (obj.TrackObject == false) { foreach (var so in obj.GetComponentsInChildren <SceneTrackObject>()) { if (so != obj && so.TrackObject == true) { PushWarning(Warnings.DisabledButChildTracking); _enabledChildren.Add(so); } } } // Odd Warning if (smr == null && mr == null && mf == null && obj.TrackMeshRenderer) { PushWarning(Warnings.NoRendererButWantsRecording); } }
/// <summary> /// Unity Inspector /// </summary> public override void OnInspectorGUI() { if (Application.isPlaying) { EditorGUILayout.HelpBox("Changes Are Not Permitted During PlayMode", MessageType.Info); return; } bool dirty = false; // Get Current Reference _targetObject = (SceneTrackObject)target; if (_targetObject != lastObject) { lastObject = _targetObject; } CheckWarnings(_targetObject); InspectWarnings(_targetObject, ref dirty); SkinnedMeshRenderer smr = _targetObject.GetComponent <SkinnedMeshRenderer>(); bool hasMeshRenderer = _targetObject.GetComponent <MeshRenderer>() != null || smr != null; bool hasCollider = _targetObject.GetComponent <Collider>() != null; GUILayout.Space(5); EditorGUILayout.LabelField("Tracking", EditorStyles.boldLabel); _targetObject.TrackObject = EditorGUILayout.Toggle("Track Object", _targetObject.TrackObject); EditorGUI.BeginDisabledGroup(!_targetObject.TrackObject); EditorGUILayout.LabelField("Components", EditorStyles.miniBoldLabel); EditorGUI.indentLevel++; if (hasMeshRenderer) { EditorGUILayout.BeginHorizontal(); _targetObject.TrackMeshRenderer = EditorGUILayout.Toggle("Mesh", _targetObject.TrackMeshRenderer); if (smr != null && smr.sharedMesh != null && _targetObject.TrackMeshRenderer) { if (_targetObject.overrideMesh == false && _targetObject.overrideMeshMesh == null) { if (GUILayout.Button("Set as Export Pose", EditorStyles.miniButton, GUILayout.Width(140))) { SetExportPose(_targetObject, smr); dirty = true; } } else { if (_targetObject.overrideMeshMesh == null) { GUILayout.Label("Missing Export Pose Mesh Asset!", EditorStyles.boldLabel); } else { if (GUILayout.Button("Remove Export Pose", EditorStyles.miniButton, GUILayout.Width(140)) && _targetObject.overrideMeshMesh != null) { RemoveExportPose(_targetObject, smr); dirty = true; } } } } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); } if (hasCollider) { _targetObject.TrackPhysics = EditorGUILayout.Toggle("Physics Events", _targetObject.TrackPhysics); } EditorGUI.indentLevel--; if (_targetObject.TrackPhysics) { GUILayout.Space(10); EditorGUILayout.LabelField("User Defined Data", EditorStyles.boldLabel); _targetObject.UserDefinedData = EditorGUILayout.TextField(_targetObject.UserDefinedData); } EditorGUI.EndDisabledGroup(); GUILayout.Space(10); // Calculate Children EditorGUILayout.LabelField("Children Trackers", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Add", EditorStyles.miniButtonLeft)) { // Look through all children (even inactive ones) foreach (var t in _targetObject.GetComponentsInChildren <Transform>(true)) { if (t.GetComponent <SceneTrackObject>() == null) { t.gameObject.AddComponent <SceneTrackObject>(); } } // Update Cache List SceneTrack.Unity.System.CacheKnownObjects(); } if (GUILayout.Button("Remove", EditorStyles.miniButtonMid)) { // Look through all children (even inactive ones) foreach (var t in _targetObject.GetComponentsInChildren <Transform>(true)) { var reference = t.GetComponent <SceneTrackObject>(); if (reference != null && reference != _targetObject) { UnityEngine.Object.DestroyImmediate(reference); } } // Update Cache List SceneTrack.Unity.System.CacheKnownObjects(); } if (GUILayout.Button("Enable", EditorStyles.miniButtonMid)) { // Look through all children (even inactive ones) foreach (var t in _targetObject.GetComponentsInChildren <Transform>(true)) { var reference = t.GetComponent <SceneTrackObject>(); if (reference != null && reference != _targetObject) { reference.TrackObject = true; } } // Update Cache List SceneTrack.Unity.System.CacheKnownObjects(); } if (GUILayout.Button("Disable", EditorStyles.miniButtonRight)) { // Look through all children (even inactive ones) foreach (var t in _targetObject.GetComponentsInChildren <Transform>(true)) { var reference = t.GetComponent <SceneTrackObject>(); if (reference != null && reference != _targetObject) { reference.TrackObject = false; } } // Update Cache List SceneTrack.Unity.System.CacheKnownObjects(); } EditorGUILayout.EndHorizontal(); GUILayout.Space(10); if (dirty || GUI.changed) { EditorUtility.SetDirty(_targetObject); EditorSceneManager.MarkAllScenesDirty(); CheckWarnings(_targetObject); } }
/// <summary> /// Generate warning report for object. /// </summary> /// <param name="obj">Target Object</param> /// <param name="dirty">Is Object Dirty?</param> static void InspectWarnings(SceneTrackObject obj, ref bool dirty) { if (_warnings == null || _warnings.Count == 0) { return; } if (_warnings != null && _warnings.Count > 0) { GUILayout.Label(String.Format("{0} Issues", _warnings.Count), EditorStyles.boldLabel); } foreach (var warning in _warnings) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); switch (warning) { case Warnings.NoRootBone: GUILayout.Label("\u2022 No Root Bone is attached the Skinned Mesh Renderer"); break; case Warnings.DisabledMeshRecording: GUILayout.Label("\u2022 Mesh recording is disabled"); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Suggested Fix:"); if (GUILayout.Button("Enable Mesh Recording", EditorStyles.miniButton)) { obj.TrackMeshRenderer = true; dirty = true; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); break; case Warnings.NoMesh: GUILayout.Label("\u2022 No Mesh is attached to the MeshFilter"); break; case Warnings.NoSkinnedMesh: GUILayout.Label("\u2022 No Mesh is attached to the Skinned Mesh Filter"); break; case Warnings.NoBones: GUILayout.Label("\u2022 There are no Bones assigned to this Skinned Mesh Renderer"); break; case Warnings.ScaledSkinnedMeshRenderer: GUILayout.Label("LocalScale is not [1, 1, 1]", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Suggested Fix:"); if (GUILayout.Button("Reset Scale", EditorStyles.miniButton, GUILayout.MaxWidth(100))) { obj.transform.localScale = Vector3.one; dirty = true; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); break; case Warnings.NotAllBonesHaveObjects: GUILayout.Label("\u2022 Some Bones do not have Trackers attached"); if (_missingObjectsOnBones != null && _missingObjectsOnBones.Count > 0) { ListChildren(_missingObjectsOnBones); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Suggested Fix:"); if (GUILayout.Button("Add Trackers to Bones", EditorStyles.miniButton)) { foreach (var bone in _missingObjectsOnBones) { SceneTrackObject boneObject = bone.gameObject.AddComponent <SceneTrackObject>(); EditorUtility.SetDirty(boneObject); EditorUtility.SetDirty(bone.gameObject); } dirty = true; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); } break; case Warnings.NoMaterial: GUILayout.Label("\u2022 No Material is assigned", EditorStyles.boldLabel); break; case Warnings.NoMaterialMainTexture: GUILayout.Label("\u2022 No Main Texture was assigned to the material"); break; case Warnings.NoMeshRenderer: GUILayout.Label("\u2022 No Mesh Renderer attached", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Suggested Fix:"); if (GUILayout.Button("Add Mesh Renderer Component", EditorStyles.miniButton)) { var mr = obj.gameObject.AddComponent <MeshRenderer>(); EditorUtility.SetDirty(mr); dirty = true; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); break; case Warnings.NoRendererButWantsRecording: obj.TrackMeshRenderer = false; dirty = true; break; case Warnings.DisabledButChildTracking: GUILayout.Label("\u2022 Tracking is disabled, but child objects are tracking"); ListChildren(_enabledChildren); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Suggested Fixes:"); if (GUILayout.Button("Turn off tracking for Children", EditorStyles.miniButton)) { foreach (var childObj in _enabledChildren) { childObj.TrackObject = false; EditorUtility.SetDirty(childObj); } dirty = true; } GUILayout.Label(" or "); if (GUILayout.Button("Enable Object Tracking", EditorStyles.miniButton)) { obj.TrackObject = true; dirty = true; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); break; case Warnings.MissingExportPoseMesh: GUILayout.Label("\u2022 Export Pose Mesh Missing", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Suggested Fix:"); if (GUILayout.Button("Set As Export Pose", EditorStyles.miniButton)) { SetExportPose(obj, obj.GetComponent <SkinnedMeshRenderer>()); dirty = true; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); break; } EditorGUILayout.EndVertical(); GUILayout.Space(5); } if (_warnings != null && _warnings.Count > 0) { EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); } }