【ARFoundation自学04】AR Tracked Image 图像追踪识别与对应类的调用

图像识别是很常用的AR功能!AR foundation 可以帮助我们轻松实现!

1.安装插件

首先还是在资源包中导入ARfoundation 。然后搭建基本的AR ARFoundation框架!

2.创建AR session 和XR origin结构!

3.然后在XR Origin 物体身上添加AR Tracker Image Manager组件!

这个组件主要负责实现目标图像的识别和追踪! 但是我们需要思考,识别那个图片,识别后让谁追踪图片!他的主要原理是,创建一个图像库Library(Serialized Library),把要被识别的图都放进去,将来所有在库里面的图都可以被单独识别!

然后,识别图片后,为了让我们能够看到追踪图片的视觉效果,AR Tracker Image Manager会为识别后的图像克隆一份Tracked Image Prefab 用于跟随识别到的图像一起运动(移动或者旋转)!如何创建一个Tracked Image Prefab ,我们后面再讲!

4.创建图像识别库

这个图像库,需要用户安装插件后,在Assets 仓库面板空白点右键-Create-XR-Reference Image Library ,然后点击创建的图像库,在右侧属性面板添加将来要被识别的图!

这些图将来都会可识别!

5.创建识别后追踪的预制体(UI、模型等)Tracked Image Prefab  

这个预制体是图像识别专用的,因此需要挂载AR Tracked Image 组件!任何物体挂在了这个组件都可以作为识别图像后的追踪预制体!

那么我们自己的模型放在那里才可以追踪图片呢?只需要放在搭载AR Tracked Image 组件的父物体下面即可!

例如创建一个空物体,挂载AR Tracked Image 组件。把我们的模型放在这个空物体的子物体下面即可!

6. 把创建好可识别图像库以及追踪预制体赋值给 AR Tracker Image Manager组件!完毕

最后 AR Tracker Image Manager组件!还有个属性Max Number Of Moving Image 是最大可跟踪的动态图像数量!

7.其他参数介绍

图像跟踪技术,是指通过图像处理技术对摄像头中拍摄到的2D图像进行定位,并对其姿态进行跟踪的技术。图像跟踪技术的基础是图像识别,图像识别是指识别和检测出数字图像或视频中对象或特征的技术,图像识别技术是信息时代的一门重要技术,其产生目的是为了让计算机代替人类去处理大量的图形图像及真实物体信息,因而成为其他许多重要技术的基

  1. 最大并发跟踪数(Max Simultaneous Tracked Images):

    指定同时能够被识别和跟踪的图像数量。由于图像跟踪较为耗能,限制此数值可以避免性能问题。

    2. 参考图像(Reference Image)    

  • 这些是您希望AR应用能够识别的特定2D图像。比如,一张海报或标志。您需要事先在Unity项目中定义这些图像作为资源。别2D图像的过程实际是一个特征值对比的过程,ARFoundation将从摄像头中获取的图像信息与参考图像库的图像特征点信息进行对比,存储在参考图像库中的用于对比的图像就叫做参考图像。一旦对比成功,真实环境中的图像将与参考图像库的参考图像建立对应关系,每一个真实2D图像的姿态信息也一并被检测。

      3.参考图像库(Reference Image Library)    :

参考图像库用来存储一系列的参考图像用于对比,每一个图像跟踪程序都必须有一个参考图像库,但需要注意的是,参考图像库中存储的实际是参考图像的特征值信息而不是原始图像,这有助于提高对比速度与鲁棒性。参考图像库越大,图像对比就会越慢,建议参考图像库的图像不要超过1000张。跟踪组件提供方(Provider)    ARFoundation是架构在底层SDK图像跟踪API之上的,也即是说ARFoundation并不具体负责图像识别过程的算法,它只提供一个接口,具体图像识别由算法提供方提供。

