在VR下面,曲面UI可以提升用户在场景中的沉浸感,获得更好的视觉体验

方案选择

做一套基于曲面的UI

我们项目中基本只用到Image和Text两种,Image是比较好处理的,直接将Texture贴到一个曲面的mesh上就可以了,但是Text相对比较麻烦。我们无法简单的取到某一段文字的Texture,必须自己从字体文件里面裁剪每个文字的Texture,然后拼接到一个Texture,然后再将最终的纹理贴到一个曲面mesh上。

单独将平面UI渲染到一个纹理,然后贴到曲面mesh上

这个方案在实现曲面化上是没有问题的,但是为了满足VR下面的立体效果,我们两只眼睛看到的东西是有一定差异的,通过这些差异才有立体感,如果是同一个曲面的UI Texture,UI上的一些立体效果会损失(比如UI向前浮动)。另外,如果使用这种方法,我们眼睛看到的UI和真实的UI有很大的差异,需要重新设计凝视输入。

让UI沿着曲面分布,且每个UI元素有曲面效果

让UI沿着曲面分布是比较好实现的,只需要计算合理的位置和角度,让UI整体上呈现出曲面的效果。目前有很多VR的曲面效果都是采用这种简单的方法实现的,但是这种方案实现的曲面效果并不是很好,是一种假曲面化的效果。如下图所示,在上下边缘可以看到很明显的直线。UI元素沿着曲面分布

所以在沿着曲面分布的前提下,如果每个”UI元素都有曲面效果“,那么整体上才会看出曲面效果。如下图所示

UI元素都有曲面效果

结合实现难度和效果,我们选择了方案 3。

曲面化中的数学原理

无论是让UI沿着曲面分布,还是实现每个UI自身的曲面效果,实质上都是做同一种数学运算——计算平面上的点映射到曲面上的坐标。

由于我们曲面化是一个圆柱面,圆柱轴心线与Y轴平行,变化前后Y轴坐标是一样的,下面是原理:掘金不支持数学公式

几何示意图

其中的关键点是变换前后的长度对应关系和弧长与半径的比是角度。上面给出的过程是一种特殊情况,实际过程中会有些变化,比如圆心不在原点,但是都是可以通过以上的方法推导出来结果。

曲面化

让UI沿着曲面分布

对每个UI计算曲面化之后的坐标,上面已经给出了计算方法,需要注意的是,计算玩坐标之后还需要调整UI的角度,让UI的前方是圆心到变换之后坐标的方向。比如上面变换之后位于B点的UItransform.forward = transform.position.normalized。

到了这一步,整体的UI就有了上面所说的假曲面化的效果。

每个UI元素的曲面效果

Unity提供了BaseMeshEffect对UI元素生成的mesh做一些修改来实现一些效果,不同Unity版本这个API有些差异,这里用到的是Unity5.3.4,主要是重写ModifyMesh(VertexHelper vh)方法。

在ModifyMesh方法主要内容:

public override void ModifyMesh(VertexHelper vh){

base.ModifyMesh(vh);

if (!this.IsActive() || !bendEnable)

return;

/*

检查是否需要重新生成或修改顶点坐标,如果不需要,则使用已经缓存的顶点坐标

*/

if (cachedVertices == null || cachedTriangles == null || verticesDirty)

{

// 需要修改顶点,首先将Unity生成的顶点取出来

List originUIVertices = new List();

vh.GetUIVertexStream(originUIVertices);

/*

对顶点做一些变换,包括增加顶点以及重新计算顶点坐标,对于Image和Text有不同的处理方式

*/

}

// 如果材质改变,重新给定点着色

if (materialDirty)

{

UpdateVertiecsColor(cachedVertices);

materialDirty = false;

}

// 清除Unity生成的顶点,将我们重新计算的顶点设置到mesh上

vh.Clear();

vh.AddUIVertexStream(cachedVertices, cachedTriangles);

// 根据生成顶点的类型也可以使用vh.AddUIVertexTriangleStream(cachedVertices)设置顶点

}复制代码

1. 检查顶点是否需要更新

当Unity发现UI需要更新的时候会调用ModifyMesh(VertexHelper vh),Unity自己触发UI更新的条件有尺寸改变和材质改变,我们也可以使用Graphic.SetAllDirty() Graphic.SetVerticesDirty() 触发。但是并非所有的情况下都需要重新计算顶点坐标,当我们计算出一个UI的曲面状态下的顶点之后,很少需要重新计算,我们只在UI尺寸改变的情况下才触发重新计算顶点,当然可以根据实际使用情况调整策略。顶点计算比较耗时,建议先判断在计算。

2. 取出顶点

取出来的顶点是一个UIVertex的列表,一般情况下,列表中每3个构成一个三角形,如果改变列表中元素的位置,会导致UI显示异常,所以最后输出给VertexHelper的顶点也是有顺序的。

