【ARFoundation自学03】平面追踪可视化效果美化

       对已检测到的平面默认的渲染效果显得有些生硬和突兀,有时我们需要更加友好、美观的的平面虚拟界面,这时就需要对已检测到的平面定制个性化的可视方案。为达到更好的视觉效果,处理的思路如下。

视觉效果前后对比!

(本节Shader与ARFeatheredPlaneMesh Visualizer.cs脚本来自Untiy官方AR Foudnation参考代码)

在实现本案例前需要先看第一篇,这篇文章搭建了平面检测的框架!本篇是在此基础上进行的升级!【ARFoundation自学01】搭建AR框架+检测平面+点击克隆立方体到地面=自信入门!_ar foundation教程-CSDN博客

一、 修改材质

(1)隐藏掉系统自带的黑色边框。

(2)重新制作一个渲染材质和Shader脚本

使用带Alpha通道半透明的PNG格式伯纹理,通过Shader脚本渲染这个半透明的纹理,将纹理透明区域镂空。

(3)编写一个渐隐的脚本,让边界的纹理渐隐

为了达到更好的视觉过渡。按照以上思路,我们直接对AR Default Plane预制体进行改造即可。

(1)删除AR Default Plane预制体上的Line Renderer组件。(这个是渲染黑色描边框的组件,删除就意味着不要描边)

(2)编写一个Shader代码,制作一张带Alpha通道半透明PNG格式纹理贴图在外部赋值给这个shader 代码!

Shader "Unlit/FeatheredPlaneShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _TexTintColor("Texture Tint Color", Color) = (1,1,1,1)
        _PlaneColor("Plane Color", Color) = (1,1,1,1)
        _ShortestUVMapping("Shortest UV Mapping Value", Range(0, 1)) = 1.0
    }

    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag   
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 uv2 : TEXCOORD1;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 uv2 : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _TexTintColor;
            fixed4 _PlaneColor;
            float _ShortestUVMapping;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv2 = v.uv2;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv) * _TexTintColor;
                col = lerp(_PlaneColor, col, col.a);    
                col.a *= 1 - smoothstep(1, _ShortestUVMapping, i.uv2.x);
                return col;
            }
            ENDCG
        }
    }
}

这个是一个材质脚本,我们写好以后创建一个普通材质,把脚本直接拖给材质即可!

调一下参数!Unlit/FeatheredPlaneShader的材质进行如下操作:

  • 将在PS里面做好的透明纹理赋值给给_MainTex属性(Texture)。
  • _TexTintColor的Alpha值设置为220,确保十字星的透明部分得以正确显示。
  • _PlaneColor的Alpha值设置为0,使平面背景完全透明。

做好的材质赋值给平面预制体AR Default Plane

上面基本完成了可视化平面的视觉效果更换!但是还可以进一步优化,让边缘平滑渐隐! 

2.创建一个普通C#脚本-边缘平滑渐隐

该脚本主要实现平面的渲染,并处理边界使其平滑渐隐。将AR Feathered Plane Mesh Visualizer挂载到AR Default Plane预制体上!

完成之后的预制体组件脚本应该如图3-5所示。编译运行,找一个富纹理平面进行平面检测,效果如图3-6所示。相比AR Foundation自带的平面可视化,个性化后的渲染视觉效果要好很多,而且在平面边界处也有一个渐隐的平滑过渡。

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

[RequireComponent(typeof(ARPlaneMeshVisualizer), typeof(MeshRenderer), typeof(ARPlane))]
public class ARFeatheredPlaneMeshVisualizer : MonoBehaviour
{
    [Tooltip("The width of the texture feathering (in world units).")]
    [SerializeField] float m_FeatheringWidth = 0.2f;
    public float featheringWidth
    {
        get { return m_FeatheringWidth; }
        set { m_FeatheringWidth = value; }
    }

    private ARPlaneMeshVisualizer m_PlaneMeshVisualizer;
    private ARPlane m_Plane;
    private MeshRenderer m_Renderer;
    private Material m_FeatheredPlaneMaterial;

