yukamu 发表于 2022-5-28 09:53

Unity3d Editor 编辑器扩展功能详解(4)Gizmos

前言:

全索引目录:Unity3d Editor 编辑器扩展功能详解(1) 目录索引
上一章节:Unity Editor 编辑器扩展功能详解(3)EditorGUI/EditorGUILayout(下)
下一章节:Unity3d Editor 编辑器扩展功能详解(5)Handles
想开新坑了,让我快马加鞭地把这系列坑填完吧。
一、 Gizmos基础介绍

官方文档: Important Classes - Gizmos & Handles
Important Classes - Gizmos & Handles
The Gizmos and Handles classes allows you to draw lines and shapes in the Scene view and Game view, as well as interactive handles and controls. These two classes together provide a way for you to extend what is shown in these views and build interactive tools to edit your project in any way you like. For example, rather than entering numbers in the inspector, you could create a draggable circle radius gizmo around a non-player character in a game, which represents the area within which they can hear or see the player.
This page provides a simple overview of the Gizmos and Handles classes. For full documentation and an exhaustive reference of every member of the Gizmos and Handles classes, see the script reference pages for Gizmos and Handles.
重要的类: Gizmos 与 Handles
Gizmos与Handles类允许你在“SceneView”(场景视图)与“GameView”(游戏视图)中绘制线段与图形,或是可交互控制柄(比如Transform移动的三轴箭头)
这两者一同作用,能让用户在这些视图中自定义扩展显示信息,或是构建自己喜欢的编辑、操作工具。
比如,相比起在Inspector(检视器)中输入数字,你可以在游戏里创建一个可拖拽的圆环附着在NPC上,这代表了NPC发现玩家的视听检测范围。
本页面仅简单介绍了Gizmos与Handles的概览,对于详尽的文档与参考,请见:Gizmos Handles简单地说,Gizmos与Handles主要用于开发编辑中,可视化一些数据信息,便于Debug。
二、 Gizmos使用方式

关键字: MonoBehaviour.OnDrawGizmos,MonoBehaviour.OnDrawGizmosSelected
Gizmos能且只能在MonoBehaviour相关子类中,使用特定的函数调用,其中:
OnDrawGizmos() 在每帧调佣。所有在OnDrawGizmos中的渲染都是可见的。
OnDrawGizmosSelected() 仅在脚本附加的物体被选择时调用。
示例代码:
public class GizmosTutotial : MonoBehaviour //新建脚本,继承自Mono
{
    private Vector3 size = new Vector3(10, 10, 10); //定义Cube大小
    private void OnDrawGizmos() //定义OnDrawGizmos方法,类似于Start,Update的定义方式
    {
      Gizmos.DrawCube(Vector3.zero, size); //使用Gizmos绘制一个Cube
    }
}
将此脚本挂载在场景中的Gameobject上,我们可以看见:



挂载脚本后,我们可以看见Gizmos的绘制

值得注意的是,场景上方工具栏的【Gizmos】开关定义了全局“是否显示Gizmos”,如果我们把此按钮取消激活,场景将不会绘制任何Gizmos图形。当然,点开小三角,能看见更详细的设置信息。



Gizmos Setting控制所有Gizmos的显示绘制

三、 Gizmos基本绘制API

注:本文不会对所有的API的全部定义进行讲解,一个方法实际存在多种重载,只介绍最基本最常用的方法;若想查看方法详细情况与重载,请自行在Visual Studio中“转到定义”。
1. 立方体(Cube)

关键字: Gizmos.DrawCube
样例:



平平无奇小Cube

示例代码:
public class GizmosTutotial : MonoBehaviour
{
    private void OnDrawGizmos()
    {
      Gizmos.DrawCube(Vector3.zero, Vector3.one); //参数释义: 1.Cube中心点 2.Cube大小
    }
}
注:为了方便起见,下文将省略Mono类定义与OnDrawGizmos定义,请记得所有Gizmos方法都是在OnDrawGizmos/OnDrawGizmosSelected中使用。
2. 视锥(Frustum)

