[Unity] Gpu Instance理论加实践

1:基础概念

1.1:渲染管线

 具体详细内容还要是看一下的,下面给出链接【_Humex_FiDOo的博客-CSDN博客】。

渲染管线流程

1.2:为什么要用Gpu Instance?

性能优化!目的就是降低DrawCall,什么是DrawCall,渲染管线中分为几个阶段,其中只有第一阶段是由cpu完成,剩下的都是Gpu去做,但是cpu和Gpu之间的数据传输速度比Cpu,Gpu内部传输要慢很多。

一次交互为一个DrawCall,我们要做的就是减少数据交互次数。数据量其实可以不太重要,因为大部分时间都是Cpu在准备数据。

1.3:什么是Gpu Instance?

大概就是将一些数据或信息(比如位置,缩放,旋转)等,转化为像素点float4(x,y,z,w),最终变为一张texture2D图的过程,将此图传入shader后就可以一次性渲染多个物体,大概就是1*10变为10*1的过程,具体GPU 实例化 - Unity 手册

2.实现流程

 

大概就是配合Job系统进行处理,Job系统不懂。关于Unity Dots 1.0版本的学习研究(二)之JobSystem - 知乎 (zhihu.com)

简单shader语句也得懂一些,比如顶点和片元,如果不懂先收藏,继续补一下其他知识。

3.开始实现

 1.首先定义数据结构,就是Gpu负责解析读取的数据。

  /// <summary>
    /// GPu数据结构
    /// </summary>
    public struct GpuData
    {
        public float3 Position;
        public float Other;
        public float Element1;
        public float Element2;
        public float Element3;
    }

2.其次定义数据处理以及数据初始化,这次要利用Job系统,大概就是随机位置吧,other就是额外信息比如贴图uv,缩放等等


//数据处理
    public struct PointJob : IJob
    {
        public NativeArray<GpuData> data;
        public NativeArray<Random> _Randoms;
        public int Width;
        public int Height;
       // public Unity.Mathematics.Random _random;
       private Random _random;
        //xyzw 

        public void Execute()
        {
            _random = _Randoms[0];
            for (int i = 0; i < data.Length; i++)
            {
                GpuData temp = new GpuData()
                {
                    Position = new float3(_random.NextFloat(-10000, 10000), _random.NextFloat(-10000, 10000), 0),
                    Other = 150055
                };
                data[i] = temp;
            }
        }
    }

3. 创建mesh,mesh就是材质展示的实体。

'''
 //创建Mesh 
            Mesh = new Mesh();
            CreateMeshData(Mesh);
'''
 /// <summary>
        /// 创建Mesh
        /// </summary>
        /// <param name="mesh"></param>
        private void CreateMeshData(Mesh mesh)
        {
            var vertices = new Vector3[5];
            int[] tris = { 0, 1, 2, 2, 1, 3 };

            Vector2[] newUVs = new Vector2[vertices.Length];
            newUVs[0] = new Vector2(0, 0);
            newUVs[1] = new Vector2(0, 1);
            newUVs[2] = new Vector2(1, 0);
            newUVs[3] = new Vector2(1, 1);

            vertices[0] = new Vector2(-0.5f, -0.5f);
            vertices[1] = new Vector2(-0.5f, 0.5f);
            vertices[2] = new Vector2(0.5f, -0.5f);
            vertices[3] = new Vector2(0.5f, 0.5f);

          

            mesh.vertices = vertices;
            mesh.triangles = tris;
            mesh.uv = newUVs;
        }

4.将数据转化为2D贴图,像素点颜色就是数据信息。

'''
 pixelData = new NativeArray<GpuData>(TexWidth * TexWidth, Allocator.Persistent);
m_Random = new NativeArray<Unity.Mathematics.Random>(1,Allocator.Persistent);
m_Random[0] = Unity.Mathematics.Random.CreateFromIndex((uint)Random.Range(0, uint.MaxValue));

 dateTex = new Texture2D(TexWidth, TexWidth, TextureFormat.RGBAFloat, false, false);
 dateTex.filterMode = FilterMode.Point;

'''
 
            PointJob job1 = new PointJob()
            {
                data = pixelData,
                Width = TexWidth,
                Height = TexWidth,
                _Randoms = m_Random
            };
            var handler = job1.Schedule();
            handler.Complete();

5.计算数据ComputerBuffer,大概就是绘制Mesh以及绘制场景的核心步骤,一般流程写法都不会变。

