unity Gpu Instance
参考网址:
https://blog.csdn.net/leonwei/article/details/73274808
https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstanced.html
https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html
https://www.cnblogs.com/hont/p/7143626.html
draw the same mesh multiple times using GPU instancing.
similar to Graphics.DrawMesh, this function draws meshes for one frame without the overhead of creating unnecessary game objects.
use this function in situations where u want to draw the same mesh for a particular amount of times using an instanced shader. meshes are not further culled by the view frustum or baked occluders, nor sorted for transparency or z efficiency.
The transformation matrix of each instance of the mesh should be packed into the matrices array. You can specify the number of instances to draw, or by default it is the length of the matrices array. Other per-instance data, if required by the shader, should be provided by creating arrays on the MaterialPropertyBlock argument using SetFloatArray, SetVectorArray and SetMatrixArray.
To render the instances with light probes, provide the light probe data via the MaterialPropertyBlock and specify lightProbeUsage with LightProbeUsage.CustomProvided. Check LightProbes.CalculateInterpolatedLightAndOcclusionProbes for the details.
Note: You can only draw a maximum of 1023 instances at once.
InvalidOperationException will be thrown if the material doesn’t have Material.enableInstancing set to true, or the current platform doesn’t support this API (i.e. if GPU instancing is not available). See SystemInfo.supportsInstancing.
以下抄写自:https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html
Description
Draw the same mesh multiple times using GPU instancing.
similar to Graphics.DrawMeshInstanced, this function draws many instances of the same mesh, but unlike that method, the arguments for how many instances to draw come from bufferWithArgs.
use this function in situations where u want to draw the same mesh for a particular amount of times using an instanced shader. meshes are not further culled by the view frustum or baked occluders, nor sorted for transparency or z efficiency.
buffer with arguments, bufferWithArgs, has to have five integer numbers at given argsOffset offset: index count per instance, instance count, start index location, base vertex location, start instance location.
unity only needs the submeshIndex argument if submeshes within the mesh have different topologies (e.g. Triangles and lines). otherwise, all the information about which submesh to draw comes from the bufferWithArgs argument.
Here is a script that can be used to draw many instances of the same mesh:
using UnityEngine;
using System.Collections;
public class GPUInstanceDemo : MonoBehaviour
{
public int instanceCount = 5;
public Mesh instanceMesh;
public Material instanceMaterial;
private int subMeshIndex = 0;
private ComputeBuffer positionBuffer;
private ComputeBuffer argsBuffer;
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()
{
Graphics.DrawMeshInstancedIndirect(instanceMesh, subMeshIndex, instanceMaterial, new Bounds(Vector3.zero, new Vector3(100,100,100)), argsBuffer);
}
void UpdateBuffers()
{
if (positionBuffer != null)
positionBuffer.Release();
positionBuffer = new ComputeBuffer(instanceCount, 16);
Vector4[] positions = new Vector4[instanceCount];
for (int i = 0; i < instanceCount; i++)
{
float x = Random.Range(-5, 5);
float y = Random.Range(-5, 5);
float z = Random.Range(-5, 5);
positions[i] = new Vector4(x, y, z);
}
positionBuffer.SetData(positions);
instanceMaterial.SetBuffer("positionBuffer", positionBuffer);
}
void OnDisable()
{
if (positionBuffer != null)
positionBuffer.Release();
positionBuffer = null;
if (argsBuffer != null)
argsBuffer.Release();
argsBuffer = null;
}
}
shader代码:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Instanced/InstancedShader"
{
SubShader
{
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
#pragma target 4.5
#include "UnityCG.cginc"
#if SHADER_TARGET >= 45
StructuredBuffer<float4> positionBuffer;
#endif
struct v2f
{
float4 pos : SV_POSITION;
};
v2f vert(appdata_full v, uint instanceID : SV_InstanceID)
{
#if SHADER_TARGET >= 45
float4 data = positionBuffer[instanceID];
#else
float4 data = 0;
#endif
v2f o;
v.vertex += data;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
#if SHADER_TARGET >= 45
fixed4 data = fixed4(1,1,0,1);
#else
fixed4 data = fixed4(1, 0, 0, 1);
#endif
return data;
}
ENDCG
}
}
}
实现效果:
完整的案例,见官网。
但是有一个问题:
Graphics.DrawMeshInstancedIndirect(instanceMesh, subMeshIndex, instanceMaterial, new Bounds(Vector3.zero, new Vector3(100,100,100)), argsBuffer);
最后的两个参数不知道啥意思,待续……