Unity-可编辑的星星特效


阅前须知

本文前置知识:CustomData与CustomList

绘制星星

创建一个名为Star的普通脚本,定义以下字段,然后将这个脚本挂在一个空对象上

//网格
private Mesh mesh;
//顶点
private Vector3[] vertices;
//颜色
private Color[] colors;
//三角形(顶点索引)
private int[] triangles;

顶点网格

思路

首先,我们要绘制顶点网格。以vertices[0]为中心点。其余所有的顶点围绕中心点绘制。

按照定义顺序绘制三角形,例如:

第一个三角形的索引顶点为:0-1-2

第二个三角形的索引顶点为:0-2-3

第三个三角形的索引顶点为:0-3-4

请注意,我们还没有定义控制点,也就是距离中心点一定距离的初始定义点Points

所有后续的顶点会按照初始定义的点按照均分角度依次旋转。其次每一个顶点都应该拥有他的颜色。

这里我们使用上篇文章使用的ColorPoint,现在我们继续定义

//中心点
public ColorPoint center;
//顶点
public ColorPoint[] points;
//迭代次数
public int frequency = 1;

实现

首先初始化网格,注意所有代码我们暂时写在Start里

void Start()
{       GetComponent<MeshFilter>().mesh = mesh = new Mesh();mesh.name = "Star Mesh";
}

下限判断

//迭代次数至少为1
if (frequency < 1)
{frequency = 1;
}
//顶点数字初始化
if (points == null)
{points = new ColorPoint[0];
}

确定顶点总数

顶点总数为迭代次数与控制点长度的乘积,你可能还不太明白,但是这没有关系,读下去你会明白的。

int numberOfPoints = frequency * points.Length;

初始化顶点数组,颜色数组,索引数组

vertices = new Vector3[numberOfPoints + 1];
colors = new Color[numberOfPoints + 1];
triangles = new int[numberOfPoints * 3];

注意,这里顶点与颜色数组都进行了加1,这是因为中心点,而我们计算的顶点总数是不包含中心点的。

顶点总数就等于三角形总数,因此索引数组是三倍的顶点总数。

请注意,顶点总数有他的下限,也就是3个顶点,如果仅有两个顶点时无法绘制三角形的,因为一个顶点在最上面一个在最下面,他们与中心点构成了直线而不是三角形。

代码如下:

if (numberOfPoints >= 3)
{//中心点vertices[0] = center.position;colors[0] = center.color;//均分角度float angle = -360f / numberOfPoints;//迭代次数for (int repetitions = 0, v = 1, t = 1; repetitions < frequency; repetitions++){//每次迭代,遍历所有控制点for (int p = 0; p < points.Length; p += 1, v += 1, t += 3){//顶点旋转vertices[v] = Quaternion.Euler(0f, 0f, angle * (v - 1)) * points[p].position;colors[v] = points[p].color;//索引赋值triangles[t] = v;triangles[t + 1] = v + 1;}}//最后一个三角形循环到第一个顶点triangles[triangles.Length - 1] = 1;
}

最后将各数组赋予给网格

mesh.vertices = vertices;
mesh.colors = colors;
mesh.triangles = triangles;

让我们看看效果:

呈现紫色,是因为还没有赋予材质,没有着色器绘制。

创建一个材质并将材质赋予对象,然后创建一个Shader并使用下面的Shader代码