3. 顶点计算

这一步中对于Text和Image有较大差异,主要原因在于一般的Text自己都有足够多且细分的三角形,只需要重新计算顶点的坐标就可以有很好的曲面效果,但是一般情况下,Image只有两个三角形(Sliced模式下Tiled模式会多一些,但是依然不够细分),四个顶点,对四个顶点重新计算之后依然是一个平面的效果,所以需要考虑给Image的mesh添加一些顶点,让Image上的三角形足够细分。

对于Text的处理

cachedVertices = new List();

vh.GetUIVertexStream(cachedVertices);

BendMeshCylinder(cachedVertices);复制代码

其中的BendMeshCylinder(cachedVertices)函数就是将传入的顶点变换到圆柱曲面上,需要注意的是UIVertex里面的坐标是相对UI自身的局部坐标。处理过程不改变UIVertex列表的顺序,处理完的依然保持之前的三角形顺序,所以最后直接使用vh.AddUIVertexTriangleStream(cachedVertices)设置顶点。

对于Image的处理

一般情况下的Image只需要4个顶点就可以构成两个三角形,但是从VertexHelper里面取出来的顶点有6个,每三个构成一个三角形,重复使用了其中的两个顶点,如下图所示,第0,1,2和3,4,5分别构成一个三角形,0和5为同一个顶点,2和3为同一个顶点。

最初的想法是忽略Unity自己生成的顶点,直接在代码中根据原始顶点的规律生成一个足够细分的mesh,然后对所有顶点采用和Text里面相同的计算就可以有曲面效果,如下图所示,因为我们只需要圆柱曲面效果,所以在Y轴方向不需要细分,这样能大大减少三角形的数量。

这种方案一般情况下是够用的,但是当遇到Sliced或者Tiled模式的Image的时候就会有问题:当我们计算新增顶点坐标的时候,需要给顶点指定一个uv值,这个值将决定图片渲染在这一点的uv,普通图片的uv值是从0到1的均匀分布,所以直接根据新计算的坐标在整个Image上的位置就知道uv值,但是Sliced和Tiled的uv不是0到1的均匀分布,根据坐标是无法直接算出uv值的。比如下图是一个Sliced模式的mesh,编号为1的顶点Y轴上是整个Image高度的0.1,但是uv中v(Y轴)的值使0.3,如果我们忽略这些值,直接生成均匀分布的点,Sliced的特性就没有了

所以需要在保持Unity计算出来的顶点,然后再在这些顶点的基础上进行线性插值计算新增的顶点。代码如下:

List originUIVertices = new List();

vh.GetUIVertexStream(originUIVertices);

TrisToQuads(originUIVertices);

for (int i = 0; i < originUIVertices.Count; i += 4)

{

CreateQuads(originUIVertices, i, cachedVertices, cachedTriangles);

}

BendMeshCylinder(cachedVertices);复制代码

首先在TrisToQuads(originUIVertices)里面是将每六个顶点构成的两个三角形合并为四个顶点构成的四边形,然后在CreateQuads(originUIVertices, i, cachedVertices, cachedTriangles)里面对每个四边形内部进行线性插值计算新增顶点,每个四边形内部点的uv都可以根据坐标在四边形内部的位置计算出来。如下图所示,红色点为新增顶点,当四边形在X轴方向足够细分,就不需要再添加顶点,通常情况下Sliced模式的图片边缘是足够细分的。

我们发现,四个顶点就足以描述两个三角形,但是需要知道两个三角形与四个顶点的对应关系,三角形更多的情况下可以通过顶点的复用使得顶点数量更少,比如上图中有36个三角形,但是只有28个顶点,我们需要缓存曲面变化之后的顶点,避免后面的重复计算,所以采用顶点复用可以让我们缓存的顶点数量大大的减少,但是我们需要缓存一个顶点与构成的三角形的对应关系的int列表,这个列表中每三个数描述一个三角形,数值对应着缓存的顶点列表的索引。顶点生成完成之后,和Text中一样对顶点的坐标进行曲面变换。最后我们设置顶点的时候需要告诉VertexHelper顶点与三角形的对应关系,vh.AddUIVertexStream(cachedVertices, cachedTriangles)。

4. 改变顶点的颜色

如果改变UI的颜色属性,会触发MaterialDirty,我们可以通过Graphic.RegisterDirtyMaterialCallback监听这个改变,然后在ModifyMesh()改变顶点的颜色。另外不建议监听Graphic.RegisterDirtyVerticesCallback来确定是否需要重新计算顶点,因为改变顶点颜色,这个回调也会调用。

曲面化的原理如上,如果要真正运用起来,还需要配合一个Editor。需要注意的是,最好不要在曲面化状态调整UI的坐标和角度,不仅很难调整到想要的位置,而且会影响整体曲面化的效果。

