using UnityEngine; using UnityEditor; namespace TFramework { public class PreviewInspector : Editor { private PreviewRenderUtility m_PreviewUtility; private GameObject m_PreviewInstance; private Bounds m_PreviewBounds; private Vector2 m_PreviewDir = new Vector2(120f, -20f); public Texture2D PreviewTexture { get; private set; } public override bool HasPreviewGUI() => true; private void AddSingleGO(GameObject go) { #if UNITY_2017_1_OR_NEWER m_PreviewUtility.AddSingleGO(go); #endif } public override void OnPreviewGUI(Rect r, GUIStyle background) { InitPreview(); m_PreviewDir = Drag2D(m_PreviewDir, r); if (Event.current.type != EventType.Repaint) return; m_PreviewUtility.BeginPreview(r, background); Camera camera = m_PreviewUtility.camera; float num = Mathf.Max(m_PreviewBounds.extents.magnitude, 0.0001f); float num2 = num * 2.8f; Quaternion quaternion = Quaternion.Euler(-m_PreviewDir.y, -m_PreviewDir.x, 0f); Vector3 position = m_PreviewBounds.center - quaternion * (Vector3.forward * num2); camera.transform.position = position; camera.transform.rotation = quaternion; camera.nearClipPlane = num2 - num * 1.1f; camera.farClipPlane = num2 + num * 1.1f; m_PreviewUtility.lights[0].intensity = .7f; m_PreviewUtility.lights[0].transform.rotation = quaternion * Quaternion.Euler(40f, 40f, 0); m_PreviewUtility.lights[1].intensity = .7f; m_PreviewUtility.lights[1].transform.rotation = quaternion * Quaternion.Euler(340, 218, 177); m_PreviewUtility.ambientColor = new Color(.1f, .1f, .1f, 0); SetEnabledRecursive(m_PreviewInstance, true); camera.Render(); SetTexture(camera, new Vector2Int(512, 512)); SetEnabledRecursive(m_PreviewInstance, false); m_PreviewUtility.EndAndDrawPreview(r); } private void InitPreview() { if (m_PreviewUtility == null) { m_PreviewUtility = new PreviewRenderUtility(true); m_PreviewUtility.cameraFieldOfView = 60f; CreatePreviewInstances(); } m_PreviewUtility.camera.cullingMask = 1 << kPreviewCullingLayer; } private void DestroyPreview() { m_PreviewUtility?.Cleanup(); m_PreviewUtility = null; } private void DestroyPreviewInstances() { if (m_PreviewInstance != null) { DestroyImmediate(m_PreviewInstance); } m_PreviewInstance = null; } void OnDestroy() { DestroyPreviewInstances(); DestroyPreview(); } private void OnDisable() { DestroyPreviewInstances(); DestroyPreview(); } private void CreatePreviewInstances() { DestroyPreviewInstances(); // Ҫ���Ƶ���Ϸ���� m_PreviewInstance = Selection.activeGameObject; if (m_PreviewInstance == null) { return; } // ʵ�������� m_PreviewInstance = Instantiate(m_PreviewInstance, Vector3.zero, Quaternion.identity) as GameObject; m_PreviewInstance.transform.localScale = 100 * Vector3.one; // �ݹ��������ر�־�Ͳ� InitInstantiatedPreviewRecursive(m_PreviewInstance); // �رն�����Ⱦ SetEnabledRecursive(m_PreviewInstance, false); m_PreviewBounds = new Bounds(m_PreviewInstance.transform.position, Vector3.zero); GetRenderableBoundsRecurse(ref m_PreviewBounds, m_PreviewInstance); AddSingleGO(m_PreviewInstance); } public static void GetRenderableBoundsRecurse(ref Bounds bounds, GameObject go) { MeshRenderer meshRenderer = go.GetComponent(typeof(MeshRenderer)) as MeshRenderer; MeshFilter meshFilter = go.GetComponent(typeof(MeshFilter)) as MeshFilter; if (meshRenderer && meshFilter && meshFilter.sharedMesh) { if (bounds.extents == Vector3.zero) { bounds = meshRenderer.bounds; } else { // ��չ��Χ�У����ð�Χ���ܹ�������һ����Χ�� bounds.Encapsulate(meshRenderer.bounds); } } SkinnedMeshRenderer skinnedMeshRenderer = go.GetComponent(typeof(SkinnedMeshRenderer)) as SkinnedMeshRenderer; if (skinnedMeshRenderer && skinnedMeshRenderer.sharedMesh) { if (bounds.extents == Vector3.zero) { bounds = skinnedMeshRenderer.bounds; } else { bounds.Encapsulate(skinnedMeshRenderer.bounds); } } foreach (Transform transform in go.transform) { GetRenderableBoundsRecurse(ref bounds, transform.gameObject); } } public static Vector2 Drag2D(Vector2 scrollPosition, Rect position) { int controlID = GUIUtility.GetControlID("Slider".GetHashCode(), FocusType.Passive); Event current = Event.current; switch (current.GetTypeForControl(controlID)) { case EventType.MouseDown: if (position.Contains(current.mousePosition) && position.width > 50f) { GUIUtility.hotControl = controlID; current.Use(); // ���������϶�����Ļ��󣬴���һ�߳��� EditorGUIUtility.SetWantsMouseJumping(1); } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlID) { GUIUtility.hotControl = 0; } EditorGUIUtility.SetWantsMouseJumping(0); break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { // ��ס Shift ���󣬿��Լӿ���ת scrollPosition -= current.delta * (float)((!current.shift) ? 1 : 3) / Mathf.Min(position.width, position.height) * 140f; scrollPosition.y = Mathf.Clamp(scrollPosition.y, -90f, 90f); current.Use(); GUI.changed = true; } break; } return scrollPosition; } // Ԥ��������Ļ��Ʋ� Camera.PreviewCullingLayer // Ϊ�˷�ֹ������ģ�����ͨ�������ȡ������ֱ��дֵ private const int kPreviewCullingLayer = 31; private static void InitInstantiatedPreviewRecursive(GameObject go) { go.hideFlags = HideFlags.HideAndDontSave; go.layer = kPreviewCullingLayer; foreach (Transform transform in go.transform) { InitInstantiatedPreviewRecursive(transform.gameObject); } } public static void SetEnabledRecursive(GameObject go, bool enabled) { Renderer[] componentsInChildren = go.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { Renderer renderer = componentsInChildren[i]; renderer.enabled = enabled; } } public void SetTexture(Camera camera, Vector2Int size) { if (camera == null) return; PreviewTexture = new Texture2D(size.x, size.y, TextureFormat.RGB24, false); var scrRenderTexture = new RenderTexture(PreviewTexture.width, PreviewTexture.height, 24); var camRenderTexture = camera.targetTexture; camera.targetTexture = scrRenderTexture; camera.Render(); camera.targetTexture = camRenderTexture; RenderTexture.active = scrRenderTexture; PreviewTexture.ReadPixels(new Rect(0, 0, PreviewTexture.width, PreviewTexture.height), 0, 0); PreviewTexture.Apply(); } } }