Shader "MyShader/Star" {SubShader {Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }Blend SrcAlpha OneMinusSrcAlphaCull OffLighting OffZWrite OffPass {CGPROGRAM#pragma vertex vert#pragma fragment fragstruct data {float4 vertex : POSITION;fixed4 color: COLOR;};data vert (data v) {v.vertex = UnityObjectToClipPos(v.vertex);return v;}fixed4 frag(data f) : COLOR {return f.color;}ENDCG}}
}

现在,让我们来看看效果:

数据参考:

自定义编辑器

[CustomEditor(typeof(Star)), CanEditMultipleObjects]
public class StarInspector : Editor
{public override void OnInspectorGUI(){SerializedPropertypoints = serializedObject.FindProperty("points"),frequency = serializedObject.FindProperty("frequency");serializedObject.Update();EditorGUILayout.PropertyField(serializedObject.FindProperty("center"));EditorList.Show(points,EditorListOption.Buttons | EditorListOption.ListLabel);EditorGUILayout.IntSlider(frequency, 1, 20);int totalPoints = frequency.intValue * points.arraySize;if (totalPoints < 3){EditorGUILayout.HelpBox("At least three points are needed.", MessageType.Warning);}else{EditorGUILayout.HelpBox(totalPoints + " points in total.", MessageType.Info);}serializedObject.ApplyModifiedProperties();}
}

如果你不明白上述代码,我建议你先阅读CustomList

编辑器模式

到目前为止,我们要查看效果必须要运行才可以查看,并且不可更改,这十分麻烦。接下来,我们将介绍如何编写编辑器模式

我们需要做的第一件事是告诉Unity,我们的组件应该在编辑模式下处于活动状态。我们通过添加ExecuteInEditMode类属性来表明这一点。从现在开始,只要编辑器中出现星号,就会调用Start方法。
因为我们在开始时创建了一个网格,所以它将在编辑模式下创建。当我们将它分配给一个MeshFilter时,它将持久化并保存在场景中。我们不希望这种情况发生,因为我们是动态生成网格的。我们可以通过设置适当的HideFlags来阻止Unity保存网格。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[ExecuteInEditMode,RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Star : MonoBehaviour
{public int numberOfPoints = 10;private Mesh mesh;private Vector3[] vertices;private Color[] colors;private int[] triangles;public ColorPoint center;public ColorPoint[] points;public int frequency = 1;void Start(){GetComponent<MeshFilter>().mesh = mesh = new Mesh();mesh.name = "Star Mesh";mesh.hideFlags = HideFlags.HideAndDontSave;if (frequency < 1){frequency = 1;}if (points == null){points = new ColorPoint[0];}int numberOfPoints = frequency * points.Length;vertices = new Vector3[numberOfPoints + 1];colors = new Color[numberOfPoints + 1];triangles = new int[numberOfPoints * 3];if (numberOfPoints >= 3){vertices[0] = center.position;colors[0] = center.color;float angle = -360f / numberOfPoints;for (int repetitions = 0, v = 1, t = 1; repetitions < frequency; repetitions++){for (int p = 0; p < points.Length; p += 1, v += 1, t += 3){vertices[v] = Quaternion.Euler(0f, 0f, angle * (v - 1)) * points[p].position;colors[v] = points[p].color;triangles[t] = v;triangles[t + 1] = v + 1;}}triangles[triangles.Length - 1] = 1;}mesh.vertices = vertices;mesh.colors = colors;mesh.triangles = triangles;}
}

编辑网格更新

我们先将网格更新封装为一个方法,并添加reset重置也要调用网格更新

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[ExecuteInEditMode,RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Star : MonoBehaviour
{public int numberOfPoints = 10;private Mesh mesh;private Vector3[] vertices;private Color[] colors;private int[] triangles;public ColorPoint center;public ColorPoint[] points;public int frequency = 1;void Start(){UpdateMesh();}void Reset(){UpdateMesh();}private void OnEnable(){UpdateMesh();}public void UpdateMesh(){if (mesh == null){GetComponent<MeshFilter>().mesh = mesh = new Mesh();mesh.name = "Star Mesh";mesh.hideFlags = HideFlags.HideAndDontSave;}if (frequency < 1){frequency = 1;}if (points == null){points = new ColorPoint[0];}int numberOfPoints = frequency * points.Length;if (vertices == null || vertices.Length != numberOfPoints + 1){vertices = new Vector3[numberOfPoints + 1];colors = new Color[numberOfPoints + 1];triangles = new int[numberOfPoints * 3];mesh.Clear();}if (numberOfPoints >= 3){vertices[0] = center.position;colors[0] = center.color;float angle = -360f / numberOfPoints;for (int repetitions = 0, v = 1, t = 1; repetitions < frequency; repetitions++){for (int p = 0; p < points.Length; p += 1, v += 1, t += 3){vertices[v] = Quaternion.Euler(0f, 0f, angle * (v - 1)) * points[p].position;colors[v] = points[p].color;triangles[t] = v;triangles[t + 1] = v + 1;}}triangles[triangles.Length - 1] = 1;}mesh.vertices = vertices;mesh.colors = colors;mesh.triangles = triangles;}
}

编辑器属性改变即更新网格,其中撤销也要更新网格

if (serializedObject.ApplyModifiedProperties() ||Event.current.commandName == "UndoRedoPerformed")
{foreach (Star s in targets){s.UpdateMesh();}
}

预制体不更新网格

if (PrefabUtility.GetPrefabType(s) != PrefabType.Prefab) {s.UpdateMesh();
}

禁用多对象编辑

if (!serializedObject.isEditingMultipleObjects)
{int totalPoints = frequency.intValue * points.arraySize;if (totalPoints < 3){EditorGUILayout.HelpBox("At least three points are needed.", MessageType.Warning);}else{EditorGUILayout.HelpBox(totalPoints + " points in total.", MessageType.Info);}
}

场景视图编辑器

//句柄在所有轴上的单元增量
private static Vector3 pointSnap = Vector3.one * 0.1f;void OnSceneGUI()
{//获得目标对象Star star = target as Star;Transform starTransform = star.transform;float angle = -360f / (star.frequency * star.points.Length);for (int i = 0; i < star.points.Length; i++){//偏移量Quaternion rotation = Quaternion.Euler(0f, 0f, angle * i);//原偏移量Vector3 oldPoint = starTransform.TransformPoint(rotation *          star.points[i].position),//创造一个句柄,传入位置和旋转newPoint = Handles.FreeMoveHandle(oldPoint, Quaternion.identity, 0.02f, pointSnap, Handles.DotHandleCap);//判断位置是否相同if (oldPoint != newPoint){Undo.RecordObject(star, "Move");//这里要注意,所有网格的位置都是局部空间,因此,而通过句柄返回的newPoint为世界空间位置//因此,变化到局部空间后的位置再叠加偏移量,然后将偏移量叠加回去,因为对象数据需要的是没有偏移量的点,这里要叠加逆旋转去消除偏移量star.points[i].position = Quaternion.Inverse(rotation) *starTransform.InverseTransformPoint(newPoint);star.UpdateMesh();}}
}

最终效果:

Unity-可编辑的星星特效相关推荐

  1. 《Unity着色器和屏幕特效》——2.2 进阶的透明效果

    本节书摘来自华章计算机<Unity着色器和屏幕特效>一书中的第2章,第2.2节,作者[美]杰米·迪恩(Jamie Dean),译 周翀,张薇,更多章节内容可以访问云栖社区"华章计 ...

  2. 《Unity着色器和屏幕特效开发秘笈》—— 3.4 创建BlinnPhong高光类型

    本节书摘来自华章出版社<Unity着色器和屏幕特效开发秘笈>一 书中的第3章,第3.4节,作者:(美)Kenny Lammers,更多章节内容可以访问云栖社区"华章计算机&quo ...

  3. Unity粒子系统创建VFX游戏特效学习教程 Visual Effects in Unity Particle Systems [Beginner’s Guide]

    在Unity中学习高级粒子系统和视觉效果创建.初级到中级 你会学到: 游戏的视觉效果 Unity粒子系统 Unity中的Vfx 创建Unity视觉效果的初级到中级指南 课程获取:Unity粒子系统创建 ...

  4. Unity创建游戏VFX视觉特效-初级到中级

    MP4 |视频:h264,1280×720 |音频:AAC,44100 Hz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:3.36 GB |时长:4h 17m 本课程是关于用Uni ...

  5. 《Unity着色器和屏幕特效开发秘笈》—— 2.1 引言

    本节书摘来自华章出版社<Unity着色器和屏幕特效开发秘笈>一 书中的第2章,第2.1节,作者:(美)Kenny Lammers,更多章节内容可以访问云栖社区"华章计算机&quo ...

  6. 《Unity着色器和屏幕特效开发秘笈(原书第2版)》一2.9 打包和混合纹理

    本节书摘来自华章出版社<Unity着色器和屏幕特效开发秘笈(原书第2版)>一书中的第2章,第2.9节,作者 [英]艾伦朱科尼(Alan Zucconi) [美]肯尼斯拉默斯(Kenneth ...

  7. 《Unity着色器和屏幕特效开发秘笈》—— 1.7 创建渐变纹理来控制漫反射着色...

    本节书摘来自华章出版社<Unity着色器和屏幕特效开发秘笈>一 书中的第1章,第1.7节,作者:(美)Kenny Lammers,更多章节内容可以访问云栖社区"华章计算机&quo ...

  8. 《Unity着色器和屏幕特效开发秘笈》—— 第3章 利用镜面反射让游戏闪耀起来...

    本节书摘来自华章出版社<Unity着色器和屏幕特效开发秘笈>一 书中的第3章,第3.1节,作者:(美)Kenny Lammers,更多章节内容可以访问云栖社区"华章计算机&quo ...

  9. java闪光的星星_基于JavaScript实现飘落星星特效

    本文实例为大家分享了js飘落星星特效的具体代码,供大家参考,具体内容如下 1.效果图 2.代码 Title img{ position: absolute; } body { background-i ...

最新文章

  1. 修复电脑右键没有新建记事本
  2. jQuery插件推荐(一) ——图像切换展示
  3. 使用sklearn来处理类别数据
  4. 使用eclipse调试ns3配置说明
  5. 30分钟,让你成为一个更好的程序员
  6. 项目管理、bug管理工具 ---禅道使用流程
  7. 随笔编号-03 基本类型相互转换集合
  8. VLAN设置实例全程解读
  9. VB讲课笔记01:VB6.0安装与启动
  10. java数组硬盘读取,java中如何通过IO流将稀疏数组写入磁盘和从磁盘中读取,整行存,整行取...
  11. ubuntu 编译安装nginx php mysql_ubuntu下安装nginx php mysql
  12. Intel微处理器列表_百度百科
  13. 分类计数原理与分步计数原理_两种基础的计数原理
  14. 小爱mini改aux立体声_拆解报告:Redmi小爱音箱Play
  15. 计算机中丢失了gdiplus.dll,解决 “计算机中丢失gdiplus.dll”
  16. 结构梁配筋最牛插件_YouTube 字幕翻译 —— Chrome 插件
  17. Spring学习Ioc
  18. msyql数据库[云图智联]
  19. 风控每日一问:风控工作的价值在于?
  20. 实话实说,现在的结婚,真就是走个形式!

热门文章

  1. 我的同事们(一):Alex Peng
  2. 软件测试到底是做什么的?职责是什么?
  3. 祝朋友们端午节快乐!
  4. 使用packet Tracer配置静态路由和动态路由
  5. STM32 RTC时钟源LSE
  6. 2018 ucla计算机排名,2018USNews美国最佳公立大学排名,UCLA和UCB并列第一
  7. 安装windows server 2008 R2虚拟机,并成功安装VMware Tools(下)
  8. 谷歌开源能翻译101种语言的AI模型,只比Facebook多一种
  9. mysql启动报错mysqld_safe MySQL from pid file /var/run/MariaDB/marabi.pid ended
  10. 基于无线NRF24L01的ardunio遥控小车