8.动态修改TrackedImageManager的状态

  • 在代码中,你可以访问TrackedImageManager实例并根据需要动态改变其行为。例如,你可以暂时禁用所有图像的跟踪,或者针对特定图像进行开关控制
    public class ImageTrackingController : MonoBehaviour
    {
        public TrackedImageManager trackedImageManager;
        
        public void DisableImageTracking()
        {
            if (trackedImageManager != null)
            {
                trackedImageManager.enabled = false; // 关闭图像跟踪
            }
        }
    
        public void EnableImageTracking()
        {
            if (trackedImageManager != null)
            {
                trackedImageManager.enabled = true; // 启用图像跟踪
            }
        }
    }

    8.多图像跟踪

对于多图像跟踪,你可能不只希望实例化一个Prefab,而是根据识别到的不同图像实例化不同的Prefab。这时,传统的方式是为每个图像在数据集中指定对应的Prefab。但ARFoundation本身并不直接支持每个图像直接关联不同Prefab,因此需要一些额外的编程逻辑来实现这一功能。

实现逻辑

编写自定义脚本

创建一个C#脚本,用于处理图像识别后的逻辑。在这个脚本中,你需要监听TrackedImageUpdated事件,该事件会在图像被识别或跟踪状态改变时触发。

using System.Collections; // 引入集合相关的命名空间,用于列表(List)和字典(Dictionary)等数据结构
using System.Collections.Generic;
using UnityEngine; // 引入Unity引擎的基本功能
using UnityEngine.XR.ARSubsystems; // 引入AR相关子系统的命名空间
using UnityEngine.XR.ARFoundation; // 引入ARFoundation命名空间,提供AR功能的支持
using TMPro; // 引入TextMeshPro文本组件支持

public class ImageTrackControl : MonoBehaviour // 定义一个新的类,继承自MonoBehaviour,这是Unity中脚本的基础类
{
    // 公开变量,用于在Inspector面板中指定图像识别的核心组件
    public ARTrackedImageManager MyImageManagerCom;

    // 定义字符串变量,用于存储当前状态信息
    string myString;

    // 引用TextMeshProUGUI组件,用于在界面上显示文本信息
    public TextMeshProUGUI textdis;
    public TextMeshProUGUI textdis2;

    // 创建一个列表,用来存储预先准备好的图像追踪预制体
    public List<GameObject> MyImagePre = new List<GameObject>();

    // 使用Dictionary存储每个跟踪图的ID与其对应的预制体GameObject
    public Dictionary<string, GameObject> DityprefabMap = new Dictionary<string, GameObject>();

    // 临时对象变量,用于存储实例化后的游戏对象
    GameObject tempobj;

    // 当此脚本所属的游戏对象被唤醒时调用
    private void Awake()
    {
        // 确保MyImageManagerCom有被指定,若未指定,则尝试从该脚本所挂载的游戏对象上获取ARTrackedImageManager组件
        if (MyImageManagerCom == null)
        {
            MyImageManagerCom = this.transform.GetComponent<ARTrackedImageManager>();
        }

        // 初始化字典,将图像名称与预制体关联起来
        // 注意:这里假设MyImagePre列表已经被正确填充了相应的预制体
        DityprefabMap.Add("a", MyImagePre[0]);
        DityprefabMap.Add("b", MyImagePre[1]);
        DityprefabMap.Add("c", MyImagePre[2]);
        DityprefabMap.Add("d", MyImagePre[3]);
        DityprefabMap.Add("e", MyImagePre[4]);
    }

    // 当脚本或其所属的游戏对象变为可用时调用
    private void OnEnable()
    {
        // 绑定ARTrackedImageManager的trackedImagesChanged事件,当跟踪到的图像发生变化时会调用MyImChanged方法
        if (MyImageManagerCom != null)
        {
            MyImageManagerCom.trackedImagesChanged += MyImChanged;
        }
    }

    // 当脚本或其所属的游戏对象变为不可用时调用
    private void OnDisable()
    {
        // 解绑ARTrackedImageManager的trackedImagesChanged事件,防止内存泄漏或在对象不可用时继续接收事件
        if (MyImageManagerCom != null)
        {
            MyImageManagerCom.trackedImagesChanged -= MyImChanged;
        }
    }