    void Awake()
    {
        m_PlaneMeshVisualizer = GetComponent<ARPlaneMeshVisualizer>();
        m_Renderer = GetComponent<MeshRenderer>();
        m_FeatheredPlaneMaterial = m_Renderer.material;
        m_Plane = GetComponent<ARPlane>();
    }

    void OnEnable()
    {
        m_Plane.boundaryChanged += ARPlane_boundaryUpdated;
    }

    void OnDisable()
    {
        m_Plane.boundaryChanged -= ARPlane_boundaryUpdated;
    }

    void ARPlane_boundaryUpdated(ARPlaneBoundaryChangedEventArgs eventArgs)
    {
        GenerateBoundaryUVs(m_PlaneMeshVisualizer.mesh);
    }

    void GenerateBoundaryUVs(Mesh mesh)
    {
        int vertexCount = mesh.vertexCount;
        if (s_FeatheringUVs.Capacity < vertexCount) { s_FeatheringUVs.Capacity = vertexCount; }

        mesh.GetVertices(s_Vertices);

        Vector3 centerInPlaneSpace = Vector3.zero;
        for (int i = 0; i < vertexCount; i++)
        {
            centerInPlaneSpace += s_Vertices[i];
        }
        centerInPlaneSpace /= vertexCount;

        float shortestUVMapping = float.MaxValue;

        for (int i = 0; i < vertexCount; i++)
        {
            float vertexDist = Vector3.Distance(s_Vertices[i], centerInPlaneSpace);
            float uvMapping = vertexDist / Mathf.Max(vertexDist - featheringWidth, 0.001f);
            if (shortestUVMapping > uvMapping) { shortestUVMapping = uvMapping; }

            s_FeatheringUVs.Add(new Vector3(uvMapping, 0, 0));
        }

        m_FeatheredPlaneMaterial.SetFloat("_ShortestUVMapping", shortestUVMapping);

        mesh.SetUVs(1, s_FeatheringUVs);
        mesh.UploadMeshData(false);
    }

    static List<Vector3> s_FeatheringUVs = new List<Vector3>();
    static List<Vector3> s_Vertices = new List<Vector3>();
}

这是一个Unity C#脚本,名为`ARFeatheredPlaneMeshVisualizer`,用于为ARFoundation框架中的ARPlane对象添加一种特殊的视觉效果:根据平面边缘与中心的距离,为平面的顶点生成渐变的UV映射,从而实现类似羽毛边缘的过渡效果。该脚本依赖`ARPlaneMeshVisualizer`、`MeshRenderer`和`ARPlane`组件,并且通过响应ARPlane的边界变化事件来实时更新UV映射。下面为您详细解释脚本各部分的功能:

1. **命名空间和引用**:

   using System.Collections.Generic;
   using UnityEngine;
   using UnityEngine.XR.ARFoundation;
   ```
   引入所需命名空间,包括泛型集合、Unity基础类库以及ARFoundation相关API。

2. **类定义**:

   [RequireComponent(typeof(ARPlaneMeshVisualizer), typeof(MeshRenderer), typeof(ARPlane))]
   public class ARFeatheredPlaneMeshVisualizer : MonoBehaviour
   ```
   定义一个公共类`ARFeatheredPlaneMeshVisualizer`,继承自`MonoBehaviour`,并使用`[RequireComponent]`特性确保附着此脚本的游戏对象必须同时具有`ARPlaneMeshVisualizer`、`MeshRenderer`和`ARPlane`组件。

3. **属性定义**:

   [Tooltip("The width of the texture feathering (in world units).")]
   [SerializeField] float m_FeatheringWidth = 0.2f;
   public float FeatheringWidth
   {
       get { return m_FeatheringWidth; }
       set { m_FeatheringWidth = value; }
   }

   定义一个具有工具提示的私有变量`m_FeatheringWidth`,默认值为0.2f。使用`[SerializeField]`使其能在Unity Inspector面板中显示并编辑。同时提供一个公开的只读属性`FeatheringWidth`,用于外部访问和修改该值。`FeatheringWidth`决定了纹理边缘渐变过渡的宽度(以世界单位计)。

