- 最后登录
- 2017-4-1
- 注册时间
- 2011-7-26
- 阅读权限
- 90
- 积分
- 24690
  
- 纳金币
- 24658
- 精华
- 6
|
自定义编辑器简易教程 an introduction to custom editors
![]()
简介 Introduction
这个教程将让你学会如何创建一个星型控件以及如何制作这个控件的自定义编辑器。你将学会:
动态的建立Mesh。
使用一个嵌套类。
建立一个自定义编辑器。
使用SerializedObject。
支持所见即所得。
对Undo、Redo、Reset和prefab提供支持。
支持多对象编辑。
支持场景视图内编辑。
我们假设你已经学会了Unity C#的基础编程知识,以及Unity 编辑器的基础知识。如果你已经完成了相关的学习,Let's Go!
建立Star类 Creating the star
我们建立一个全新的Unity工程,然后建立一个新的C#脚本,将它命名为Star。我们将用这个脚本,建立一个由三角面拼接成的星,这里需要一个Mesh。
什么是Mesh?
3D模型是由多边形拼接而成,一个复杂的多边形,实际上是由多个三角面拼接而成。所以一个3D模型的表面是由多个彼此相连的三角面构成。三维空间中,构成这些三角面的点以及三角形的边的集合就是Mesh。
using UnityEngine;
public class Star : MonoBehaviour {
private Mesh mesh;
}
任何对于Mesh的使用,都必须搭配一个MeshFilter组件,而MeshFilter又被用于MeshRenderer组件。只有这样,才能被Unity绘制。所以,这些组件都必须被加载到GameObject对象上,我们的Star对象也必须这么做。
当然,我们可以手动添加这些组件,但默认的自动添加是一个更好的办法。所以我们需要添加一个RequireComponent类作为Star对象的一个特性。
什么是类的特性?
特性像对类附加一个标签,用来告诉编译器这个类需要如何处理。是除了类声明的代码之外,对类做的附加说明。另外,特性不止针对类,对方法和属性同样适用。
typeof有什么用?
typeof是一种运算符,能够获得任何类的类型描述数据,数据里最常用的就是类的名字。那为什么不直接在代码里写类的名字就好呢?因为代码中所有的赋值和运算都需要变量,直接使用类的名字会导致编译错误。
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Star : MonoBehaviour {
private Mesh mesh;
}
现在,我们建立一个新的空GameObject,将它命名为My First Star,然后拖拽我们的脚本Star到My First Star上。你可以看到,My First Star拥有了两个组件,MeshRenderer和Star。
拖动一个,得到三个
![]()
下一个步骤是建立一个Mesh。我们需要在Unity的Start事件里来做这些事,Start事件将在程序启动的时候发生。我们还需要在MeshFilter中给这个新的Mesh起一个名字。
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Star : MonoBehaviour {
private Mesh mesh;
void Start () {
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Star Mesh";
}
}
无编辑器模式与实时预览模式
![]()
当然,现在我们在预览模式下还看不到任何东西,因为Mesh还是空的。所以让我们开始编辑顶点数组吧,我们的Star类需要一个用来设置顶点数量的属性,以及这些定点与中心的相对距离。
第一个顶点是Star的中心点,其余的顶点将顺时针排列。我们将使用四元数来计算这些点的排列。因为我们假设俯视Z轴,所以,轮转的角度是负数,否则,将使这些点做逆时针排列。我们不需要设置第一个点,因为vector默认会被设置成0, Mesh中使用本地坐标系。
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Star : MonoBehaviour {
public Vector3 point = Vector3.up;
public int numberOfPoints = 10;
private Mesh mesh;
private Vector3[] vertices;
void Start () {
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Star Mesh";
vertices = new Vector3[numberOfPoints + 1];
float angle = -360f / numberOfPoints;
for(int v = 1; v < vertices.Length; v++){
vertices[v] = Quaternion.Euler(0f, 0f, angle * (v - 1)) * point;
}
mesh.vertices = vertices;
}
}
新的编辑器属性
![]()
三角面会被保存成顶点数组,每个面三个顶点。因为我们使用三角形来描述多边形,每个三角形都起始于相同的中点,并且与其他的三角形相连。最后一个三角形与第一个三角形相连。例如,如果有四个三角形,那么顶点数组如下{0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 1}。
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Star : MonoBehaviour {
public Vector3 point = Vector3.up;
public int numberOfPoints = 10;
private Mesh mesh;
private Vector3[] vertices;
private int[] triangles;
void Start () {
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Star Mesh";
vertices = new Vector3[numberOfPoints + 1];
triangles = new int[numberOfPoints * 3];
float angle = -360f / numberOfPoints;
for(int v = 1, t = 1; v < vertices.Length; v++, t += 3){
vertices[v] = Quaternion.Euler(0f, 0f, angle * (v - 1)) * point;
triangles[t] = v;
triangles[t + 1] = v + 1;
}
triangles[triangles.Length - 1] = 1;
mesh.vertices = vertices;
mesh.triangles = triangles;
}
}
一个简单的星星
![]()
现在,我们的星星看起来还只是一个简单的多边形。Unity也提示说丢失材质坐标,因为默认的Shader需要这些坐标。我们不会使用一个纹理来描绘所有的星星,让我们通过建立我们自己的Shader来消除这个警告,这个Shader将只使用顶点着色。
我们建立一个新的Shader将它命名为Star,然后写入以下代码。
什么是CGPROGRAM?
Basically, data flows from the Unity engine into the graphics card, where it's processed per vertex. Then interpolated data flows from the vertices down to the individual pixels. In this case, we pass position and color data all the way down. The only additional thing we do is convert vertex positions from world space to screen space.
The statements above the CGPROGRAM switch off default lighting and depth buffer writing. Culling is switched off so we can see the triangles from both sides, not just the front. "Blend SrcAlpha OneMinusSrcAlpha" is default alpha blending, allowing for transparency.
为什么不使用fixed-function shader?
fixed-function shader已经属于过时的技术了。 CGPROGRAM 在将数据转化成屏幕像素方面拥有更强大的功能。
Shader "Star"{
SubShader{
Tags{ "Queue"="Transparent" "IgnoreProjector"="***e" "RenderType"="Transparent"}
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Lighting Off
ZWrite Off
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
s***ct data {
float4 vertex : POSITION;
fixed4 color: COLOR;
};
data vert (data v) {
v.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
return v;
}
fixed4 frag(data f) : COLOR {
return f.color;
}
ENDCG
}
}
} |
|