需要源码和资源包请点赞关注收藏后评论区留言私信~~~
一、效果展示
效果展示如下 射线动态的在地球上发射和接收 整个场景也是一个的动态的过程,看上去充满科技感
演示视频如下
虚拟地球射线
二、实现步骤
打开Unity Hub选择新建下项目,选择3D模板,工程名为EarthRay
然后导入资源包 需要资源包请点赞关注收藏后评论区留言私信
1:制作虚拟地球
创建球体 在Hierarchy视图中右击,选择3D Object->Sphere命令 新建一个球体
然后将球体的position设置为0,0,0,设置摄像机的position属性为0,0,-1.5,这样地球就在屏幕正中间显示了
2:制作虚拟地球大气层
在Hierarchy视图中右击球体对象,选择新建一个球体,命名为Clouds
然后调整Clouds对象的Scale属性为1.01,1.01,1.01 使其比Earth对象大一点,笼罩在Earth对象外围
3:天空盒设置
天空有些单调 我们将天空盒设置为太空的场景 这样看起来更美观和具有科技感
打开window-rendering-lighting窗口 然后切换到environment选项卡 找到skybox material属性,然后将materials文件夹中的skybox文件拖入skybox material属性卡槽
至此 虚拟地球场景搭建完成
4:制作虚拟地球信息射线
首先我们要实现地球自转
在Scripts文件夹中新建一个C#脚本,命名为Earth 代码放在文章结尾
在实现虚拟地球信息射线前,需要先了解一下如何制作射线
因为地球的球面是一个弧形,从地球上的一点向另一点发射信息射线是一个弧线,所以不能直接将两个点链接到一起,需要弧度平滑,弧度平滑可以用贝塞尔曲线生成
5:实现单击后发射虚拟地球信息射线
接下来实现当单击地球上两个点后发射虚拟地球信息射线的功能
新建一个C#脚本,命名为Line 代码放在文章末尾
6:实现自动发射虚拟地球信息射线
自动发射虚拟地球信息射线需要先在球的表面选取两个点,用代码实现时要设计几何知识,已知球的求新坐标,要想在球的表面随机选取两个点,需要先在球心随机生成两个方向向量,这两个方向向量从球心出发,分别经过一个半径长度,即可到达球的表面,方向向量与球的表面的相交处就是要选取的点
7:波纹粒子特效
我们将用做好的粒子特效,直接导入即可
三、代码
导入资源包结构如下
代码文件夹结构如下
部分代码如下 需要全部代码请点赞关注收藏后评论区留言私信~~~
earth.cs
using System.Collections; using Uni public class Earth : MonoBehaviour { public Line line;// 曲线 private Vector3 pos1 = Vector3.zero;// 鼠标点击第一个点 private Vector3 pos2 = V { line.gameObject.SetActive(false); } void Update() { // 地球自转 transform.Rotate(Vector3.up * Time.deltaTime, Space.Self); // 点击发射虚拟地球信息射线 RayClickLine(); // 自动发射虚拟地球信息射线 AutoFireLine(); } /// <summar private void RayClickLine() { if (Input.GetMouseButtonDown(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { mouseClicks++; if (mouseClicks == 1) { // 第一个点坐标 pos1 = hit.point; } if (mouseClicks == 2) {2 = hit.point; // 计算其他点的坐标 Vector3[] pos; pos = CountPoints(pos1, pos2); Vector3 ctrlPoint1 = pos[0]; Vector3 ctrlPoint2 = pos[1]; Line line = Instantiate(this.line); line.gameObject.SetActive(true); line.transform.SetParent(transform); // 画线 StartCoroutine(line.DrawRay(transform.position,pos1, ctrlPoint1, ctrlPoint2, pos2)); // 状态恢复 pos1 = Vector3.zero; pos2 = Vector3.zero; mouseClicks = 0; } } } } /// <summary> /// 自动发射虚拟地球信息射线 /// </summary> /// <returns></returns> void AutoFireLine() { //this.line.gameObject.SetActive(false); invokeTime += Time.deltaTime; if (invokeTime > invokeDistance) { // 循环生成曲线 Line line = Instantiate(this.line); line.gameObject.SetActive(true); line.transform.SetParent(transform); // 在地球表面随机一个起始点 Vector3 fromPos = SpawnRandPos(); // 在地球表面随机一个终点 Vector3 toPos = SpawnRandPos(); // 计算其他点的坐标 Vector3[] pos; pos = CountPoints(fromPos, toPos); Vector3 ctrlPoint1 = pos[0]; Vector3 ctrlPoint2 = pos[1]; StartCoroutine(line.DrawRay(transform.position,fromPos, ctrlPoint1, ctrlPoint2, toPos)); // 状态恢复 invokeTime = 0; invokeDistance = Random.Range(0.3f, 2f); } } // 控制点2 pos[1] = toPos + (center - transform.position).normalized * (fromPos - toPos).magnitude * 0.6f; return pos; } //生成随机点 private Vector3 SpawnRandPos() { // 半径 float radius = transform.localScale.x / 2f; Vector3 Pos= transform.position + new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)).normalized * radius; return Pos; } }
line.cs
using System.Collections; using SystEngine; public class Line : MonoBehaviour { private LineRenderer lineRenderer;//lineRenderer组件 private List<Vector3> posList = new List<Vector3>();//存储点坐标 public int MAX_FRAG_CNT = 100;//曲线最大点数 void Awake() { lineRenderer = GetComponent<LineRenderer>(); } public Transform startPoint;//开始位置波纹粒子 public Transform endPoint; //结束位置波纹粒子 /// <summary> /// 绘制曲线 /// </summary> /// <param name="earthPos">虚拟地球位置</param> /// <param name="fromPos">起点坐标</param> /// <param name=trlPoint2">控制坐标2</param> /// <param name="toPos">终点坐标</param> /// <returns></returns> public IEnumerator DrawRay(Vector3 earthPos, Vector3 fromPos, Vector3 ctrlPoint1, Vector3 ctrlPoint2, Vector3 toPos) { // 起始位置粒子 startPoint.gameObject.SetActive(true); startPoint.forward = fromPos - earthPos; startPoint.localPosition = fromPos + startPoint.forward * 0.01f; for (int i = 0; i <= MAX_FRAG_CNT; ++i) { posList.Clear(); for (int j = 0; j <= i; ++j) { posList.Add(cubicBezier(fromPos, ctrlPoint1, ctrlPoint2, toPos, (float)j / MAX_FRAG_CNT)); } lineRenderer.positionCount = posList.Count; lineRenderer.SetPositions(posList.ToArray()); yield return new WaitForSeconds(0.02f); } // 目标位置粒子 endPoint.gameObject.SetActive(true); endPoint.forward =MAX_FRAG_CNT; ++i) { posList.Clear(); for (int j = i; j <= MAX_FRAG_CNT; ++j) { posList.Add(cubicBezier(fromPos, ctrlPoint1, ctrlPoint2, toPos, (float)j / MAX_FRAG_CNT)); } lineRenderer.positionCount = posList.Count; lineRenderer.SetPositions(posList.ToArray()); yield return new WaitForSeconds(0.001f); } Destroy(gameObject); } /// <summary> /// 三阶贝塞尔曲线 /// </summary> /// <param name="pos1">控制点1</param> /// <param name= private Vector3 cubicBezier(Vector3 pos1, Vector3 pos2, Vector3 pos3, Vector3 pos4, float t) { Vector3 aa = pos1 + (pos2 - pos1) * t; Vector3 bb = pos2 + (pos3 - pos2) * t; Vector3 cc = pos3 + (pos4 - pos3) * t; return (aa + (bb - aa) * t) + ((bb + (cc - bb) * t) - (aa + (bb - aa) * t)) * t; } }
创作不易 觉得有帮助请点赞关注收藏~~~