关键字:Gizmos.DrawFrustum
样例:



摄像机的视锥绘制就是这样画的

示例代码:
Gizmos.DrawFrustum(Vector3.zero, 60, 300, 0.3f, 1.7f);
//参数释义:1. 绘制中心 2. FOV角度 3. 远裁切平面 4. 近裁切平面 5. aspect 屏幕长宽比3. 贴图(Texture)

关键字:Gizmos.DrawGUITexture
样例:



在场景中绘制贴图(texture)

示例代码:
public Texture texture;
...
if (texture != null)
{
    Gizmos.DrawGUITexture(new Rect(0, 0, 10, 10), texture); //1.指定Rect 2.指定贴图
}
4. 图标(Icon)

关键字: Gizmos.DrawIcon
样例:



绘制自定义图标,注意图片资源名称

示例代码:
Gizmos.DrawIcon(Vector3.up, "MyIcon"); //1.绘制中心 2.图标名
注: 此处图标名“MyIcon”是指在路径:“Assets/Gizmos/...”中的图片名称。
DrawIcon的前提是在资源文件夹“Gizmos”中存放想绘制的图片,定义好名称后,在代码中调用。
此处图片全路径为:“Assets/Gizmos/MyIcon.png”,所以写“MyIcon”。
值得注意的是,所有在Gizmos/Handles中的绘制都不会发布到实际游戏中,只是在使用Editor开发时作为可视化辅助工具。
5. 线段(Line)

关键字: Gizmos.DrawLine
样例:



画线

示例代码:
Gizmos.DrawLine(Vector3.zero, Vector3.one);//1.from(线段起点) 2.to(线段终点)
6. 网格(Mesh)

关键字:Gizmos.DrawMesh
样例:



绘制网格(重载方法可以定义位置、选择、缩放等)

示例代码:
public Mesh mesh;
...
if (mesh != null)
{
    Gizmos.DrawMesh(mesh, 0); //1. mesh 2.submeshIndex
}
7. 射线(Ray)

关键字:Gizmos.DrawRay
样例:



与Drawline很类似

示例代码:
Gizmos.DrawRay(Vector3.zero, Vector3.one); //1.from 2.direction
8. 球体(Sphere)

关键字:Gizmos.DrawSphere
样例:



画个球,实际上把半径缩小也能看做画个点

示例代码:
Gizmos.DrawSphere(Vector3.up, 1); //1.center 2.radius
9. 网格线(Wire)

关键字:Gizmos.DrawWireCube
样例:



绘制各种Wire网格

示例代码:
public Mesh mesh;
...
Gizmos.DrawWireCube(Vector3.left, Vector3.one);
Gizmos.DrawWireSphere(Vector3.right, 1);
if (mesh != null)
{
    Gizmos.DrawWireMesh(mesh, 0, Vector3.forward);
}
10. 颜色设置(Color)

关键字:Gizmos.Color
样例:



颜色设置,便于区分

示例代码:
Gizmos.color = Color.red;
Gizmos.DrawSphere(Vector3.left, 0.5f);
Gizmos.color = Color.green;
Gizmos.DrawCube(Vector3.zero, Vector3.one);
Gizmos.color = Color.blue;
Gizmos.DrawLine(Vector3.right, Vector3.right * 2);
11. 矩阵设置(Matrix)

关键字:Gizmos.matrix
样例:



应用某个物体的transform矩阵,gizmos的绘制图像也会应用矩阵数据进行仿射变换

示例代码:
Gizmos.matrix = this.transform.localToWorldMatrix; //这里使用挂载transform进行举例
Gizmos.DrawWireSphere(Vector3.zero, 1);
如果不对Gizmos的矩阵进行设置,默认为单位矩阵。
四、 Gizmos经验使用