4. **成员变量**:

   private ARPlaneMeshVisualizer m_PlaneMeshVisualizer;
   private ARPlane m_Plane;
   private MeshRenderer m_Renderer;
   private Material m_FeatheredPlaneMaterial;
   ```
   定义私有变量,分别存储`ARPlaneMeshVisualizer`、`ARPlane`、`MeshRenderer`组件的引用以及关联的`Material`对象。

5. **Awake()**:

   void Awake()
   {
       m_PlaneMeshVisualizer = GetComponent<ARPlaneMeshVisualizer>();
       m_Renderer = GetComponent<MeshRenderer>();
       m_FeatheredPlaneMaterial = m_Renderer.material;
       m_Plane = GetComponent<ARPlane>();
   }
   `Awake()`方法在游戏对象初始化阶段调用,用于获取并存储所需组件的引用。

6. **生命周期方法**:

   void OnEnable()
   {
       m_Plane.boundaryChanged += ARPlane_boundaryUpdated;
   }

   void OnDisable()
   {
       m_Plane.boundaryChanged -= ARPlane_boundaryUpdated;
   }
   ```
   当组件启用时,注册`ARPlane.boundaryChanged`事件的处理函数`ARPlane_boundaryUpdated`。当组件禁用时,取消注册该事件,以避免内存泄漏和不必要的性能开销。

7. **ARPlane_boundaryUpdated()**:
   ```csharp
   void ARPlane_boundaryUpdated(ARPlaneBoundaryChangedEventArgs eventArgs)
   {
       GenerateBoundaryUVs(m_PlaneMeshVisualizer.mesh);
   }
   ```
   事件处理函数,当ARPlane的边界发生变化时调用。在此调用`GenerateBoundaryUVs`方法,传入`ARPlaneMeshVisualizer`组件提供的`Mesh`对象,以更新其UV映射。

8. **GenerateBoundaryUVs()**:
   ```csharp
   void GenerateBoundaryUVs(Mesh mesh)
   {
       // ... (详细解释见下文)
   }
   ```
   主要功能方法,负责计算并设置Mesh顶点的UV映射以实现羽毛边缘效果。下面详细解释内部逻辑:

   - 获取顶点数量和检查`s_FeatheringUVs`容量。
   - 使用`mesh.GetVertices`获取所有顶点坐标并存储在`s_Vertices`列表中。
   - 计算顶点集的中心点(质心)。
   - 初始化`shortestUVMapping`为最大浮点数,用于记录最小UV映射值。
   - 遍历每个顶点,计算其与中心点的距离(`vertexDist`),并据此计算UV映射值(`uvMapping`)。
     - UV映射值通过`vertexDist`与`featheringWidth`之差(取最大值为0.001f避免除以零)的比值得到,距离越远,UV映射值越大。
     - 如果当前UV映射值小于已记录的最小值,则更新`shortestUVMapping`。
   - 将计算得到的UV映射值(仅包含x分量,y和z设为0)添加到`s_FeatheringUVs`列表。
   - 将计算得到的最小UV映射值(`shortestUVMapping`)设置到材质的`_ShortestUVMapping`属性。
   - 使用`mesh.SetUVs`方法将`s_FeatheringUVs`列表中的UV映射值设置到Mesh的第二个UV通道(索引为1)。
   - 调用`mesh.UploadMeshData(false)`更新Mesh数据到GPU,完成UV映射设置。

9. **静态列表**:
   ```csharp
   static List<Vector3> s_FeatheringUVs = new List<Vector3>();
   static List<Vector3> s_Vertices = new List<Vector3>();
   ```
   定义两个静态列表,分别用于暂存计算得到的UV映射值和临时存储Mesh顶点坐标。

总结:`ARFeatheredPlaneMeshVisualizer`脚本为ARFoundation中的ARPlane添加了一种基于顶点距离的UV映射渐变效果,实现了类似羽毛边缘的过渡视觉效果。它监听ARPlane边界变化事件,动态更新Mesh的UV映射,确保在AR环境变化时能实时反映到渲染结果中。

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

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

相关文章

Android Compose 七:常用组件 Image

