内容简介:GPU instancing 很早就支持手机了(Android只支持Opengl ES 3.0),但是我一直不知道将它应用到哪里,刚好最近在调研这个我对它又重新测试了一下。如果是不动的物体勾选static静态合并批次(40-50帧率)
GPU instancing 很早就支持手机了(Android只支持Opengl ES 3.0),但是我一直不知道将它应用到哪里,刚好最近在调研这个我对它又重新测试了一下。
如果是不动的物体勾选static静态合并批次(40-50帧率)
自定义Shader中勾选Enable GPU Instancing
帧率竟然还不如静态合批次(帧率 30-40)
自定义Shader
Shader "SimplestInstancedShader1" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_instancing #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID // necessary only if you want to access instanced properties in fragment Shader. }; UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float4, _Color) UNITY_INSTANCING_BUFFER_END(Props) sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata v) { v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); // necessary only if you want to access instanced properties in the fragment Shader. o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag(v2f i) : SV_Target { UNITY_SETUP_INSTANCE_ID(i); // necessary only if any instanced properties are going to be accessed in the fragment Shader. return tex2D (_MainTex, i.uv) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color); } ENDCG } } }
所以,静态不动的物体就没必要用上面的方法了,于是我又测试了Graphics.DrawMeshInstanced()方法,终于满意了。(稳定60帧)
Graphics.DrawMeshInstanced()方法不需要游戏对象以及游戏组件的额外开销,在Update()方法中一气呵成,不过它也有限制,最多可以画1023个。
还有个方法是Graphics.DrawMeshInstancedIndirect()它没有画多少的限制,而且更加灵活,我也搞了好一会儿才在游戏中跑起来,后来才知道它不能再手机上用,只有PC上可以.
在shader中接收位置 颜色 矩阵
Shader "Instanced/InstancedIndirectSelection" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags{ "RenderType" = "Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 4.5 #include "UnityCG.cginc" StructuredBuffer<float4> positionBuffer; StructuredBuffer<float4> colorBuffer; StructuredBuffer<float4x4> matrix4x4Buffer; struct appdata { fixed4 color : COLOR; float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 color: COLOR; float4 vertex : SV_POSITION; float2 texcoord : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata v, uint instanceID : SV_InstanceID) { float4 data = positionBuffer[instanceID]; float4x4 materix = matrix4x4Buffer[instanceID / matrix4x4Buffer.Length]; float3 worldPosition = data.xyz + mul(materix,v.vertex.xyz * data.w); v2f o; o.vertex = mul(UNITY_MATRIX_VP, float4(worldPosition, 1.0f)); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); o.color = colorBuffer[instanceID]; return o; } fixed4 frag(v2f i) : SV_Target { return tex2D (_MainTex, i.texcoord) * i.color; } ENDCG } } }
在代码中将位置 颜色 矩阵传进去就行了
using UnityEngine; public class InstancedIndirectExample : MonoBehaviour { public int instanceCount = 100000; public Mesh instanceMesh; public Material instanceMaterial; private ComputeBuffer positionBuffer; private ComputeBuffer argsBuffer; private ComputeBuffer colorBuffer; private ComputeBuffer matrix4x4Buffer; private uint[] args = new uint[5] { 0, 0, 0, 0, 0 }; void Start() { argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); UpdateBuffers(); } void Update() { // instanceMaterial.SetBuffer("positionBuffer", positionBuffer); Graphics.DrawMeshInstancedIndirect(instanceMesh, 0, instanceMaterial, new Bounds(Vector3.zero, new Vector3(100.0f, 100.0f, 100.0f)), argsBuffer); } void UpdateBuffers() { if ( instanceCount < 1 ) instanceCount = 1; // Positions & Colors if (positionBuffer != null) positionBuffer.Release(); if (colorBuffer != null) colorBuffer.Release(); if (matrix4x4Buffer != null) matrix4x4Buffer.Release(); positionBuffer = new ComputeBuffer(instanceCount, 16); colorBuffer = new ComputeBuffer(instanceCount, 4*4); matrix4x4Buffer = new ComputeBuffer(instanceCount,16); Vector4[] positions = new Vector4[instanceCount]; Vector4[] colors = new Vector4[instanceCount]; Matrix4x4[] materix4X4 = new Matrix4x4[instanceCount]; for (int i=0; i < instanceCount; i++) { positions [i] = new Vector4 (i, 0f, 0f, 1f); colors[i] = new Vector4( 1f, 1f, 1f, 1f ); materix4X4[i] = Matrix4x4.TRS (positions [i], Quaternion.Euler (0F, 0F, 0F), Vector3.one); } positionBuffer.SetData(positions); colorBuffer.SetData(colors); matrix4x4Buffer.SetData (materix4X4); instanceMaterial.SetBuffer("positionBuffer", positionBuffer); instanceMaterial.SetBuffer("colorBuffer", colorBuffer); instanceMaterial.SetBuffer("matrix4x4Buffer", matrix4x4Buffer); // indirect args uint numIndices = (instanceMesh != null) ? (uint)instanceMesh.GetIndexCount(0) : 0; args[0] = numIndices; args[1] = (uint)instanceCount; argsBuffer.SetData(args); } void OnDisable() { if (positionBuffer != null) positionBuffer.Release(); positionBuffer = null; if (colorBuffer != null) colorBuffer.Release(); colorBuffer = null; if (argsBuffer != null) argsBuffer.Release(); argsBuffer = null; if (matrix4x4Buffer != null) matrix4x4Buffer.Release(); matrix4x4Buffer = null; } }
如果是发生移动的物体顶点数量在900以内会动态合并批次,如果需要支持更多的顶点GPU Instaning的优势就更明显了。 目前来看草、石头、植被、比较合适用它。
- 本文固定链接: https://www.xuanyusong.com/archives/4488
- 转载请注明:雨松MOMO 于雨松MOMO程序研究院 发表
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
捐 赠 如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 中国电信广州研究院与思博伦通信共同推动智能化承载网络测试技术研究
- 中国电子技术标准化研究院雷虎:以标准为依托,构建区块链测试生态
- 巨头们的AI研究院战事
- 清华人工智能研究院成立「知识智能研究中心」,发布四大知识平台
- AWS在上海成立人工智能研究院
- 微软亚洲研究院:NLP将迎来黄金十年
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ruby on Rails电子商务实战
Christian Hellsten、Jarkko Laine / 曹维远 / 人民邮电出版社 / 2008-4 / 49.00元
《Ruby on Rails电子商务实战》全面讲解了使用Ruby on Rails创建产品级应用程序的过程。书中通过演示构建网上书店的全过程,先后介绍如何使用如TDD的敏捷实践,启动一个项目并建立良好稳定的基础,如何深入Ruby on Rails,实现诸如将应用程序翻译成各种语言对产品进行调试等的普遍需求。其中用到的主要技术包括Ajax、聚合、设置标签和国际化等,还介绍了如何使用ActiveRec......一起来看看 《Ruby on Rails电子商务实战》 这本书的介绍吧!