1. 绘制圆环(Circle)

由于Gizmos没有自带的圆环绘制API,这里我们使用DrawLine自行计算圆环线段来实现圆环绘制。
样例:


示例代码:
public Transform player; //绑定player
public Transform enemy; //绑定enemy
...
if (player != null && enemy != null)
{
    Gizmos.color = Color.green; //设置绿色
    Gizmos.DrawSphere(player.position, 0.5f); //在player处绘制球体
    Gizmos.color = Color.red; //设置红色
    Gizmos.DrawSphere(enemy.position, 0.5f); //在enemy处绘制球体
    Gizmos.color = Color.yellow; //设置黄色
    Gizmos.DrawLine(player.position, enemy.position); //绘制线段连接player enemy
    DrawCircle(enemy, 3, 0.1f, Color.red); //绘制半径3的红色圆环
    DrawCircle(enemy, 5, 0.1f, Color.green); //绘制半径5的绿色圆环
}
// theta越小,线段绘制数越多,圆环越平滑。
private void DrawCircle(Transform transform, float radius, float theta, Color color)
{
    var matrix = Gizmos.matrix; //保存原本的矩阵信息
    Gizmos.matrix = transform.localToWorldMatrix; //应用目标trans矩阵信息
    Gizmos.color = color; //设置颜色
    Vector3 beginPoint = new Vector3(radius, 0, 0); //定义起始点
    Vector3 firstPoint = new Vector3(radius, 0, 0); //定义起始点
    for (float t = 0; t < 2 * Mathf.PI; t += theta) //循环线段绘制
    {
      float x = radius * Mathf.Cos(t); //计算cos
      float z = radius * Mathf.Sin(t); //计算sin
      Vector3 endPoint = new Vector3(x, 0, z); //确定圆环采样点
      Gizmos.DrawLine(beginPoint, endPoint); //绘制线段
      beginPoint = endPoint; //迭代赋值
    }
    Gizmos.DrawLine(firstPoint, beginPoint); //绘制最后一段
    Gizmos.matrix = matrix; //还原Gizmos矩阵信息
}
2. 绘制弧线(Arc)

样例:


示例代码:
public Transform enemy;
...
Gizmos.color = Color.red;
Gizmos.DrawSphere(enemy.position, 0.5f);
DrawArc(enemy, 1, 90, 0.1f, Color.green);
...
private void DrawArc(Transform transform, float radius, float angle, float theta, Color color)
{
    var matrix = Gizmos.matrix;
    Gizmos.matrix = transform.localToWorldMatrix;
    Gizmos.color = color;
    Vector3 beginPoint = Vector3.zero;
    Vector3 firstPoint = Vector3.zero;
    var rad = Mathf.Deg2Rad * angle;
    for (float t = 0; t < rad; t += theta)
    {
      float x = radius * Mathf.Cos(t);
      float z = radius * Mathf.Sin(t);
      Vector3 endPoint = new Vector3(x, 0, z);
      Gizmos.DrawLine(beginPoint, endPoint);
      beginPoint = endPoint;
    }
    Gizmos.DrawLine(firstPoint, beginPoint);
    Gizmos.matrix = matrix;
}
值得注意的是,这种弧线的绘制算法,以单位圆为例,起点是从局部坐标(1,0,0)开始,也就是相对于forward的right方向,90度弧线实际扫过的面积是从right(1,0,0)到forward(0,0,1)的面积。
所以这种算法不适用于AI视锥感知范围的绘制(90度视觉范围应该是相对于forward方向的左右各45度)。
如何修改,那就是简单的数学题了,就待读者自行计算了。
五、小结

Gizmos提供了基本的图形绘制,而场景文本(Text)绘制则是由UnityEditor.Handles.Label提供,我们将在后续介绍中对Handles进行说明。
页: [1]
查看完整版本: Unity3d Editor 编辑器扩展功能详解(4)Gizmos