[david]unity3d绘制调用批处理(draw call batching)
2017-10-13 17:20
363 查看
要绘制一个gameobject到屏幕上,unity需要调用图像api(dx,opengl)。
图像api对每一个绘制请求都需要做大量的工作,例如输入资源校验,顶点空间信息转换。
特别是在切换不同材质球的时候,图形api要做的工作更多,因为要切换状态(透明,不透明,贴图输入,渲染方式,加载shader,调用gpu驱动api前,获取/组织/封装输入参数)。
而图形api(dx,opengl)是在cpu上运行的,所以draw call的调用会增加cpu负载,消耗cpu时间
(unity--draw call-->dx/opengl || CPU || -->显卡驱动|| GPU ||);
优化思路:减少draw call 数量,减少状态切换
每个mesh,每个材质,每个pass 都会产生一个draw call调用。
所以,最有效的方法是合并mesh来减少draw call数量。
unity有内置(好处:引擎代码层面可以独立控制每个物体)的两种合并mesh技术:
A:针对足够小的动态网格体,使用动态批处理(Dynamic batching),把类似的顶点分组,一次绘制。
限制:1、shader中最多使用900个顶点属性(例如:vert函数输出中有vertex position,normal,uv三个属性,那么输入网格最多能有300个顶点,才能加入到动态批处理)(动态批处理的每个顶点都有开销)
2、空间上存在镜像的多个物体不能一起使用动态批处理(例如:A物体的Transform_scale_x是1,B物体的Transform_scale_x是-1)
3、使用不同的材质实例不能动态批处理,即使是同一材质的不同实例,原因是阴影投射渲染的异常?
4、有附加渲染参数(lightmap index offset/scale)的光照贴图游戏物体。通常动态光照贴图游戏物体应该指向定位在批处理里的相同光照贴图?
5、多pass shader不能批处理。
在前向(forward rendering)渲染模式中,unity shader 支持多灯光,附加像素光源对应的pass不能批处理。
传统的延后(defferred(light pre-pass))渲染不支持批处理,因为延后渲染要绘制物体两次。
动态批处理要在CPU上将游戏物体的所有顶点变换到世界空间。这样变换的开销比图形api(dx,opengl)执行draw call的开销更小才有意义。
draw call要求的资源受很多因素影响,主要是dx/opengl api使用的资源。例如:主机或苹果平台上draw call的开销较小,动态批处理没有什么优势。
B:针对静态物体,合并成一个大网格体,叫静态批处理(static batching)
静态批处理会增加内存消耗。即使批处理前共享网格的N个物体,也会增加N-1份内存消耗。
例如:茂密的树林,标记为静态,使用静态批处理,就会有大量的内存消耗。这时可以考虑不标记为静态,消耗时间,节省内存开销
处理过程:将静态游戏物体转换到世界空间,
创建一个大的顶点集(64K 顶点数 )和索引缓存(64K 索引数(48K opengles,32K macos));
然后,对同意批次中的可见游戏对象,执行一系列简单的,几乎没有状态切换的draw call。
技术上没有减少draw call 数量,当大量减少了状态切换(dx/opengl重大开销的部分);
这两种批处理技术能够减少的draw call数的一个重要因素是:合并的物体共享材质的程度。
因为,不同材质不可能使用同一个draw call(排除阴影绘制)
只有共享材质的多个物体,合并成一个大网格体后,才能显著降低draw call数。
例如,10个共享材质(1个pass)的静态物体
没有使用静态批处理是10个draw call;
使用后为1个draw call,降低了90%的draw call 数。
可使用批处理的渲染器:Mesh Renderers,Trail Renderers,Line Renderers,PaticleSystems,Sprite Renderers
不能使用批处理的渲染器:skinned Meshes,cloth,other
只有同类型的渲染器可以批处理。
半透明物体比不透明物体更少的机会使用批处理,因为要从后到前的顺序获取半透明物体(确保透明效果),然后才批处理,顺序严格,获得批处理的机会更少。
通过3d模型软件或Mesh.CombineMeshes手动合并相邻的网格物体是一个替换批处理的好方法。
例如一个有多个绘制器的静态碗柜合并成一个网格是好的。
结论:多个物体共享材质(合并贴图,shader减少pass,少分支判断语句),多标为静态物体,是有效减少draw call,state changes,进而减少图形api(dx,opengl)/CPU负载,同时降低GPU负载的有效途径。
图像api对每一个绘制请求都需要做大量的工作,例如输入资源校验,顶点空间信息转换。
特别是在切换不同材质球的时候,图形api要做的工作更多,因为要切换状态(透明,不透明,贴图输入,渲染方式,加载shader,调用gpu驱动api前,获取/组织/封装输入参数)。
而图形api(dx,opengl)是在cpu上运行的,所以draw call的调用会增加cpu负载,消耗cpu时间
(unity--draw call-->dx/opengl || CPU || -->显卡驱动|| GPU ||);
优化思路:减少draw call 数量,减少状态切换
每个mesh,每个材质,每个pass 都会产生一个draw call调用。
所以,最有效的方法是合并mesh来减少draw call数量。
unity有内置(好处:引擎代码层面可以独立控制每个物体)的两种合并mesh技术:
A:针对足够小的动态网格体,使用动态批处理(Dynamic batching),把类似的顶点分组,一次绘制。
限制:1、shader中最多使用900个顶点属性(例如:vert函数输出中有vertex position,normal,uv三个属性,那么输入网格最多能有300个顶点,才能加入到动态批处理)(动态批处理的每个顶点都有开销)
2、空间上存在镜像的多个物体不能一起使用动态批处理(例如:A物体的Transform_scale_x是1,B物体的Transform_scale_x是-1)
3、使用不同的材质实例不能动态批处理,即使是同一材质的不同实例,原因是阴影投射渲染的异常?
4、有附加渲染参数(lightmap index offset/scale)的光照贴图游戏物体。通常动态光照贴图游戏物体应该指向定位在批处理里的相同光照贴图?
5、多pass shader不能批处理。
在前向(forward rendering)渲染模式中,unity shader 支持多灯光,附加像素光源对应的pass不能批处理。
传统的延后(defferred(light pre-pass))渲染不支持批处理,因为延后渲染要绘制物体两次。
动态批处理要在CPU上将游戏物体的所有顶点变换到世界空间。这样变换的开销比图形api(dx,opengl)执行draw call的开销更小才有意义。
draw call要求的资源受很多因素影响,主要是dx/opengl api使用的资源。例如:主机或苹果平台上draw call的开销较小,动态批处理没有什么优势。
B:针对静态物体,合并成一个大网格体,叫静态批处理(static batching)
静态批处理会增加内存消耗。即使批处理前共享网格的N个物体,也会增加N-1份内存消耗。
例如:茂密的树林,标记为静态,使用静态批处理,就会有大量的内存消耗。这时可以考虑不标记为静态,消耗时间,节省内存开销
处理过程:将静态游戏物体转换到世界空间,
创建一个大的顶点集(64K 顶点数 )和索引缓存(64K 索引数(48K opengles,32K macos));
然后,对同意批次中的可见游戏对象,执行一系列简单的,几乎没有状态切换的draw call。
技术上没有减少draw call 数量,当大量减少了状态切换(dx/opengl重大开销的部分);
这两种批处理技术能够减少的draw call数的一个重要因素是:合并的物体共享材质的程度。
因为,不同材质不可能使用同一个draw call(排除阴影绘制)
只有共享材质的多个物体,合并成一个大网格体后,才能显著降低draw call数。
例如,10个共享材质(1个pass)的静态物体
没有使用静态批处理是10个draw call;
使用后为1个draw call,降低了90%的draw call 数。
可使用批处理的渲染器:Mesh Renderers,Trail Renderers,Line Renderers,PaticleSystems,Sprite Renderers
不能使用批处理的渲染器:skinned Meshes,cloth,other
只有同类型的渲染器可以批处理。
半透明物体比不透明物体更少的机会使用批处理,因为要从后到前的顺序获取半透明物体(确保透明效果),然后才批处理,顺序严格,获得批处理的机会更少。
通过3d模型软件或Mesh.CombineMeshes手动合并相邻的网格物体是一个替换批处理的好方法。
例如一个有多个绘制器的静态碗柜合并成一个网格是好的。
结论:多个物体共享材质(合并贴图,shader减少pass,少分支判断语句),多标为静态物体,是有效减少draw call,state changes,进而减少图形api(dx,opengl)/CPU负载,同时降低GPU负载的有效途径。
相关文章推荐
- Unity3D项目优化--绘制调用批处理unity3D Draw
- unity项目优化--绘制调用批处理unity3d Draw Call Batching
- unity3d Draw Call Batching (绘制调用批处理)
- Draw Call Batching (绘制调用批处理)
- Unity3D技术之优化图形性能绘制调用批处理浅析
- Unity3D技术之优化图形性能绘制调用批处理浅析
- 【Unity3d】在Unity3d中调用外部程序及批处理文件,写自动化编译脚本需要注意的地方
- cocos2d-x 3.0 绘制图形DrawNode与调用周期性回调函数schedule
- cocos2dx-draw绘制
- cvDrawContours绘制轮廓
- Unity3d绘制饼状图
- java JDBC最基本的操作读取、调用存储过程、执行批处理、事务等
- 【数据库-MySQL】批处理调用MySQL的sql文件
- Unity3D技术之名称与血条绘制详解
- 【神经网络与深度学习】【python开发】caffe-windows使能python接口使用draw_net.py绘制网络结构图过程
- Unity3D 游戏引擎之游戏对象的访问绘制线与绘制面详解(十七)
- [Unity3D]调用Android接口
- cocos2dx-draw绘制
- Unity3D开发小贴士(六)Lua里调用C#扩展
- Android开发:canvas.drawTextOnPath()无效----Android4.03的又一个bug!!!!(关于Canvas绘制的方方面面) .