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

栏目: 后端 · 发布时间: 6年前

内容简介:最近将GPU Instancing应用在游戏中,遇到了一些坑和大家分享一下,我们用的版本是unity2017。前面说了GPU Instancing目前适合游戏中的草、石头等元素较多的地方。首先需要开发一个刷地表的编辑器,试想一下如果场景上的草每个都要美术手动的去摆这得多麻烦啊,如下图所示,根据网格和材质动态的在地形上刷地表。

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

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

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

刷地表的代码如下所示

void OnSceneGUI()
{
	Event e = Event.current;
	if (e == null) {
		return;
	}
	HandleUtility.AddDefaultControl (GUIUtility.GetControlID (FocusType.Passive));
 
	Ray worldray = HandleUtility.GUIPointToWorldRay (e.mousePosition);
 
 
 
	if (e.type == EventType.MouseDown && !e.alt && e.button == 0) {
		//点击种草
	}
 
	if (e.type == EventType.MouseDrag && !e.alt && e.button == 0) {
 
		//拖动种草
	}
 
	if (Physics.Raycast (worldray, out m_Hit,500f,1 << LayerMask.NameToLayer("GInstances"))) {
	
		//种草椭圆区域
		Handles.color = new Color (1f, 1f, 1f, 0.5f);
		Handles.DrawSolidDisc (m_Hit.point, m_Hit.normal, m_Radiua.floatValue);
		Handles.color = Color.red;
		Handles.DrawWireDisc (m_Hit.point, m_Hit.normal, m_Radiua.floatValue);
		SceneView.RepaintAll ();
	}
}

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

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

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

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

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

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

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

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

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

for (int i = 0; i < m_Matrixs.Count; i++)
{
   MaterialPropertyBlock prop = new MaterialPropertyBlock();
   prop.SetVectorArray("_LightMapUV", m_Lightmaps[i]);
   prop.SetColor("_Color", Color.white);
   var item = m_Matrixs[i];
   Graphics.DrawMeshInstanced(m_InstanceMesh, 0, m_InstanceMaterial, item, prop, ShadowCastingMode.On, true);
}

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

UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
UNITY_DEFINE_INSTANCED_PROP(float4, _LightMapUV)
UNITY_INSTANCING_BUFFER_END(Props)

毕竟opengl es2.0的手机是不支持的,所以我们还需要做个容错机制。 可以判断出来手机是否支持  SystemInfo.supportsInstancing

最后如果有什么建议或者意见欢迎在下面留言!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人人都是架构师:分布式系统架构落地与瓶颈突破

人人都是架构师:分布式系统架构落地与瓶颈突破

高翔龙 / 电子工业出版社 / 2017-5 / 69

《人人都是架构师:分布式系统架构落地与瓶颈突破》并没有过多渲染系统架构的理论知识,而是切切实实站在开发一线角度,为各位读者诠释了大型网站在架构演变过程中出现一系列技术难题时的解决方案。《人人都是架构师:分布式系统架构落地与瓶颈突破》首先从分布式服务案例开始介绍,重点为大家讲解了大规模服务化场景下企业应该如何实施服务治理;然后在大流量限流/消峰案例中,笔者为大家讲解了应该如何有效地对流量实施管制,避......一起来看看 《人人都是架构师:分布式系统架构落地与瓶颈突破》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具