Contents

Unity编辑器扩展-Scene窗口扩展

Scene窗口扩展

Scene窗口更新相应函数

OnSceneGUI函数会在 选中挂在自定义脚本的对象时自动执行

选中该对象时才会执行

[CustomEditor(typeof(SceneTest))]
public class SceneTestEditor : Editor
{
    private void OnSceneGUI()
    {
        Debug.Log("Scene窗口扩展相关逻辑")
    }
}
public class SceneTest : MonoBehaviour{}

自定义窗口中监听Scene窗口更新相应函数

//SceneView.duringSceneGUI += 事件函数;
public class void TestWindow : EditorWindow
{
    [MenuItem("/Unity编辑器扩展/Test/打卡窗口")]
    private static void OpenWindow()
    {
        GetWindow<TestWindow>().Show();
    }  
    private void OnEnable()
    {
        SceneView.duringSceneGUI += (view)=>
        {
            Debug.Log("自定义窗口扩展Scene");
        };
    }
}

Handles公共类

Handles类提供了很多API

让我们可以在Scene窗口中绘制我们的自定义内容

它和GUI、EditorGUI类似,只不过它专门提供给Scene窗口使用

Handles中的颜色控制

Handles.color = new Color(0, 1, 1, 0.3f);

Handles中的文本控件

Handles.Label(显示位置, 文本内容);

Handles中的线段

Handles.DrawLine(起点, 终点, 粗细);

Handles中的虚线

Handles.DrawDottedLine(起点, 终点, 粗细);

Handles中的弧线(圆弧)

//绘制线框弧线
//Handles.DrawWireArc(圆心, 法线, 绘制朝向, 角度, 半径); 
// 绘制填充弧线
///Handles.DrawSolidArc(圆心, 法线, 绘制朝向, 角度, 半径); 
Handles.color = Color.white;
Handles.DrawWireArc(obj.transform.position, Vector3.up, obj.transform.forward, 30, 5);
Handles.DrawSolidArc(obj.transform.position, obj.transform.up, Quaternion.Euler(0,-15,0)* obj.transform.forward, 30, 4);

Handles中的圆

//绘制填充圆
//Handles.DrawSolidDisc(圆心, 法线, 半径); 
//绘制线框圆
//Handles.DrawWireDisc(圆心, 法线, 半径); 
Handles.color = Color.gray;
Handles.DrawSolidDisc(obj.transform.position, obj.transform.up, 2);
Handles.DrawWireDisc(obj.transform.position, obj.transform.up, 3);

Handles中的立方体

//Handles.DrawWireCube(中心点, xyz大小);
Handles.DrawWireCube(obj.transform.position, Vector3.one);

Handles中的几何体

//Handles.DrawAAConvexPolygon(几何体各顶点);
 Handles.DrawAAConvexPolygon(Vector3.zero, Vector3.right, Vector3.right + Vector3.forward, Vector3.forward);

Handles中的移动轴

//Vector3 Handles.DoPositionHandle(位置, 角度);
//Vector3 Handles.PositionHandle(位置, 角度);
obj.transform.position = Handles.DoPositionHandle(obj.transform.position, obj.transform.rotation);

Handles中的旋转轴

//Quaternion Handles.DoRotationHandle(角度, 位置);
//Quaternion Handles.RotationHandle(角度, 位置);
 obj.transform.rotation = Handles.RotationHandle(obj.transform.rotation, obj.transform.position);

Handles中的缩放轴

//Vector3 Handles.DoScaleHandle(缩放, 位置, 角度, HandleUtility.GetHandleSize(位置));
//Vector3 Handles.ScaleHandle(缩放, 位置, 角度, HandleUtility.GetHandleSize(位置));
 obj.transform.localScale = Handles.DoScaleHandle(obj.transform.localScale, obj.transform.position, obj.transform.rotation, HandleUtility.GetHandleSize(obj.transform.position));
//HandleUtility.GetHandleSize方法的作用是
//获取给定位置的操纵器控制柄的世界空间大小
//使用当前相机计算合适的大小
//它决定了控制柄的缩放大小

Handles中的自由移动

  • 一个不受约束的移动控制柄
  • 这个把手可以在所有方向上自由移动
//Vector3 Handles.FreeMoveHandle(位置, 句柄大小, 移动步进值(按住ctrl键时会按该单位移动), 渲染控制手柄的回调函数);句柄大小一般配合HandleUtility.GetHandleSize函数使用
//渲染控制手柄的常用回调函数:
        //Handles.RectangleHandleCap:一个矩形形状的控制手柄,通常用于表示一个平面的控制面
        //Handles.CircleHandleCap:一个圆形的控制手柄,通常用于表示一个球体的控制面
        //Handles.ArrowHandleCap:一个箭头形状的控制手柄,通常用于表示方向
obj.transform.position = Handles.FreeMoveHandle(obj.transform.position, HandleUtility.GetHandleSize(obj.transform.position),Vector3.one*5, Handles.CircleHandleCap);

Handles中的自由旋转

