Unity原生渲染方案

Unity原生渲染方案

作者:3dimensions

本文为原创内容,转载请注明出处。

  做这个的动机是想在原生代码中使用Unity的材质系统绘制,同时由原生代码提供绘制数据,省掉动态模型数据“非托管内存→ 托管内存→ 非托管内存”的传输过程。适用于有大量动态模型数据生成的情况,注意,如果不使用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 Bu?er Object

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

时间: 04-24

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

我使用的 unity 热更新方案 JSB(求小编 推荐一下)

今天周五 ,明天没有什么事情,可以安心写一些博客. 今天聊 两个话题 一 , unity热更新的窘境 二 ,我所使用的unity 热更新方案JSB ======================================热更新的窘境============================================= (1)其实unity 热更新到瓶颈是 ios 的 系统本身 ,禁止你 jit .说白了,内存中代码,系统本身不让你执行. 安卓 系统,桌面 系统,本身都支持 动态直接替换d

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

我们的业务在展开的过程中,前端渲染的模式主要经历了三个阶段:服务端渲染.前端渲染和目前的同构直出渲染方案. 服务端渲染的主要特点是前后端没有分离,前端写完页面样式和结构后,再将页面交给后端套数据,最后再一起联调.同时前端的发布也依赖于后端的同学:但是优点也很明显:页面渲染速度快,同时 SEO 效果好. 为了解决前后端没有分离的问题,后来就出现了前端渲染的这种模式,路由选择和页面渲染,全部放在前端进行.前后端通过接口进行交互,各端可以更加专注自己的业务,发布时也是独立发布.但缺点是页面渲染慢,严重

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

第七章:着色器 高效GPU渲染方案 本章介绍着色器的基本知识以及Geiv下对其提供的支持接口.并以"渐变高斯模糊"为线索进行实例的演示解说. [背景信息] [计算机中央处理器的局限性] 在大学的"数字图像处理"课程中,老师解说了高斯模糊的基本算法.并使用C#进行了基本实现.高斯模糊.简单地说,就是使用高斯权重模板对图像的每个像素进行再计算.填充,以达到模糊的效果. 在课程中.对于给定的模板与模糊度系数,对一副800X600的图像进行模糊处理.须要计算48万个像素点,

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

第七章:着色器 高效的GPU渲染方案 本章介绍着色器的基本知识以及Geiv下对其提供的支持接口,并以"渐变高斯模糊"为线索进行实例的演示讲解. [背景信息] [计算机中央处理器的局限性] 在大学的"数字图像处理"课程中,老师讲解了高斯模糊的基本算法,并使用C#进行了基本实现.高斯模糊,简单地说,就是使用高斯权重模板对图像的每一个像素进行再计算.填充,以达到模糊的效果. 在课程中,对于给定的模板与模糊度系数,对一副800X600的图像进行模糊处理,需要计算48万个像素

Web开发中,页面渲染方案

转载自:http://www.jianshu.com/p/d1d29e97f6b8 (在该文章中看到一段感兴趣的文字,转载过来) 在Web开发中,有两种主流的页面渲染方案: 服务器端渲染,通过页面渲染引擎渲染好HTML页面发送给浏览器 客户端渲染,客户单端通过RESTAPI获取数据在浏览器上动态渲染页面 前者的技术栈包括:Thymeleaf.Apache Velocity .Freemarker 等主流方案,后者有React.AngularJS.vue.js.Backbone.js等前端渲染框架

[Unity官方文档翻译]Primitive and Placeholder Objects Unity原生3D物体教程

Primitive and Placeholder Objects 原始的基础物体 Unity can work with 3D models of any shape that can be created with modelling software. However, there are also a number of primitive object types that can be created directly within Unity, namely the Cube, S

Unity热更新方案(uLua vs sLua)

首先附上这两个项目的地址,这两个项目都是比较完善的lua解决方案,从效率和使用方式上说都不相伯仲,我最终选择了ulua,但是并不是说其具有压倒性优势. uLua:http://ulua.org/index.html sLua:https://github.com/pangweiwei/slua 引入lua,基本上就是为了热更新,不过后面苹果似乎对lua脚本的热更新也限制的很严格,拿脚本做热更新也要偷偷摸摸的去做.所以说我一贯的观点是游戏框架设计的合理些(比如技能.界面中可以用配置的,尽量不要硬编

解决圆角离屏渲染方案

最近看了大量的优化tableview方案,为了配合sd下载图片,并且解决圆角图片离屏渲染问题,于是利用category自己写了个处理圆角的方法,解决了离屏渲染问题(并不是非常高效,感觉只是降低了GPU的消耗,但是提升了CPU的消耗,但是好歹也算是能提高一点fps),我还是更推荐使用yyimage下载图片,里面封装了处理圆角图片方法. 下面是代码: // // UIImageView+CornerRadius.m // test // // Created by gkoudai_xsm on 16

用体渲染的方法在Unity中渲染云

最近在知乎上看到一篇文章讲云层的渲染(https://zhuanlan.zhihu.com/p/34836881?utm_medium=social&utm_source=qq) 原文简单的讲了噪声生成云体的办法,以及一个光照模型. 看了之后很感兴趣,加上本科毕设做的就是体渲染,于是打算在unity里山寨一个出来. 原原文(知乎上的文章引用的文章)是2015年地平线黎明时分制作团队的一个talk(http://advances.realtimerendering.com/s2015/The%20