1 基本使用 Image(painter painterResource(id R.drawable.ic_wang_lufei), contentDescription "" ) // 图片Spacer(modifier Modifier.height(20.dp))Image(imageVector ImageVector.vectorResource(id R.drawable.ic_android_black_24dp), contentDescript…

Nature 正刊!瑞典于默奥大学研究团队在研究全球河流和溪流的甲烷排放中取得新进展

甲烷(CH4)是一种强有力的温室气体&#xff0c;自工业革命以来&#xff0c;其在大气中的浓度增加了两倍。有证据表明&#xff0c;全球变暖增加了淡水生态系统的 CH4 排放&#xff0c;为全球气候提供了积极的反馈。然而&#xff0c;对于河流和溪流来说&#xff0c;甲烷排放的控制…

618有什么宠物空气净化器推荐?希喂FreAir Lite宠物空气净化器真实体验

一、宠物空气净化器的必要性 掉毛季又来了&#xff0c;猫咪的毛发满天飞&#xff0c;怎么办&#xff1f;我家里的猫咪一到换毛季就掉满地的毛发&#xff0c;尤其喜欢在家里奔跑打闹&#xff0c;结果整个房间都是毛。为了减少家里空气中的浮毛&#xff0c;你都做过哪些努力呢&a…

电脑出现:excel词典(xllex.dll)文件丢失或损坏的错误提示怎么办?有效的将丢失的xllex.dll修复

当遇到 Excel 提示“词典 (xllex.dll) 文件丢失或损坏”的问题时&#xff0c;通常意味着该动态链接库文件&#xff08;Dynamic Link Library&#xff0c;DLL&#xff09;&#xff0c;它与拼写检查功能相关联的&#xff0c;无法被正确找到或者合适地使用。那么有什么办法可以解决…

空间转录组数据的意义

10X空间转录组Visium学习笔记&#xff08;三&#xff09;跑通Visium全流程记录 | 码农家园 (codenong.com) 这两个的区别是&#xff1a;一个是像素的位置信息&#xff0c;一个是阵列的位置信息

第97天:权限提升-Web 权限权限划分源码后台中间件第三方数据库等

前置知识 具体有哪些权限需要我们了解掌握的 后台权限&#xff0c;网站权限&#xff0c;数据库权限&#xff0c;接口权限&#xff0c;系统权限&#xff0c;域控权限等 以上常见权限获取方法简要归类说明 后台权限&#xff1a;SQL 注入,数据库备份泄露&#xff0c;默认或弱口…

设计模型-系统架构师(三)

1、按照《中华人民共和国著作权法》的权利保护期&#xff0c;署名权和修改权 是永久保护的。 发表权、使用权和获取报酬权 保护期限 作者终生和死后的50年。 2、&#xff08;重要&#xff09;面向对象的分析模型主要由 顶层架构图、用例与用例图和&#xff08;&#xff09;构成…

CTF网络安全大赛简单的web抓包题目:HEADache

题目来源于&#xff1a;bugku 题目难度&#xff1a;简单 题目 描  述: > Wanna learn about some types of headache? > Lets dig right into it! 下面是题目源代码&#xff1a; <!DOCTYPE html> <html> <head><meta charset"utf-8"&…

基于C#开发web网页管理系统模板流程-主界面管理员入库和出库功能完善

前言 紧接上篇->基于C#开发web网页管理系统模板流程-主界面管理员录入和编辑功能完善-CSDN博客 本篇将完善主界面的管理员入库和出库功能&#xff0c;同样的&#xff0c;管理员入库和出库的设计套路适用于动态表的录入和编辑 首先还是介绍一下本项目将要实现的功能 &#xf…

对象解构与迭代器的猫腻?

前言 变量的解构赋值是前端开发中经常用到的一个技巧&#xff0c;比如&#xff1a; // 对象解构 const obj { a: 1, b: 2 }; const { a, b } obj; console.log(a, b)数组解构 const arr [1, 2, 3]; const [a, b] arr; console.log(a, b)工作中我们最经常用的就是类似上面…

【Python安全攻防】【网络安全】一、常见被动信息搜集手段