    // 自定义事件处理方法,响应ARTrackedImageManager的trackedImagesChanged事件
    private void MyImChanged(ARTrackedImagesChangedEventArgs obj)
    {
        // 输出日志,表明图像跟踪状态已改变
        Debug.Log("追踪的图像发生变化了,调用委托函数");

        // 遍历新增的图像
        foreach (var trackedImage in obj.added)
        {
            // 更新UI显示新增的图像名称
            textdis.text = "新增图像: " + trackedImage.referenceImage.name;

            // 根据图像的名称从字典中获取对应的预制体,并在该图像的位置和旋转状态下实例化
            tempobj = Instantiate(DityprefabMap[trackedImage.referenceImage.name], trackedImage.transform.position, trackedImage.transform.rotation, trackedImage.transform);

            // 更新UI显示已克隆的预制体名称
            textdis2.text = "克隆了对象" + DityprefabMap[trackedImage.referenceImage.name].name;
        }

        // 下面注释掉的部分原本用于处理更新和移除的图像,可以根据需要启用并实现相应逻辑
        // ...
        
        // 遍历移除的图像,这里只是记录了移除的信息,实际操作如销毁相关游戏对象的逻辑可以根据需求添加
        foreach (var trackedImage in obj.removed)
        {
            myString = "移除图像: " + trackedImage.referenceImage.name;
            Debug.Log("移除图像: " + trackedImage.name);
        }
    }
}

下面是一些关于上面代码中核心类和方法的详细解释:

没有调用过ARTrackedImageManager 类下面的相关方法,尤其是 trackedImagesChanged,他是什么意思呢,什么作用? 

trackedImagesChanged 是 ARFoundation 中 ARTrackedImageManager 类的一个事件(可以去复习C#中的委托和事件的使用)。这个事件在图像跟踪状态发生改变时被触发!就会调用这个事件委托的函数(自己定义的)
在程序中如何使用呢?

 trackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;

其中 trackedImageManager 是AR Tracked Image Manager 组件的对应类变量。存储了你场景中的一个AR Tracked Image Manager 组件!

+= OnTrackedImagesChanged;

这个意思是这个  trackedImageManager.trackedImagesChanged ,组件调用了一个委托事件trackedImagesChanged(代表识别的物体有变化,不管是位置、旋转、还是内容都算),一旦有变化我就委托一个函数去执行一个事情。trackedImageManager.trackedImagesChanged+=OnTrackedImagesChanged;

OnTrackedImagesChanged;就是一个自己定义的函数,被委托了!下面是这个函数的标准定义

 private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        //具体事情
    }

函数里面有个形式参数,这个参数是必须带的,就像我让你去办一件事,去把车门打开,我得给你钥匙,这个钥匙就是形式参数 ARTrackedImagesChangedEventArgs eventArgs!

ARTrackedImagesChangedEventArgs eventArgs

ARTrackedImagesChangedEventArgs 是 ARFoundation 提供的一个类,它作为参数传递给 ARTrackedImageManagertrackedImagesChanged 事件处理方法。这个类封装了在图像跟踪状态发生改变时的所有相关信息,包括哪些图像被新增、哪些被更新以及哪些被移除。通过分析 eventArgs 参数,开发者可以得知当前跟踪图像集合的具体变化情况,并据此做出相应的逻辑处理,比如实例化或销毁游戏对象、更新UI、执行特定动画等。

ARTrackedImagesChangedEventArgs 类包含三个主要的属性:

  1. added: 这是一个 NativeArray<ARTrackedImage> 类型的集合,包含了所有新被识别和开始跟踪的图像。每一个 ARTrackedImage 对象代表一个被跟踪的图像,包含了图像的 ID、大小、位置、旋转等信息。

  2. updated: 同样是 NativeArray<ARTrackedImage> 类型,包含了所有已跟踪图像中状态有所更新的图像(比如位置、姿态的微小变动)。开发者可以通过这些信息来实时调整已存在的AR内容,确保与实际跟踪状态同步。

  3. removed: 包含了 NativeArray<ARTrackedImage> 类型的集合,表示那些不再被跟踪的图像,可能是由于图像离开视野、遮挡或是其他原因导致跟踪丢失。对于这些图像,开发者通常需要清理与其关联的任何游戏对象或资源,以避免内存泄漏或视觉混乱。

