Unity3D研究院GPU Instancing测试

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

内容简介:GPU instancing 很早就支持手机了(Android只支持Opengl ES 3.0),但是我一直不知道将它应用到哪里,刚好最近在调研这个我对它又重新测试了一下。如果是不动的物体勾选static静态合并批次(40-50帧率)

GPU instancing 很早就支持手机了(Android只支持Opengl ES 3.0),但是我一直不知道将它应用到哪里,刚好最近在调研这个我对它又重新测试了一下。

如果是不动的物体勾选static静态合并批次(40-50帧率)

Unity3D研究院GPU Instancing测试

自定义Shader中勾选Enable GPU Instancing

Unity3D研究院GPU Instancing测试

帧率竟然还不如静态合批次(帧率 30-40)

Unity3D研究院GPU Instancing测试

自定义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帧)

Unity3D研究院GPU Instancing测试

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的优势就更明显了。 目前来看草、石头、植被、比较合适用它。

雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!

最后编辑:

作者:雨松MOMO

专注移动互联网,Unity3D游戏开发

站内专栏 QQ交谈 腾讯微博 新浪微博

捐 赠 如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

Ruby on Rails电子商务实战

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电子商务实战》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具