'''
   public int PointNum = 1000000;
        private ComputeBuffer itemArgsBuffer;
        private uint[] itemArgs = new uint[5] { 0, 0, 0, 0, 0 };
        private int m_ItmeSubMeshIndex = 0;
        public int TexWidth;
        private int itmeSubMeshIndex = 0;
        private Bounds m_Bounds = new Bounds(Vector3.zero, new Vector3(10000.0f, 10000.0f, 0));

'''
 
void TextureInit()
        {
            //NativeArray<GpuData>.Copy(pos, pixelData, Mathf.Min(pos.Length, TexWidth * TexWidth));
            dateTex.SetPixelData(pixelData, 0, 0);
            dateTex.Apply();
            //itmeSubMeshIndex
            itmeSubMeshIndex = Mathf.Clamp(itmeSubMeshIndex, 0, Mesh.subMeshCount - 1);
            //获取给定 sub-mesh 的索引计数。
            itemArgs[0] = (uint)Mesh.GetIndexCount(itmeSubMeshIndex);
            //顶点数量
            itemArgs[1] = (uint)PointNum;
            //对于给定 /sub-mesh/,获取网格索引缓冲区中的起始索引位置。
            itemArgs[2] = (uint)Mesh.GetIndexStart(itmeSubMeshIndex);
            //获取给定 sub-mesh 的基顶点索引。
            itemArgs[3] = (uint)Mesh.GetBaseVertex(itmeSubMeshIndex);

            itemArgsBuffer.SetData(itemArgs);
            Graphics.DrawMeshInstancedIndirect(Mesh, itmeSubMeshIndex, Material, m_Bounds, itemArgsBuffer, 0);
        }

6.shader 相关。

v2f vert(appdata_full v, uint instanceID : SV_InstanceID)
				{
					int wideh=1;
					float4 data = tex2Dlod(_DataTex,fixed4(((instanceID * wideh + 0) % _Width) * (1.0f / _Width),(int)((instanceID *wideh ) / _Width) * (1.0f / _Height),0,0));
					
					//xyzw
					int uvId = data.w / 10000;
					v2f o;
					o.pos = mul(UNITY_MATRIX_VP, fixed4(worldPosition, 1.0f));
						float4 uvData = tex2Dlod(_Tex0Uv, fixed4(14 / _Tex0Num, 0,0,0));
						o.uv_MainTex = v.texcoord.xy * fixed2(uvData.z,uvData.w) + float2(uvData.x, uvData.y);
					}
				
					o.index = textureIndex;
					return o;
				}

大概意思就是一个数据占Texture_0-8像素(8*1),一个像素是一个float4数据(一个数据结构最多为4*8=32个数据),如果默认只要第一个数据比如图中的那个(pos+other ),就会定义在(id=0*8+0)第一个像素点float4,读取4个数据。 

 uv 一个像素的float4,xy为左下坐标,zw为右上坐标,解析id对应像素id/64。

 7.结果

 4.总结

其实项目很简单,应用场景很广泛,比如 草地渲染,树木渲染,等等需要很多类似的大量渲染时非常有效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BETA RELEASE Download Demo Build (Windows PC)​ Crowd Animations is an extension for GPU Instancer, and requires it to work. Support Forum | Documentation | F.A.Q. Crowd Animations is an out of the box solution for using massive amounts of animated characters in your scenes with high performance. CA uses the GPU Instancer core and adds GPU skinning techniques on top of GPUI’s indirect instancing solution and GPU culling techniques. This results in a combination which will allow you to get the most out of GPU Instancing in Unity for your animated characters. ——————————— FEATURES ——————————— – Indirect GPU instancing with skinned meshes. – GPU frustum, occlusion and distance culling. – VR compatible. Works with both single pass and multipass rendering modes. – Supports Standard, LW, HD and Universal Render Pipelines. – Custom shader support (requires manual set-up). – Animation Blending (up to 4 animations). – Multiple skinned mesh renderers and submeshes support. – LOD Groups support (all LOD meshes must use the same rig). – Bone attachments. – Root Motion support. – Ability to use custom shadow distance per prototype and to choose the LOD to render shadows with. – Automatic detection of added and removed instances without any additional code. – Rigidbody and physics support. – Custom animation event system. – Easy to use interface. Crowd Animations supports two different animator workflows: Mecanim Animator: You can use the Unity Mecanim Animator to handle the state machine for animations as usual, and GPUI will read the animator states from the Mecanim Animator. This will let you use your existing Animators and scripts with Crowd Animations, and make it possible to use indirect GPU Instancing out of the box with all the GPUI features such as GPU frustum and occlusion culling. This workflow increases GPU performance while rendering skinned meshes, but it won’t be an ideal solution for projects that are CPU bound since the Mecanim Animator will still create an o

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值