预览图:Inspector面板下方显示
缩略图:Project视图中显示
有时候没有预览图和缩略图将很不方便。特别是预制体。
几种方案的选择:
1.继承ObjectPreview类
using UnityEngine;
using UnityEditor;
[CustomPreview(typeof(GameObject))]
public class MyPreview : ObjectPreview
{
public override bool HasPreviewGUI()
{
return true;
}
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
GUI.Label(r, target.name + " is being previewed");
}
}
这种方案只能绘制预览图,而不能生成缩略图。
2.继承Editor类,重写两个方法
public Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height);
public void OnPreviewGUI(Rect r, GUIStyle background);
这种方法可以自定义缩略图和预览图,但是官方文档有说明:
Note: Inspector previews are limited to the primary editor of persistent objects (assets), e.g., GameObjectInspector, MaterialEditor, TextureInspector. This means that it is currently not possible for a component to have its own inspector preview.
一般而言,只需要特定类型的对象生成预览图。其他类型的对象,使用系统自带的预览图方案。如果指定Editor的目标为GameObject,势必影响所有的预览图:包括模型,贴图等。
如果能够继承默认实现的Editor,也可以达到目的。关键问题是,Unity内部的没有对外公开。Unity内部实现的Editor叫做GameObjectInspector
终上所述,解决方案是:使用反射获取内部的GameObjectInspector,来处理默认的预览图生成方案。
需要实现两个类:
Preview
PreviewEditor
使用方法:
将Preview组件添加到需要的对象上,并在Inspector面板设置预览图和缩略图。
也可以右键选择预制体,在弹出的菜单中选择“刷新预览图”。会自动生成一张预览图,并自动设置属性
Preview类:
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using DG.Tweening;
//挂上这个脚本来预览公共界面
public class Preview : MonoBehaviour {
#if UNITY_EDITOR
public Texture2D PreviewThumbnail;
public Texture2D PreviewImage;
#endif
}
PreviewEditor类:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
[CustomEditor(typeof(GameObject))]
public class PreviewEditor : Editor
{
private Editor m_GameObjectInspector;
private MethodInfo m_OnHeaderGUI;
private MethodInfo m_ShouldHideOpenButton;
Editor reflectorGameObjectEditor
{
get
{
return m_GameObjectInspector;
}
}
bool ValidObject()
{
GameObject targetGameObject = target as GameObject;
Preview example = targetGameObject.GetComponent();
if (example == null)
return false;
return true;
}
public override bool HasPreviewGUI()
{
if (!ValidObject())
return reflectorGameObjectEditor.HasPreviewGUI();
return true;
}
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (!ValidObject())
{
reflectorGameObjectEditor.OnPreviewGUI(r, background);
return;
}
var targetGameObject = target as GameObject;
Preview example = targetGameObject.GetComponent();
if (example.PreviewImage == null)
return;
GUI.DrawTexture(r, example.PreviewImage);
}
public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height)
{
if (!ValidObject())
return reflectorGameObjectEditor.RenderStaticPreview(assetPath, subAssets, width, height);
GameObject argetGameObject = target as GameObject;
Preview example = argetGameObject.GetComponent();
if (example.PreviewThumbnail == null)
return null;
//example.PreviewIcon must be a supported format: ARGB32, RGBA32, RGB24,
// Alpha8 or one of float formats
Texture2D tex = new Texture2D(width, height);
EditorUtility.CopySerialized(example.PreviewThumbnail, tex);
return tex;
}
public override void DrawPreview(Rect previewArea)
{
reflectorGameObjectEditor.DrawPreview(previewArea);
}
public override void OnInspectorGUI()
{
reflectorGameObjectEditor.OnInspectorGUI();
}
public override string GetInfoString()
{
return reflectorGameObjectEditor.GetInfoString();
}
public override GUIContent GetPreviewTitle()
{
return reflectorGameObjectEditor.GetPreviewTitle();
}
public override void OnInteractivePreviewGUI(Rect r, GUIStyle background)
{
reflectorGameObjectEditor.OnInteractivePreviewGUI(r, background);
}
public override void OnPreviewSettings()
{
reflectorGameObjectEditor.OnPreviewSettings();
}
public override void ReloadPreviewInstances()
{
reflectorGameObjectEditor.ReloadPreviewInstances();
}
void OnEnable()
{
System.Type gameObjectorInspectorType = typeof(Editor).Assembly.GetType("UnityEditor.GameObjectInspector");
m_OnHeaderGUI = gameObjectorInspectorType.GetMethod("OnHeaderGUI",
BindingFlags.NonPublic | BindingFlags.Instance);
m_GameObjectInspector = Editor.CreateEditor(target, gameObjectorInspectorType);
}
void OnDisable()
{
if (m_GameObjectInspector)
DestroyImmediate(m_GameObjectInspector);
m_GameObjectInspector = null;
}
protected override void OnHeaderGUI()
{
if (m_OnHeaderGUI != null)
{
m_OnHeaderGUI.Invoke(m_GameObjectInspector, null);
}
}
public override bool RequiresConstantRepaint()
{
return reflectorGameObjectEditor.RequiresConstantRepaint();
}
public override bool UseDefaultMargins()
{
return reflectorGameObjectEditor.UseDefaultMargins();
}
protected override bool ShouldHideOpenButton()
{
return (bool)m_ShouldHideOpenButton.Invoke(m_GameObjectInspector, null);
}
[MenuItem("Assets/刷新预览图")]
public static void CreatePreview()
{
var targetGameObject = Selection.activeGameObject;
if (targetGameObject == null)
return;
const string cachePreviewPath = "CachePreviews";
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(targetGameObject));
if (string.IsNullOrEmpty(guid))
{
Debug.LogError("选择的目标不是一个预制体");
return;
}
string rel_pathname = Path.Combine(cachePreviewPath, guid + ".png");
string pathname = Path.Combine("Assets", rel_pathname);
var preview = GetAssetPreview(targetGameObject);
SaveTexture2D(preview as Texture2D, Path.Combine(Application.dataPath, rel_pathname));
{
AssetDatabase.ImportAsset(pathname);
AssetDatabase.Refresh();
TextureImporter Importer = AssetImporter.GetAtPath(pathname) as TextureImporter;
Importer.textureType = TextureImporterType.Default;
TextureImporterPlatformSettings setting = Importer.GetDefaultPlatformTextureSettings();
setting.format = TextureImporterFormat.RGBA32;
setting.textureCompression = TextureImporterCompression.Uncompressed;
Importer.SetPlatformTextureSettings(setting);
Importer.mipmapEnabled = false;
AssetDatabase.ImportAsset(pathname);
AssetDatabase.Refresh();
Debug.Log("SaveTextureToPNG " + pathname);
}
preview = AssetDatabase.LoadAssetAtPath(pathname);
var targetGameObjectClone = PrefabUtility.InstantiatePrefab(targetGameObject) as GameObject;
var previewCom = targetGameObjectClone.GetComponent();
if (previewCom == null)
{
previewCom = targetGameObjectClone.AddComponent();
}
previewCom.PreviewImage = preview as Texture2D;
previewCom.PreviewThumbnail = preview as Texture2D;
PrefabUtility.ApplyPrefabInstance(targetGameObjectClone, InteractionMode.AutomatedAction);
GameObject.DestroyImmediate(targetGameObjectClone);
}
public static Texture GetAssetPreview(GameObject obj)
{
GameObject canvas_obj = null;
GameObject clone = GameObject.Instantiate(obj);
Transform cloneTransform = clone.transform;
GameObject cameraObj = new GameObject("render camera");
Camera renderCamera = cameraObj.AddComponent();
renderCamera.backgroundColor = new Color(0.8f, 0.8f, 0.8f, 1f);
renderCamera.clearFlags = CameraClearFlags.Color;
renderCamera.cameraType = CameraType.SceneView;
renderCamera.cullingMask = 1 << 21;
renderCamera.nearClipPlane = -100;
renderCamera.farClipPlane = 100;
bool isUINode = false;
if (cloneTransform is RectTransform)
{
//如果是UGUI节点的话就要把它们放在Canvas下了
canvas_obj = new GameObject("render canvas", typeof(Canvas));
Canvas canvas = canvas_obj.GetComponent
效果图(显示了UGUI预制体的预览):