在实际应用中,通过检查和响应 eventArgs 的这三个集合,开发者可以灵活地管理AR体验中的图像跟踪逻辑,保证应用的动态性和响应性。

完整示例代码:

using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class ImageTrackingEventHandler : MonoBehaviour
{
    public ARTrackedImageManager trackedImageManager;

    void Start()
    {
        // 确保ARTrackedImageManager组件已经附加到了某个游戏对象上
        if (trackedImageManager == null)
        {
            trackedImageManager = GetComponent<ARTrackedImageManager>();
        }

        // 订阅trackedImagesChanged事件
        if (trackedImageManager != null)
        {
            trackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
        }
    }

    // 当跟踪的图像集合发生变化时,此方法会被调用
    private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        // 遍历新增的图像
        foreach (var trackedImage in eventArgs.added)
        {
            Debug.Log("新增图像: " + trackedImage.name);
            // 这里可以添加实例化预设体或其他处理逻辑
        }

        // 遍历更新的图像
        foreach (var trackedImage in eventArgs.updated)
        {
            Debug.Log("更新图像: " + trackedImage.name);
            // 可以在这里根据需要更新图像相关联的游戏对象状态
        }

        // 遍历移除的图像
        foreach (var trackedImage in eventArgs.removed)
        {
            Debug.Log("移除图像: " + trackedImage.name);
            // 这里可以添加销毁相关联游戏对象的逻辑
        }
    }

    void OnDestroy()
    {
        // 当这个脚本被销毁时,取消订阅事件,防止内存泄漏
        if (trackedImageManager != null)
        {
            trackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
        }
    }
}

9. 再来一份代码,实现图像不在被追踪是清除克隆的Image prefab

using UnityEngine; // 引入Unity基本库,提供游戏对象、组件、物理等基础功能
using UnityEngine.XR.ARFoundation; // 引入ARFoundation库,用于AR开发的核心功能
using UnityEngine.XR.ARSubsystems; // 引入AR子系统,提供低级AR支持
using System.Collections.Generic; // 引入通用集合类型,如List、Dictionary等

public class TrackedImageHandler : MonoBehaviour // 定义一个Unity组件类,可以挂载到游戏对象上
{
    public ARTrackedImageManager trackedImageManager; // 公开的ARTrackedImageManager组件引用,用于管理图像跟踪
    public GameObject imagePrefab; // 公开的GameObject预设体,当识别到图像时将克隆这个预设体

    private Dictionary<XRCameraImageId, GameObject> trackedObjects = new Dictionary<TrackableId, GameObject>(); // 私有的字典,用于存储跟踪图像ID与对应实例化游戏对象的关系

    void Start() // Unity生命周期方法,当游戏对象启动时调用
    {
        if (trackedImageManager == null) // 检查是否已经指定了trackedImageManager
        {
            trackedImageManager = FindObjectOfType<ARTrackedImageManager>(); // 如果没有指定,则尝试在场景中自动查找ARTrackedImageManager组件
        }

        if (trackedImageManager != null) // 确保找到了ARTrackedImageManager
        {
            trackedImageManager.trackedImagesChanged += OnTrackedImagesChanged; // 注册事件处理器,当跟踪图像变化时调用OnTrackedImagesChanged方法
        }
        else
        {
            Debug.LogError("ARTrackedImageManager not found in the scene."); // 如果找不到ARTrackedImageManager,打印错误信息
        }
    }