//Quaternion Handles.FreeRotateHandle(角度, 位置, 句柄大小);
obj.transform.rotation = Handles.FreeRotateHandle(obj.transform.rotation, Vector3.zero, HandleUtility.GetHandleSize(Vector3.zero));

Scene窗口中显示GUI

private void OnSceneGUI()
{
    Handles.BeginGUI();
    //GUI
    Handles.EndGUI();
}

获取Scene窗口大小

  • SceneView.currentDrawingSceneView
  • 它继承自EditorWindow,因此通过position就能得到它的大小
private void OnSceneGUI()
{
    Handles.BeginGUI();
    //GUI
    if(GUILayout.Button("测试按钮"))
    {
        Debug.Log("Scene中的按钮响应");
    }
    //获取Scene窗口宽高
    float w = SceneView.currentDrawingSceneView.position.width;
    float h = SceneView.currentDrawingSceneView.position.height;
    // 创建一个GUILayout块
    GUILayout.BeginArea(new Rect(w - 100, h - 100, 100, 100));
    GUILayout.Label("测试文本控件显示");
    if (GUILayout.Button("测试按钮"))
    {
        Debug.Log("Scene中的按钮响应");
    }
    GUILayout.EndArea();
    Handles.EndGUI();
}

HandleUtility公共类

HandleUtility是 Unity 中的一个工具类

用于处理场景中的编辑器句柄(Handles)以及其他一些与编辑器交互相关的功能

它提供了一系列静态方法,用于处理编辑器中的鼠标交互、坐标转换以及其他与Handles相关的功能

HandleUtility类中的常用API

获取在场景中给定位置的句柄的合适尺寸

GetHandleSize(Vector3 position)

将世界坐标转换为 GUI 坐标

通常用于将场景中的某个点的位置转换为屏幕上的像素坐标

//WorldToGUIPoint(Vector3 worldPosition)
Vector2 pos = HandleUtility.WorldToGUIPoint(obj.transform.position);
Handles.BeginGUI();
GUI.Button(new Rect(pos.x, pos.y, 50, 20), "按钮会跟着物体移动");
Handles.EndGUI();

将屏幕上的像素坐标转换为射线

可以理解为是Scene场景的摄像机 发射一条射线

//GUIPointToWorldRay(Vector2 position)
Ray r = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);//得到一条射线
RaycastHit info;
if (Physics.Raycast(r, out info))
    Debug.Log(info.collider.name);

计算场景中一条线段与鼠标光标的最短距离

DistanceToLine(Vector3 lineStart, Vector3 lineEnd)

在编辑器中进行对象的拾取

根据鼠标光标位置获取场景中的对象

PickGameObject(Vector2 position, bool isSelecting)

Gizmos公共类

Gizmos和Handles一样是用来让我们拓展Scene窗口的

而Gizmos相对Handles来说它主要专注于绘制辅助线、图标、形状等

而Handles主要用来绘制编辑器控制手柄等

Gizmos响应函数

继承MonoBehaviour的脚本中实现以下函数

便可以在其中使用Gizmos来进行图形图像的绘制

  1. OnDrawGizmos() 在每帧调用,绘制的内容随时可以在Scene窗口中看见
  2. OnDrawGizmosSelected() 仅当脚本依附的GameObject被选中时才会每帧调用绘制相关内容

它们的执行类似生命周期函数,Unity会帮助我们自动执行

private void OnDrawGizmos()
{
    Debug.Log("Gizmos");
}

private void OnDrawGizmosSelected()
{
    Debug.Log("Gizmos2");
}

Gizmos API

Gizmos修改颜色

Gizmos.color = Color.green;

Gizmos绘制基础形状

//立方体
Gizmos.DrawCube(中心点, 大小);
Gizmos.DrawWireCube(中心点, 大小);
//球
Gizmos.DrawSphere(中心点, 半径);
Gizmos.DrawWireSphere(中心点, 半径);
//mesh网络
public Mesh mesh;
Gizmos.DrawWireMesh(mesh, 位置, 角度);

Gizmos绘制视锥

Gizmos.DrawFrustum(绘制中心, FOV(Field of View,视野)角度, 远裁切平面, 近裁切平面, 屏幕长宽比); 

矩阵

可以理解为是 绘制图形相对的坐标系

//修改Gizmos绘制前的矩阵
//Gizmos.matrix = Matrix4x4.TRS(位置, 角度, 缩放);
Gizmos.matrix = Matrix4x4.TRS(this.transform.position, this.transform.rotation, this.transform.localScale);//可以分别设置位置旋转缩放
Gizmos.matrix = this.transform.localToWorldMatrix;//等同于上一行代码
//还原矩阵
//Gizmos.matrix = Matrix4x4.identity

绘制贴图

Gizmos.DrawGUITexture(new Rect(x, y, w, h), 图片信息);

绘制图标

//图标需要放置在Assets/Gizmos/中
Gizmos.DrawIcon(Vector3.up, "图标名");

绘制线段

Gizmos.DrawLine(起点, 终点);

绘制网格

public Mesh mesh;
Gizmos.DrawMesh(mesh, this.transform.position, this.transform.rotation);

绘制射线

//位置 方向
Gizmos.DrawRay(this.transform.position, this.transform.forward);