文章里面主要聚焦圆柱面,如果是球面,主要要修改UI坐标的计算方法,和Image三角形细化方法,如果是其他更复杂的曲面,不太建议用这种方式处理,因为涉及到曲面的数据计算,效果也很难保证。

mesh渲染到ui_Unity中UI曲面化相关推荐

  1. UI设计培训中的扁平化理念

    本文是为正在学习UI设计的同学们整理的一份资料,主要讲的是UI设计培训中的扁平化理念,扁平化的设计是抛弃一切装饰的设计,扁平化设计使得用户操作起来更加简洁.高效和舒适.简洁大方的交互界面设计自然能够引 ...

  2. Android N中UI硬件渲染(hwui)的HWUI_NEW_OPS(基于Android 7.1)

    原文地址:http://blog.csdn.net/jinzhuojun/article/details/54234354 背景 UI作为用户体验的核心之一,始终是Android每次升级中的重点.从A ...

  3. Unity VR开发中UI始终优先渲染不被物体遮挡

    Unity VR开发中UI始终优先渲染不被物体遮挡 在用Vive开发VR的时候,3DUI很容易被场景中的物体遮挡,解决办法是使用一个Shader:Overlay.shader,这个shader很好找, ...

  4. javascript --- 函数的柯里化 Vue 2.x中柯里化的使用

    函数式编程部分重点 参考资料: 函数式编程 柯里化 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数 var add = function (x) {return function(y ...

  5. 谈谈Hybird3D中的光栅化优化

    看到空明流转分享了他的SALVIA 0.5.2优化谈,我也来说说Hybird3D中和光栅化相关的一些优化技术. Hybird3D的设计目标是打造一款准实时的软件高质量渲染器,采用了光栅化和光线跟踪混合 ...

  6. XCoreRedux框架:Android UI组件化与Redux实践

    XCoreRedux框架:Android UI组件化与Redux实践 @author: 莫川 https://github.com/nuptboyzhb/ XCoreRedux源码+Demo:http ...

  7. Unity PointCloud开发:Mesh渲染点云

    因任务需求,需要实现Unity中点云的渲染,同时将点云与模型相结合,达到点云在模型上特定位置的绑定.经相关探索,特此记录. 前言 在Unity中实现点云的渲染可以采用相关的插件,例如PCX插件,可以直 ...

  8. 云宏WinCloud前端工程师告诉你什么是UI扁平化

    初见"UI扁平化"这个词也许很多人会觉得陌生,但在今天UI扁平化其实一点也不神秘,因为UI扁平化在我们的生活中随处可见.拿我们现在最常用的智能手机为例,智能手机的操作系统,手机里的 ...

  9. 在Unity中实现体素化

    在Unity中实现体素化 博客链接:在Unity中实现体素化 体素化 类似与用网格存储二维平面,将三维空间划分成大量尺寸相同的小方块的过程就称之为体素化. 为什么要体素化 以下是个人理解 当场景中多边 ...

最新文章

  1. 深入剖析 RocketMQ 源码 - 消息存储模块
  2. 数字电视接口(HDMI,DVI)
  3. strftime和strptime使用
  4. php 网页内容下载,php实现当前页面点击下载文件的简单方法
  5. 使用 TensorFlow 的公司
  6. linux创建用户,并修改分组,改变权限
  7. 中国微型计算机分省市产量数据统计,2017年6月中国微型计算机设备产量统计数据分析...
  8. 华为新系统鸿蒙能互通吗,「连接」万物的鸿蒙,能拯救华为手机吗?
  9. 智能文档分析:NLP和OCR的融合技术
  10. 妙啊,小米11保护壳先小米11一步上市了...
  11. wps xml转换表格_wps手机版下载-WPS Office 安卓版v12.9.2
  12. Win11怎么卸载软件?Win11彻底卸载软件教程
  13. 2.4.1 ALU-串行加法器和并行加法器
  14. JavaScript数组求和
  15. 腾讯消消乐 状压dp加普通dp
  16. 《Microduino实战》——1.4 开源硬件
  17. 通过JSP网页连接MySQL数据库,从MySQL数据库中读出一张表并显示在JSP网页中
  18. [紫书CH0] 《算法竞赛入门经典》(第2版) 题解目录
  19. php学生管理系统视频教程,学生管理系统——PHP
  20. python学习笔记8

热门文章

  1. 哪些动物拥有惊人的数学天赋?
  2. Java(学习笔记三,kk自用)
  3. hBuilder调试
  4. Golang中defer的执行时机
  5. 学会Pr剪辑培训,兼职竟比主业还高?
  6. 复杂网络之社区发现算法
  7. 如何练习插画?插画应该如何构图?
  8. Tello无人机版之使用Scratch2和ROS进行机器人图形化编程学习
  9. k8s+Jenkins+GitLab-自动化部署tomcat项目
  10. 为什么特斯拉Q2业绩能超预期?