    void OnDestroy() // Unity生命周期方法,在游戏对象被销毁前调用
    {
        if (trackedImageManager != null) // 确保trackedImageManager仍然有效
        {
            trackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged; // 解除事件注册,避免内存泄漏
        }
    }

    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs) // 处理图像跟踪状态变化的事件方法
    {
        foreach (var trackedImage in eventArgs.removed) // 遍历移除的图像
        {
            GameObject trackedObject;
            if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)) // 尝试从字典中获取关联的GameObject
            {
                Destroy(trackedObject); // 销毁关联的GameObject
                trackedObjects.Remove(trackedImage.trackableId); // 从字典中移除该条目
            }
        }

        foreach (var trackedImage in eventArgs.added) // 遍历新增的图像
        {
            if (!trackedObjects.ContainsKey(trackedImage.trackableId)) // 确保这个图像还没有被处理过
            {
                GameObject newObject = Instantiate(imagePrefab, trackedImage.transform.position, trackedImage.transform.rotation); // 实例化预设体,并放置在图像的位置和旋转
                trackedObjects.Add(trackedImage.trackableId, newObject); // 记录新实例化对象与图像ID的关联
            }
        }

        foreach (var trackedImage in eventArgs.updated) // 遍历更新的图像(位置或状态改变)
        {
            GameObject trackedObject;
            if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)) // 获取关联的GameObject
            {
                trackedObject.transform.position = trackedImage.transform.position; // 更新游戏对象的位置
                trackedObject.transform.rotation = trackedImage.transform.rotation; // 更新游戏对象的旋转
            }
        }
    }
}

其他部分读者根据前面的理解应该能看懂!

解释一下其中的 if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)) { Destroy(trackedObject); trackedObjects.Remove(trackedImage.trackableId); }

这段代码的作用是从一个字典(trackedObjects)中查找与特定跟踪图像ID(trackedImage.trackableId)关联的游戏对象,并在找到后进行销毁和从字典中移除的操作。让我逐步解释每一部分:

  1. if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)):

    • TryGetValue 是 Dictionary 类的一个方法,用于尝试从字典中获取与指定键(这里是 trackedImage.trackableId)相关联的值(即游戏对象 GameObject)。
    • 方法有两个参数:键(key,这里是 trackedImage.trackableId)和一个输出参数(out parameter),用于接收查找到的值。如果找到了对应的键值对,这个值会被输出到 out 参数中;如果没有找到,输出参数会被赋予类型的默认值(对于引用类型,如 GameObject,默认值是 null)。
    • 这行代码的意思是尝试从 trackedObjects 字典中查找 trackedImage.trackableId 对应的 GameObject,并将找到的对象赋值给 trackedObject 变量。如果找到,TryGetValue 方法会返回 true,让 if 条件成立,执行后续代码。
  2. Destroy(trackedObject);:

    • 如果 trackedObject 不为 null(即字典中找到了与之关联的游戏对象),Destroy 函数会被调用,用来销毁这个 GameObject 实例。在Unity中,Destroy 方法用于清理游戏对象及其所有的子对象,释放它们占用的资源。
  3. trackedObjects.Remove(trackedImage.trackableId);:

    • 在销毁了游戏对象之后,这行代码从 trackedObjects 字典中移除与 trackedImage.trackableId 关联的条目。这样做是为了保持字典的整洁,避免保留不再使用的键值对,也有助于内存管理。

综上所述,这段代码块旨在处理图像跟踪移除事件,当一个AR跟踪图像不再被识别或跟踪时,它会安全地销毁与该图像关联的任何游戏对象实例,并清理字典中的记录,确保系统资源得到合理释放和管理。

课堂代码示例(重点讲解了委托函数以及事件回调):
 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.Events;

public class ImageARmanager : MonoBehaviour
{
    // 检测用户图片识别的状态,
    public ARTrackedImageManager SMImageARMg;
    public ARFaceManager SMImfACEARMg;
    public GameObject muban;

    public UnityEvent OneUserHanshu;
    
    //public UnityEvent oneCallvbackevent;
   private void OnEnable()
    {
        SMImageARMg.trackedImagesChanged += SMImageARMg_trackedImagesChanged1; ;
        SMImfACEARMg.facesChanged += SMImfACEARMg_facesChanged;
    }

    private void SMImageARMg_trackedImagesChanged1(ARTrackedImagesChangedEventArgs obj)
    {
       
    }

