【Unity 3D】元宇宙案例之虚拟地球信息射线实战(附源码、演示视频和步骤 超详细)

简介: 【Unity 3D】元宇宙案例之虚拟地球信息射线实战(附源码、演示视频和步骤 超详细)

需要源码和资源包请点赞关注收藏后评论区留言私信~~~

一、效果展示

效果展示如下 射线动态的在地球上发射和接收 整个场景也是一个的动态的过程,看上去充满科技感

演示视频如下

虚拟地球射线

二、实现步骤

打开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;
    }
}

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
10天前
|
安全 图形学
Unity射线检测的“坑”
在 Unity 中,射线检测是常用功能,但也存在一些常见问题。首先是层(Layer)设置问题,如射线忽略某些层或误检测到不期望的层,需正确设置 LayerMask。其次是碰撞体相关问题,包括碰撞体未启用或类型不匹配,确保碰撞体启用并合理设置属性。再者是射线起始点和方向问题,错误的位置或方向计算会导致检测失败,需准确设置起始点和方向。此外,频繁进行射线检测或检测范围过大会影响性能,应减少检测次数并合理设置范围。最后,在多线程中进行射线检测可能导致错误,应避免在非主线程中直接调用射线检测。
|
10天前
|
图形学
Unity 获取鼠标位置下的UGUI或3D物体
本文总结了两种检测方法,分别用于UGUI和3D物体的检测。第一种方法`GetOverUIobj`专门用于检测鼠标悬停的UGUI元素,通过`GraphicRaycaster`实现。第二种方法`GetOverWordGameObject`则同时适用于UI和3D物体检测,利用`PhysicsRaycaster`进行射线检测。两者均返回悬停对象或null。
|
10天前
|
前端开发 图形学
unity UGUI跟随3D物体的坐标转换
在 Unity 中实现 UGUI 元素跟随 3D 物体,关键是将 3D 物体的世界坐标转换为屏幕或画布坐标。通过 Camera.WorldToScreenPoint 方法,可将 3D 物体位置映射到屏幕上,再更新 UGUI 元素的位置。代码示例展示了如何使用该方法,使 UGUI 图像跟随 3D 模型,并提供文字显示、图像和线条的显示/隐藏功能。
|
10天前
|
图形学
Unity 射线移动物体Ray
在Unity中,通过射线检测实现3D物体的拖拽和移动。射线由起点和方向组成,使用`Physics.Raycast`检测与物体的交点。点击物体时,记录位置偏移量,拖动过程中更新物体位置。代码包括基本拖拽和上下拖动功能,适用于正交摄像机场景。测试时为物体设置特定标签(如&quot;JQR&quot;)以便区分和操作。 示例代码展示了如何通过鼠标事件控制物体移动,并结合层级掩码优化射线检测。具体实现包括:点击选中物体、拖动更新位置、释放鼠标取消选择。此外,提供了上下拖动的额外功能,通过按键切换模式。
|
6月前
|
图形学 数据可视化 开发者
超实用Unity Shader Graph教程:从零开始打造令人惊叹的游戏视觉特效,让你的作品瞬间高大上,附带示例代码与详细步骤解析!
【8月更文挑战第31天】Unity Shader Graph 是 Unity 引擎中的强大工具,通过可视化编程帮助开发者轻松创建复杂且炫酷的视觉效果。本文将指导你使用 Shader Graph 实现三种效果:彩虹色渐变着色器、动态光效和水波纹效果。首先确保安装最新版 Unity 并启用 Shader Graph。创建新材质和着色器图谱后,利用节点库中的预定义节点,在编辑区连接节点定义着色器行为。
448 0
|
6月前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
222 1
|
6月前
|
图形学 Android开发 iOS开发
穿越数字洪流,揭秘Unity3d中的视频魔法!Windows、Android和iOS如何征服RTSP与RTMP的终极指南!
【8月更文挑战第15天】在数字媒体的海洋中,实时视频流是连接世界的桥梁。对于那些渴望在Unity3d中搭建这座桥梁的开发者来说,本文将揭示如何在Windows、Android和iOS平台上征服RTSP与RTMP的秘密。我们将深入探讨这两种协议的特性,以及在不同平台上实现流畅播放的技巧。无论你是追求稳定性的RTSP拥趸,还是低延迟的RTMP忠实粉丝,这里都有你需要的答案。让我们一起穿越数字洪流,探索Unity3d中视频魔法的世界吧!
117 2
|
5月前
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
533 0
|
6月前
|
开发者 图形学 API
从零起步,深度揭秘:运用Unity引擎及网络编程技术,一步步搭建属于你的实时多人在线对战游戏平台——详尽指南与实战代码解析,带你轻松掌握网络化游戏开发的核心要领与最佳实践路径
【8月更文挑战第31天】构建实时多人对战平台是技术与创意的结合。本文使用成熟的Unity游戏开发引擎,从零开始指导读者搭建简单的实时对战平台。内容涵盖网络架构设计、Unity网络API应用及客户端与服务器通信。首先,创建新项目并选择适合多人游戏的模板,使用推荐的网络传输层。接着,定义基本玩法,如2D多人射击游戏,创建角色预制件并添加Rigidbody2D组件。然后,引入网络身份组件以同步对象状态。通过示例代码展示玩家控制逻辑,包括移动和发射子弹功能。最后,设置服务器端逻辑,处理客户端连接和断开。本文帮助读者掌握构建Unity多人对战平台的核心知识,为进一步开发打下基础。
226 0
|
6月前
|
开发者 图形学 C#
揭秘游戏沉浸感的秘密武器:深度解析Unity中的音频设计技巧,从背景音乐到动态音效,全面提升你的游戏氛围艺术——附实战代码示例与应用场景指导
【8月更文挑战第31天】音频设计在游戏开发中至关重要,不仅能增强沉浸感,还能传递信息,构建氛围。Unity作为跨平台游戏引擎,提供了丰富的音频处理功能,助力开发者轻松实现复杂音效。本文将探讨如何利用Unity的音频设计提升游戏氛围,并通过具体示例代码展示实现过程。例如,在恐怖游戏中,阴森的背景音乐和突然的脚步声能增加紧张感;在休闲游戏中,轻快的旋律则让玩家感到愉悦。
205 0