首页 > Unity3D频道 > 【Unity3D研究院之游戏开发】 > Unity3D研究院GPU Instancing实战(九十七)
2018
09-30

Unity3D研究院GPU Instancing实战(九十七)

最近将GPU Instancing应用在游戏中,遇到了一些坑和大家分享一下,我们用的版本是unity2017。前面说了GPU Instancing目前适合游戏中的草、石头等元素较多的地方。

首先需要开发一个刷地表的编辑器,试想一下如果场景上的草每个都要美术手动的去摆这得多麻烦啊,如下图所示,根据网格和材质动态的在地形上刷地表。

Unity3D研究院GPU Instancing实战(九十七) - 雨松MOMO程序研究院 - 1

刷地表的代码如下所示

刷出来的元素就是每个不同的游戏对象,编辑模式下可以还可以单独的调整它们。不过这又带来另一个问题,如果美术刷了几万个草元素,总不能运行时也管理这些游戏对象吧。上篇文章我们也讲过,GPU Instancing使用游戏对象的方式效率是最低的,所以我们需要使用Graphics.DrawMeshInstanced()一次性将元素画出来,不需要游戏对象。

Unity3D研究院GPU Instancing实战(九十七) - 雨松MOMO程序研究院 - 2

所以在编辑模式下我们还需要一个保存的功能,就是将美术刷出来的草元素每个的位置、旋转、缩放、顶点色、序列化在本地,我是将游戏对象的矩阵序列化在本地的。如下图所示,运行时就不需要游戏对象了,使用Graphics.DrawMeshInstanced()一次画出来,只占用一个drawcall。

Unity3D研究院GPU Instancing实战(九十七) - 雨松MOMO程序研究院 - 3

Graphics.DrawMeshInstanced()这方法还有两问题

1.一次最多画1023个元素,如果超出就会报错,所以需要将草进行分类管理。

2.它不提供裁切的功能,也就是说摄像机看不到的地方,这些草是不会被剔除掉的,依然会被渲染。

解决这个问题,为了避免运行时暴力的for循环来判断是否在视野内,我采取的方法是预先将场景分成20X20若干个格子(可根据游戏的可视范围而定)根据玩家的位置,始终只渲染周围9个格子内的草元素,这样将大幅度减少运行时for循环的次数。

如果每个草的顶点色是不一样的怎么办呢?接着我们看看C#这边如何将参数传到shader中,如下代码所示,创建MaterialPropertyBlock以后就可以将参数以及对应的值传递给shader中了。

Shader中可以接受这些值,在vs和ps中处理 。

毕竟opengl es2.0的手机是不支持的,所以我们还需要做个容错机制。 可以判断出来手机是否支持  SystemInfo.supportsInstancing
最后如果有什么建议或者意见欢迎在下面留言!

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院GPU Instancing实战(九十七)》有 5 条评论

  1. 李XX 说:

    如果按照你说的这样子,为什么竟然分格子,不直接预先把一个格子整成一个批次(相当于静态合并批次,但是u3d的静态合并批次,并不是将全部相同物体整成一个批次,他只是减少setpass,有些才合并了一个,但是你上面那种例子,肯定是适合提前整一个格子整成一个批次),上一篇讲这个文章,没用DrawMeshInstanced让它自动instancing,帧数那么低其实有一个小概率可能,就是并没有真正instancing,因为u3d代码很多情况会break,我这边遇到一个很奇葩的现象,一些低端机(当然是支持instancing的),有一些截帧工具发现它并没有instancing,换是分开绘制,但是里面的shader已经编译为带instancing标识的,同时supportsInstancing是true。当然我用高端一些的机器就没有这个问题,不知道你有没有遇到过这样的问题,就是在联发科的cpu,机器大概才500块

  2. ZeratuJ 说:

    也就是说,GPU Instancing 需要相同VBO,相同的着色器Pass, 并且绘制区别仅限于值类型参数的数值区别,GPU Instancing才会生效,是这样吗?

  3. 龙哥 说:

    gpu instancing的意义不是在于相同的材质使用不同的属性 但仍然可以合批吗…

留下一个回复

你的email不会被公开。