Unity原生渲染方案
Unity原生渲染方案
作者:3dimensions
three_dimensions@live.cn
本文为原创内容,转载请注明出处。
做这个的动机是想在原生代码中使用Unity的材质系统绘制,同时由原生代码提供绘制数据,省掉Unity内部的分配内存及数据转换,以及动态模型数据“非托管内存→ 托管内存→ 非托管内存”的传输过程。适用于有大量动态模型数据生成的情况,测试结果在PC和移动平台上均有数倍的性能提升。注意,如果不使用Unity的材质系统,并不需要按这个方案做。方案是我在Miloyip的建议下完成的。
一、目标
在Unity中,动态生成三维模型需要把数据填入Mesh对象中,当中Unity内部需要分配内存及做数据转换,效率不佳。而且如果要编写Unity原生插件去生成三维模型,模型数据需要 经“非托管内存→ 托管内存→ 非托管内存”的传输过程,浪费很多内存频宽及时间,特别是每 帧都需要更新的串流数据。所以,我们希望能绕过这数据传输过程,直接进行原生渲染。本文总结的原生渲染方案,目标是令原生插件继续使用Unity的材质系统,然后在插件内生成顶点数据并提交Draw-call。
二、方案
大致的想法是希望让Unity设置好OpenGL绘制状态后,在原生插件中获取这些状态并 加以利用。此方案暂不考虑多线程渲染及多步骤材质(Multi-pass material),并针对Open GL (Windows)及OpenGL ES(iOS和Android)进行测试。
2.1 进入原生渲染的时机──选项A:GL.IssuePluginEvent
首先我们考虑使用Unity的GL.IssuePluginEvent,但这个方法还存在问题,在PC上测试 的结果显示,通过GL.IssuePluginEvent进入原生渲染后,一些绘制资源(如纹理)已经被解 绑,Unity中设置好的绘制状态被破坏了。所以此方案不可行。
2.2 进入原生渲染的时机──选项B:直接调用原生API
另一个方法是在Unity脚本中先设置好材质,然后直接调用原生插件。首先,在Unity中调 用Material.SetPass()设置材质,但这个命令并不一定会被Unity立即执行,此时若直接进入 原生渲染,可能会发现绘制状态不正确。我们找到一个可行的方法是,在调用SetPass()后紧 随执行DrawMeshNow()去绘制一个小网格,此时整个OpenGL的绘制状态已经被正确设置,然 后才调用原生插件,在原生渲染器中查询到的绘制状态,便是相应材质对应的正确绘制状态。
2.3 如何在Native plugin中利用Unity的绘制状态
如何利用Unity设置好的绘制状态,对于PC和Android有一些区别:
- 在PC上,Unity进入原生渲染之后,查询到的当前着色器名字为0,但这并不意味着绘制 状态被破坏,仍然可以绘制出正确的结果。我们怀疑DrawMeshNow()选择了设置材质到固 定管线,在PC原生渲染中只能利用这一固定管线。OpenGL固定管线的顶点属性是有语 义的,在原生渲染中调用gl*Pointer接口提供顶点数据就可以提交draw-call。
- 在Android上,OpenGL ES 2.0以上版本只能使用可编程管线,且移除了顶点属性的语义, 所有顶点属性变成了Generic。为了给当前绘制状态提供顶点数据,需要在原生渲染器中 查询当前着色器名称,并解析着色器的接口信息。Unity对顶点属性有比较固定的命名格 式,可以根据这些属性字符串从当前着色器中查询到Location信息。在原生渲染器中调 用glVertexAttribPointer提供顶点数据到相应Location,然后再提交Draw-call。
2.4 参与Unity的视锥裁剪
为了使原生渲染器正确的参与视锥裁剪,我们需要在原生渲染器的GameObject设置和原生 几何体相同的包围盒。 具体方法为如下。首先,在挂载原生渲染器的GameObject上关联Renderer及MeshFilter。 然后,在MonoBehaviour.Update()时,从原生渲染器中读取原生几何体的包围盒,再把一个 拥有相同包围盒的Mesh设置到这个GameObject的MeshRenderer,然后Mesh重新计算包围盒引 发MeshRenderer重新计算包围盒。最后,在OnWillRenderObject()时,记录GameObject是否 通过了视锥裁剪。而在OnRenderObject()时,根据是否通过了裁剪来决定是否调用原生渲染 器.
2.5 多个摄像机及多个原生调用
我们测试了多个摄像机的情况,以及在Material.SetPass()后紧随多次原生调用的情况, 原生渲染器均能正确绘制。
2.6 绘制次序
原生渲染器的绘制次序通过Unity的层(Layer)控制,原生渲染器对应不同于场景其他物 体的Layer,原生渲染器的层对应独立的摄像机。摄像机之间依据其Depth属性决定绘制顺序。
三、原生渲染器的性能
测试了一个4W粒子的原生粒子系统,材质为Unity内置的“Particles/Alpha Blended”。测试结果:

四、其他事项
4.1 注意事项
在PC上运行Unity时要给予命令行参数-force-opengl, 强制在PC上选择OpenGL作为绘 制API。内置材质“Particles/Multipy”在PC上效果不正确,原因未明。 OpenGL状态是全局的,在原生渲染器中对OpenGL状态的改变,除原生渲染器申请的自 有资源不需要释放,其他改变如bind/unbind必须在返回Unity时还原回进入原生渲染器时的初 始状态,否则可能导致崩溃。 测试过程中遇到一些问题,如Nexus 10(Mali T604)的驱动在执行Draw-call后会造成内 存泄漏,运行一段时间后驱动便会占用超过1GB内存,令malloc分配新空间时出现内存不足。 在别的机型上没有遇到这种情况,应属于驱动问题。
4.2 未考虑的事宜
- 本文总结的方案未考虑多步骤材质(Multi-pass material),多步骤的材质情况比较复杂, 暂时未考虑它们参与原生渲染器的方法。
- 本文方案未将遮挡剔除考虑在内。
- 开启多线程渲染后,本文方法可能不能得到正确效果。
- Unity调用DrawMeshNow()绘制的网络需要被隐藏起来。
4.3 Buffer Object
把数据上传到GPU有一些需要注意的地方,如果上传新数据时Buffer object仍然被绘制 占用,可能会引发隐式同步(Implicit synchronization),等待绘制完成。通过使用多个Buffer object,在帧之间循环使用不同Buffer object可以降低这方面的开销。在GPU负载较大时会有一些性能提升,缺点是可能会增加了驱动的内存占用。
Unity原生渲染方案的更多相关文章
- Android学习探索之本地原生渲染 LaTeX数据公式
前言: 一直致力于为公司寻找更加高效的解决方案,作为一款K12在线教育App,功能中难免会有LaTeX数学公式的显示需求,这部分公司已经实现了此功能,只是个人觉得在体验和效率上还是不太好,今天来聊一下 ...
- 腾讯新闻抢金达人活动node同构直出渲染方案的总结
我们的业务在展开的过程中,前端渲染的模式主要经历了三个阶段:服务端渲染.前端渲染和目前的同构直出渲染方案. 服务端渲染的主要特点是前后端没有分离,前端写完页面样式和结构后,再将页面交给后端套数据,最后 ...
- UI系统的核心在于渲染机制:效率与生命--原生渲染为何比webview渲染快?
作者:谷宝剑链接:https://www.zhihu.com/question/264592475/answer/283852178来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- 快速上手Unity原生Json库
现在新版的Unity(印象中是从5.3开始)已经提供了原生的Json库,以前一直使用LitJson,研究了一下Unity用的JsonUtility工具类的使用,发现使用还挺方便的,所以打算把项目中的J ...
- AIR 3.0针对移动设备的高性能渲染方案
转自:http://blog.domlib.com/articles/242.html 当我们一边正在等待Stage3D的发布时,很多开发者似乎还停留在这个印象中:即使AIR 3.0也无法在移动设备上 ...
- Web开发中,页面渲染方案
转载自:http://www.jianshu.com/p/d1d29e97f6b8 (在该文章中看到一段感兴趣的文字,转载过来) 在Web开发中,有两种主流的页面渲染方案: 服务器端渲染,通过页面渲染 ...
- PIE SDK地图图层渲染方案管理
1. 功能简介 在数据种类较多.渲染规则复杂的情况下,逐个设置其渲染方式是一件繁琐的工作.PIE SDK提供了一种省力省心的办法, PIE SDK提供栅格和矢量数据渲染方案的打开与保存.能够将配色方案 ...
- [GEiv]第七章:着色器 高效GPU渲染方案
第七章:着色器 高效GPU渲染方案 本章介绍着色器的基本知识以及Geiv下对其提供的支持接口.并以"渐变高斯模糊"为线索进行实例的演示解说. [背景信息] [计算机中央处理器的局限 ...
- 在Unity中渲染一个黑洞
在Unity中渲染一个黑洞 前言 N年前观看<星际穿越>时,被其中的"卡冈图雅"黑洞所震撼.制作团队表示这是一个最贴近实际的黑洞效果,因为它是通过各种科学理论实现的.当 ...
随机推荐
- 【KVM安装】在Centos6.8中安装KVM
阅读目录 前题条件 章节1:安装Centos6.8-进行硬件检测 章节2:配置网络-设置桥接方式 章节3:安装KVM 章节4:OVA转qcow2 章节5:使用KVM创建虚拟机 章节6:参考链接 前题条 ...
- Maven仓库—Nexus环境搭建及简单介绍
1. 环境搭建 1.1 下载 http://www.sonatype.org/nexus/ NEXUS OSS [OSS = Open Source Software,开源软件--免费] NE ...
- iMac一体机安装苹果和Win7双系统
前几天,有个客户说有一苹果的一体机,想装苹果和Win7双系统.约好了时间,带上工具就过去了.去的路上,用手机上网查了一下苹果电脑装双系统的过程.虽然以前也有给苹果的电脑安装过双系统,但次数不多而且时间 ...
- Windows2012修改光驱盘符
1.输入diskmgmt.msc打开磁盘管理器 2.找到需要修改的盘符,右键点击修改盘符
- android学习笔记八——SeekBar
SeekBar——拖动条 拖动条(SeekBar)组件与ProgressBar水平形式的显示进度条类似,不过其最大的区别在于,拖动条可以由用户自己进行手工的调节,例如当用户需要调整播放器音量或者电影的 ...
- Win7系统安装Centos7.0双系统(二)
4.6语言选择
- activiti自定义流程之自定义表单(二):创建表单
注:环境配置:activiti自定义流程之自定义表单(一):环境配置 在上一节自定义表单环境搭建好以后,我就正式开始尝试自己创建表单,在后台的处理就比较常规,主要是针对ueditor插件的功能在前端进 ...
- SIP 状态码
SIP应答消息状态码 与功能 类型 状态码 状态说明临时应答(1XX) 100 Trying 正在处理中180 Ringing 振铃181 call being forwarder 呼叫正在前向182 ...
- set_union的几个例子
获得两个集合的并集.两个输入序列须保证已排好序. 数组用的时候 // set_union example #include <iostream> #include <algorith ...
- XHTML的使用规范
一.XHTML的简介 XHTML指的是可扩展超文本标记语言 XHTML与HTML4.01几乎是相同的 XHTML是更严格更纯净的HTML版本 XHTML是以XML应用的方式定义的HTML 二.为什么使 ...