一、IP查询 原理&#xff1a;通过目标URL查询目标的IP地址。 所需库&#xff1a;socket Python代码示例&#xff1a; import socketip socket.gethostbyname(www.163.com) print(ip)上述代码中&#xff0c;使用gethostbyname函数。该函数位于Python内置的socket库中&#xf…

②单细胞学习-组间及样本细胞比例分析

目录 数据读入 每个样本各细胞比例 两个组间细胞比例 亚组间细胞比例差异分析&#xff08;循环&#xff09; 单个细胞类型亚新间比例差异 ①单细胞学习-数据读取、降维和分群-CSDN博客 比较各个样本间的各类细胞比例或者亚组之间的细胞比例差异 ①数据读入 #各样本细胞…

ubuntu-24.04系统静态Mac和IP配置

操作系统版本&#xff08;桌面版&#xff09;&#xff1a;ubuntu-24.04-desktop-amd64.iso 原因说明&#xff1a;因网络的IP地址和Mac是预分配的&#xff0c;所以ubuntu系统需要修改网卡的mac地址和IP才能访问&#xff0c;网络查了半天资料都没成功&#xff0c;后再界面提示&a…

vue2 案例入门

vue2 案例入门 1 vue环境2 案例2.1 1.v-text v-html2.2 v-bind2.3 v-model2.4 v-on2.5 v-for2.6 v-if和v-show2.7 v-else和v-else-if2.8 计算属性和侦听器2.9 过滤器2.10 组件化2.11 生命周期2.12 使用vue脚手架2.13 引入ElementUI2.13.1 npm方式安装2.13.2 main.js导入element…

BIGO前端CICD平台

本文首发于&#xff1a;https://github.com/bigo-frontend/blog/ 欢迎关注、转载。 我是谁 BIGO前端CICD平台&#xff0c;是一个服务于前端团队的全研发周期管理平台&#xff0c;已经是我们团队日常都要使用的工具了。 该平台实现了一键创建项目、发布编排、新建迭代、checkl…

互联网应用主流框架整合之数据库事务管理

在互联网系统中同时运行着成千上百个线程是十分常见的事情&#xff0c;尤其当一个热门出现时&#xff0c;用户几乎同时打开手机、电脑、平板灯设备进行访问&#xff0c;这样就会导致数据库处在一个多事务访问的环境中&#xff0c;从而引发数据丢失或者数据不一致的现象&#xf…

Java GC问题排查的一些个人总结和问题复盘

个人博客 Java GC问题排查的一些个人总结和问题复盘 | iwts’s blog 是否存在GC问题判断指标 有的比较明显&#xff0c;比如发布上线后内存直接就起飞了&#xff0c;这种也是比较好排查的&#xff0c;也是最多的。如果单纯从优化角度&#xff0c;看当前应用是否需要优化&…

Mowgli用于配对多组学整合

对同一组细胞的多个分子层进行分析逐渐流行。越来越需要能够联合分析这些数据的多视图学习方法。Mowgli是一种支持配对多组学数据的整合方法。值得注意的是&#xff0c;Mowgli将非负矩阵分解和最优传输相结合&#xff0c;同时提高了非负矩阵分解的聚类性能和可解释性。作者将Mo…

解锁数据的力量:Navicat 17 新特性和亮点

解锁数据的力量&#xff1a;Navicat 17 新特性和亮点 大家好&#xff0c;我是猫头虎。今天我要为大家介绍 Navicat 17 的新特性和亮点。Navicat 是一款专业的数据库管理工具&#xff0c;支持多种数据库类型&#xff0c;包括 MySQL、Oracle、SQL Server、PostgreSQL、MariaDB、…

5月28号总结

刷题记录 1.A. Phone Desktop 输入&#xff1a; 11 1 1 7 2 12 4 0 3 1 0 8 1 0 0 2 0 15 0 8 2 0 9 输出&#xff1a; 1 1 2 2 1 1 0 1 1 2 5 题意&#xff1a;题目给我们1x1和2x2的图标个数&#xff0c;让我们求最少需要多少个5x3的屏幕。 思路&#xff1a;当只看2x2的图…