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有一些区别:

  1. 在PC上,Unity进入原生渲染之后,查询到的当前着色器名字为0,但这并不意味着绘制 状态被破坏,仍然可以绘制出正确的结果。我们怀疑DrawMeshNow()选择了设置材质到固 定管线,在PC原生渲染中只能利用这一固定管线。OpenGL固定管线的顶点属性是有语 义的,在原生渲染中调用gl*Pointer接口提供顶点数据就可以提交draw-call。
  2. 在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 未考虑的事宜

  1. 本文总结的方案未考虑多步骤材质(Multi-pass material),多步骤的材质情况比较复杂, 暂时未考虑它们参与原生渲染器的方法。
  2. 本文方案未将遮挡剔除考虑在内。
  3. 开启多线程渲染后,本文方法可能不能得到正确效果。
  4. Unity调用DrawMeshNow()绘制的网络需要被隐藏起来。

4.3 Buffer Object

  把数据上传到GPU有一些需要注意的地方,如果上传新数据时Buffer object仍然被绘制 占用,可能会引发隐式同步(Implicit synchronization),等待绘制完成。通过使用多个Buffer object,在帧之间循环使用不同Buffer object可以降低这方面的开销。在GPU负载较大时会有一些性能提升,缺点是可能会增加了驱动的内存占用。

Unity原生渲染方案的更多相关文章

  1. Android学习探索之本地原生渲染 LaTeX数据公式

    前言: 一直致力于为公司寻找更加高效的解决方案,作为一款K12在线教育App,功能中难免会有LaTeX数学公式的显示需求,这部分公司已经实现了此功能,只是个人觉得在体验和效率上还是不太好,今天来聊一下 ...

  2. 腾讯新闻抢金达人活动node同构直出渲染方案的总结

    我们的业务在展开的过程中,前端渲染的模式主要经历了三个阶段:服务端渲染.前端渲染和目前的同构直出渲染方案. 服务端渲染的主要特点是前后端没有分离,前端写完页面样式和结构后,再将页面交给后端套数据,最后 ...

  3. UI系统的核心在于渲染机制:效率与生命--原生渲染为何比webview渲染快?

    作者:谷宝剑链接:https://www.zhihu.com/question/264592475/answer/283852178来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  4. 快速上手Unity原生Json库

    现在新版的Unity(印象中是从5.3开始)已经提供了原生的Json库,以前一直使用LitJson,研究了一下Unity用的JsonUtility工具类的使用,发现使用还挺方便的,所以打算把项目中的J ...

  5. AIR 3.0针对移动设备的高性能渲染方案

    转自:http://blog.domlib.com/articles/242.html 当我们一边正在等待Stage3D的发布时,很多开发者似乎还停留在这个印象中:即使AIR 3.0也无法在移动设备上 ...

  6. Web开发中,页面渲染方案

    转载自:http://www.jianshu.com/p/d1d29e97f6b8 (在该文章中看到一段感兴趣的文字,转载过来) 在Web开发中,有两种主流的页面渲染方案: 服务器端渲染,通过页面渲染 ...

  7. PIE SDK地图图层渲染方案管理

    1. 功能简介 在数据种类较多.渲染规则复杂的情况下,逐个设置其渲染方式是一件繁琐的工作.PIE SDK提供了一种省力省心的办法, PIE SDK提供栅格和矢量数据渲染方案的打开与保存.能够将配色方案 ...

  8. [GEiv]第七章:着色器 高效GPU渲染方案

    第七章:着色器 高效GPU渲染方案 本章介绍着色器的基本知识以及Geiv下对其提供的支持接口.并以"渐变高斯模糊"为线索进行实例的演示解说. [背景信息] [计算机中央处理器的局限 ...

  9. 在Unity中渲染一个黑洞

    在Unity中渲染一个黑洞 前言 N年前观看<星际穿越>时,被其中的"卡冈图雅"黑洞所震撼.制作团队表示这是一个最贴近实际的黑洞效果,因为它是通过各种科学理论实现的.当 ...

随机推荐

  1. laravel5-目录结构分析

    laravel5-目录结构分析 (2016-01-21 11:24:03) 转载▼     一.环境配置: $ lsb_release -a No LSB modules are available. ...

  2. zend studio一些常用配置

    zend studio 常用 配置 1.zend中添加注释是ctrl+slash,这个slash在哪里?如何来取消注释 slash是斜杠'/'那个键,就是在,.之后的那个. 进行注释是 ctrl+'/ ...

  3. bootstrap的datetimepicker只选择月份

    本文转载自:http://blog.csdn.net/feng1603/article/details/41869523 直接上代码: //选择年月日的 startView: 2, minView: ...

  4. Java-输入输出

    1. 流的分类 java.io 1.1 输入和输出流 File类不能访问文件内容本身,需要使用输入/输出流 输入输出流的方向是相对与内存读写的方向. 1.2 字节流和字符流 字节流 InputStea ...

  5. [Freescale]E9学习笔记-LTIB安装配置

    转自:http://blog.csdn.net/girlkoo/article/details/44535979 LTIB: Linux Target Image Builder Freescale提 ...

  6. BestCoder Round #86 部分题解

    Price List 题意: 有n件商品,每天只能买一件,并且会记录账本,问有多少次一定记多了? 题解: 就是求和,最后如果大于和就输出1,否则0. 代码: #include <bits/std ...

  7. SCREAM:Error suppression ignored for

    wamp报错SCREAM:Error suppression ignored for 问题:SCREAM:Error suppression ignored for 解决: 在php.ini最下面加入 ...

  8. 转--Android学习笔记-实用代码合集

    http://blog.csdn.net/yf210yf/article/details/7295577 转载请注明原文出处:奔跑的蜗牛(袁方的技术博客)点击打开链接 一.当利用textview显示内 ...

  9. gerrit 配置 apache2 反向代理(转载)

    Apache 2 Configuration To run Gerrit behind an Apache server using mod_proxy, enable the necessary A ...

  10. lamp.phpstudy.net

    phpStudy phpStudy » PHP教程 » phpStudy for Linux (lnmp+lamp一键安装包) phpStudy for Linux (lnmp+lamp一键安装包) ...