    private void SMImfACEARMg_facesChanged(ARFacesChangedEventArgs obj)
    {
        foreach (var oneImage in obj.added)
        {
            Debug.Log("人脸换了");
            OneUserHanshu.Invoke();
        }
    }

    private void SMImageARMg_trackedImagesChanged(ARTrackedImagesChangedEventArgs obj)
    {

        foreach (var oneImage in obj.added)
        {
            Debug.Log("有新图片进入摄像头");
            GameObject.Instantiate(muban, oneImage.transform.position, oneImage.transform.rotation, oneImage.transform);
            OneUserHanshu.Invoke();
        }
        foreach (var oneImage in obj.removed)
        {
            Debug.Log("有图片离开摄像头");


        }     

    }
    
    private void OnDisable()
    {
        SMImageARMg.trackedImagesChanged -= responsive;//卸载这个委托节省性能
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/698802.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开放式耳机怎么选性价比高?2024五大新晋爆卖机型精选!

​喜欢户外活动的朋友们&#xff0c;你们都是懂得享受生活的达人吧&#xff01;想象一下&#xff0c;在户外活动时&#xff0c;如果能有一副既适合场景又提供超棒音乐体验的耳机&#xff0c;那该多完美啊&#xff01;这时候&#xff0c;开放式耳机就闪亮登场了&#xff01;它的…

小小手表实现全球音视频通话!小寻手表×菊风这样做!

现阶段&#xff0c;儿童手表几乎成了孩子上学的标配&#xff0c;已逐渐发展为家长和孩子沟通的工具与桥梁&#xff0c;而音视频通话也成为了儿童手表中不可或缺的功能。 作为儿童手表市场的领航者&#xff0c;小寻手表在2023年交出了全球出货量第2名、产品覆盖全球1800城市的优…

[图解]建模相关的基础知识-08

1 00:00:01,650 --> 00:00:04,950 如果说&#xff0c;A乘BB乘A的话 2 00:00:06,350 --> 00:00:07,140 意味着什么 3 00:00:07,560 --> 00:00:08,420 A就等于B了 4 00:00:09,500 --> 00:00:10,680 只有两个相等 5 00:00:10,690 --> 00:00:13,360 它们的笛卡尔…

【基于 PyTorch 的 Python 深度学习】8 注意力机制(3):Transformer(下)

前言 文章性质&#xff1a;学习笔记 &#x1f4d6; 学习资料&#xff1a;吴茂贵《 Python 深度学习基于 PyTorch ( 第 2 版 ) 》【ISBN】978-7-111-71880-2 主要内容&#xff1a;根据学习资料撰写的学习笔记&#xff0c;该篇主要介绍了 vision Transformer 和 Swin Transformer…

WeTrade 在印度尼西亚井里汶成功举办研讨会

端午安康!在这欢乐的假日里&#xff0c;WeTrade和各位投资者分享一则喜事!如果有意参加的&#xff0c;可以联系小编! 5 月底&#xff0c;我们在印度尼西亚井里汶成功举办了一场精彩研讨会&#xff0c;聚集了来自印度尼西亚各地交易社区的100多名交易者。 此次研讨会由经验丰富…

互联网政务应用指那些?怎么过等保?

随着互联网技术的快速发展&#xff0c;互联网已经跟大家的生活分不开了&#xff0c;已经成为了大家获取信息交流互动的重要渠道了。因此为了提高用户体验&#xff0c;跟上时代潮流&#xff0c;政府开通了不少互联网政务应用&#xff0c;作为政府服务社会、联系群众的重要窗口。…

从文本文件中读取博客数据并将其提取到文件中

通常情况下我们可以使用 Python 中的文件操作来实现这个任务。下面是一个简单的示例&#xff0c;演示了如何从一个文本文件中读取博客数据&#xff0c;并将其提取到另一个文件中。 假设你的博客数据文件&#xff08;例如 blog_data.txt&#xff09;的格式 1、问题背景 我们需…

3D模型如何快速渲染效果图?

3D模型快速渲染效果图的关键在于优化渲染过程&#xff0c;减少不必要的计算量&#xff0c;并充分利用软件和硬件的性能。那么&#xff0c;3D模型如何实现快速渲染效果图呢? 一、优化模型与材质 1.优化模型文件&#xff1a;尽量减少模型面数&#xff0c;因为模型面数越多&#…

独具魅力的 App UI 风格才能称之为优秀

独具特色的App UI 长什么样&#xff01;看这里

【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版7(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言绘制进度条UI控制关卡进度测试按配置表使用关卡进度变化源码结束语 前言 本节主要实现关卡进度条的功能 绘制进度条UI 控制关卡进度测试 新增ProgressPanel代码&#xff0c;控制关卡进度 public class ProgressPanel : Mon…

(css)el-tabs滚动按钮浮动问题

(css)el-tabs滚动按钮浮动问题 修改前&#xff1a; 修改后&#xff1a; 思路&#xff1a;找到相应元素&#xff0c;降低层级 css写法&#xff1a; ::v-deep .el-tabs__nav {z-index: 1; }

【设计模式】行为型设计模式之 备忘录模式(快照模式)

介绍 备忘录应用场景明确并且有限&#xff0c;一般用来数据的防丢失、撤销和恢复。对大对象的备份和恢复&#xff0c;备忘录模式能有效的节省时间和空间开销。 定义 备忘录模式&#xff1a;也称为快照模式&#xff0c;在不违背封装原则的前提下&#xff0c;捕获一个对象的内…

你必须得认真体验下 TDengine Cloud 了!抢 600 元体验券

你真的了解 TDengine Cloud 吗&#xff1f; 在当今快速演变的数字经济时代&#xff0c;企业面临着前所未有的挑战和机遇。数据量的激增、计算需求的不断增长以及对业务敏捷性的迫切需求&#xff0c;促使企业寻求更加灵活、高效的技术解决方案。云服务由此应运而生&#xff0c;成…

文献解读-农业系列-第七期|《高粱驯化的基因组足迹和多种最终用途的育种选择》

关键词&#xff1a;高粱基因分析&#xff1b;基因组变异检测&#xff1b;全基因组重测序&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;Genomic footprints of sorghum domestication and breeding selection for multiple end uses标题&#xff08;中文…

二叉树左右树交换

leetcode 226题 翻转二叉树 题目描述 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3]…

理解 Bearer Token:什么是它以及如何运作?

在当前数字化时代&#xff0c;网络安全尤为关键。随着技术快速进步&#xff0c;需求日益增长&#xff0c;保障应用程序中用户数据的安全成为开发者们的首要任务。其中&#xff0c;Bearer Token 作为一种高效的验证策略&#xff0c;在防止未授权访问中发挥着不可或缺的作用。 解…

算法005:有效三角形的个数

. - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/valid-triangle-number/ 要组成三角形的三条边&#xff0c;需要保证&am…

沂蒙精神宣讲员尹志林寻访“电台双杰”秦鸿钧贺伯珍烈士故居

临沂信息联播讯&#xff08;张春兄、冯爱云&#xff09; 近日&#xff0c;为了更好的弘扬沂蒙精神、讲好先烈事迹&#xff0c;沂蒙精神宣讲员、《百集学沂蒙党史颂沂蒙精神大讲堂》主讲人、中共临沂市兰山区委宣传部宣讲团成员尹志林一行&#xff0c;专程赶往沂南县辛集镇世和村…

wgcloud可以监测交换机的哪些数据

WGCLOUD可以监测交换机的cpu&#xff0c;内存&#xff0c;温度&#xff0c;电压&#xff0c;磁盘&#xff0c;流量传输速率等数据 WGCLOUD也是基于SNMP协议来监测交换机的

新能源汽车不安全?新能源汽车测试之方案篇——充电桩综合测试

背景 随着全球对气候变化和环境污染问题的日益加剧&#xff0c;新能源汽车作为一种环保、节能的交通工具备受关注。其发展背景主要源于对环境问题的关注以及对传统燃油汽车依赖的减少。新能源汽车的出现&#xff0c;带来了减少尾气排放、节能减排、保护环境等多方面的优点&…