版本:Unity 6 (6000.0)
语言英语
  • C#

Graphics.DrawMeshInstancedIndirect

建议修改

成功!

感谢您帮助我们提高 Unity 文档的质量。虽然我们无法接受所有意见,但我们会阅读用户建议的每项修改,并在适用情况下进行更新。

关闭

提交失败

由于某些原因,您建议的修改无法提交。请在几分钟后<a>重试</a>。感谢您抽出时间帮助我们提高 Unity 文档的质量。

关闭

取消

声明

public static void DrawMeshInstancedIndirect(网格 网格, int 子网格索引, 材质 材质, 范围 范围, 计算缓冲区 带参数的缓冲区, int 参数偏移 = 0, 材质属性块 属性 = null, 渲染.阴影投射模式 投射阴影 = ShadowCastingMode.On, bool 接收阴影 = true, int = 0, 摄像机 摄像机 = null, 渲染.光照探测器使用情况 光照探测器使用情况 = LightProbeUsage.BlendProbes, 光照探测器代理体积 光照探测器代理体积 = null);

声明

public static void DrawMeshInstancedIndirect(网格 网格, int 子网格索引, 材质 材质, 范围 范围, 图形缓冲区 带参数的缓冲区, int 参数偏移 = 0, 材质属性块 属性 = null, 渲染.阴影投射模式 投射阴影 = ShadowCastingMode.On, bool 接收阴影 = true, int = 0, 摄像机 摄像机 = null, 渲染.光照探测器使用情况 光照探测器使用情况 = LightProbeUsage.BlendProbes, 光照探测器代理体积 光照探测器代理体积 = null);

参数

网格 要绘制的网格
子网格索引 要绘制的网格的子集。这仅适用于由多种材质组成的网格。
材质 要使用的材质
范围 你打算绘制的实例周围的边界体积。
bufferWithArgs 包含如何绘制该网格的实例数量的参数的 GPU 缓冲区。
argsOffset 绘制参数开始处的缓冲区中的字节偏移量。
properties 要应用的附加材料属性。参见MaterialPropertyBlock
castShadows 确定网格能否投射阴影。
receiveShadows 确定网格能否接收阴影。
layer 要使用的图层
camera 如果为null(默认值),网格将在所有摄像机中绘制。否则,它将仅在给定的摄像机中绘制。
lightProbeUsage 实例的LightProbeUsage

描述

此函数现已弃用。请改用Graphics.RenderMeshIndirect。使用 GPU 实例化多次绘制同一网格。

此函数仅适用于支持计算着色器的平台。

类似于Graphics.DrawMeshInstanced,此函数绘制同一网格的多个实例,但与该方法不同,有关要绘制多少个实例的参数来自bufferWithArgs

在你要使用实例化着色器绘制特定次数的同一网格时,请使用此函数。网格不会被视景体或烘焙的遮挡器进一步剔除,也不会针对透明度或 z 效率进行排序。

带参数缓冲区bufferWithArgs必须在给定的argsOffset偏移量处有五个整数:每个实例的索引计数、实例计数、起始索引位置、基本顶点位置、起始实例位置。

如果网格内的子网格具有不同的拓扑(例如三角形和线),Unity 才需要 submeshIndex 参数。否则,有关要绘制哪个子网格的所有信息都来自 bufferWithArgs 参数。

以下脚本可用于绘制同一网格的多个实例

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour { public int instanceCount = 100000; public Mesh instanceMesh; public Material instanceMaterial; public int subMeshIndex = 0;

private int cachedInstanceCount = -1; private int cachedSubMeshIndex = -1; 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() { // Update starting position buffer if (cachedInstanceCount != instanceCount || cachedSubMeshIndex != subMeshIndex) UpdateBuffers();

// Pad input if (Input.GetAxisRaw("Horizontal") != 0.0f) instanceCount = (int)Mathf.Clamp(instanceCount + Input.GetAxis("Horizontal") * 40000, 1.0f, 5000000.0f);

// Render Graphics.DrawMeshInstancedIndirect(instanceMesh, subMeshIndex, instanceMaterial, new Bounds(Vector3.zero, new Vector3(100.0f, 100.0f, 100.0f)), argsBuffer); }

void OnGUI() { GUI.Label(new Rect(265, 25, 200, 30), "Instance Count: " + instanceCount.ToString()); instanceCount = (int)GUI.HorizontalSlider(new Rect(25, 20, 200, 30), (float)instanceCount, 1.0f, 5000000.0f); }

void UpdateBuffers() { // Ensure submesh index is in range if (instanceMesh != null) subMeshIndex = Mathf.Clamp(subMeshIndex, 0, instanceMesh.subMeshCount - 1);

// Positions if (positionBuffer != null) positionBuffer.Release(); positionBuffer = new ComputeBuffer(instanceCount, 16); Vector4[] positions = new Vector4[instanceCount]; for (int i = 0; i < instanceCount; i++) { float angle = Random.Range(0.0f, Mathf.PI * 2.0f); float distance = Random.Range(20.0f, 100.0f); float height = Random.Range(-2.0f, 2.0f); float size = Random.Range(0.05f, 0.25f); positions[i] = new Vector4(Mathf.Sin(angle) * distance, height, Mathf.Cos(angle) * distance, size); } positionBuffer.SetData(positions); instanceMaterial.SetBuffer("positionBuffer", positionBuffer);

// Indirect args if (instanceMesh != null) { args[0] = (uint)instanceMesh.GetIndexCount(subMeshIndex); args[1] = (uint)instanceCount; args[2] = (uint)instanceMesh.GetIndexStart(subMeshIndex); args[3] = (uint)instanceMesh.GetBaseVertex(subMeshIndex); } else { args[0] = args[1] = args[2] = args[3] = 0; } argsBuffer.SetData(args);

cachedInstanceCount = instanceCount; cachedSubMeshIndex = subMeshIndex; }

void OnDisable() { if (positionBuffer != null) positionBuffer.Release(); positionBuffer = null;

if (argsBuffer != null) argsBuffer.Release(); argsBuffer = null; } }

以下曲面着色器可用于与上述示例脚本结合使用

          Shader "Instanced/InstancedSurfaceShader" {
    Properties {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

CGPROGRAM // Physically based Standard lighting model #pragma surface surf Standard addshadow fullforwardshadows #pragma multi_compile_instancing #pragma instancing_options procedural:setup

sampler2D _MainTex;

struct Input { float2 uv_MainTex; };

#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED StructuredBuffer<float4> positionBuffer; #endif

void rotate2D(inout float2 v, float r) { float s, c; sincos(r, s, c); v = float2(v.x * c - v.y * s, v.x * s + v.y * c); }

void setup() { #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED float4 data = positionBuffer[unity_InstanceID];

float rotation = data.w * data.w * _Time.y * 0.5f; rotate2D(data.xz, rotation);

unity_ObjectToWorld._11_21_31_41 = float4(data.w, 0, 0, 0); unity_ObjectToWorld._12_22_32_42 = float4(0, data.w, 0, 0); unity_ObjectToWorld._13_23_33_43 = float4(0, 0, data.w, 0); unity_ObjectToWorld._14_24_34_44 = float4(data.xyz, 1); unity_WorldToObject = unity_ObjectToWorld; unity_WorldToObject._14_24_34 *= -1; unity_WorldToObject._11_22_33 = 1.0f / unity_WorldToObject._11_22_33; #endif }

half _Glossiness; half _Metallic;

void surf (Input IN, inout SurfaceOutputStandard o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }

以下定制着色器可用于与上述示例脚本结合使用

          Shader "Instanced/InstancedShader" {
    Properties {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
    }
    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" #include "UnityLightingCommon.cginc" #include "AutoLight.cginc"

sampler2D _MainTex;

#if SHADER_TARGET >= 45 StructuredBuffer<float4> positionBuffer; #endif

struct v2f { float4 pos : SV_POSITION; float2 uv_MainTex : TEXCOORD0; float3 ambient : TEXCOORD1; float3 diffuse : TEXCOORD2; float3 color : TEXCOORD3; SHADOW_COORDS(4) };

void rotate2D(inout float2 v, float r) { float s, c; sincos(r, s, c); v = float2(v.x * c - v.y * s, v.x * s + v.y * c); }

v2f vert (appdata_full v, uint instanceID : SV_InstanceID) { #if SHADER_TARGET >= 45 float4 data = positionBuffer[instanceID]; #else float4 data = 0; #endif

float rotation = data.w * data.w * _Time.x * 0.5f; rotate2D(data.xz, rotation);

float3 localPosition = v.vertex.xyz * data.w; float3 worldPosition = data.xyz + localPosition; float3 worldNormal = v.normal;



float3 ndotl = saturate(dot(worldNormal, _WorldSpaceLightPos0.xyz)); float3 ambient = ShadeSH9(float4(worldNormal, 1.0f)); float3 diffuse = (ndotl * _LightColor0.rgb); float3 color = v.color;

v2f o; o.pos = mul(UNITY_MATRIX_VP, float4(worldPosition, 1.0f)); o.uv_MainTex = v.texcoord; o.ambient = ambient; o.diffuse = diffuse; o.color = color; TRANSFER_SHADOW(o) return o; }

fixed4 frag (v2f i) : SV_Target { fixed shadow = SHADOW_ATTENUATION(i); fixed4 albedo = tex2D(_MainTex, i.uv_MainTex); float3 lighting = i.diffuse * shadow + i.ambient; fixed4 output = fixed4(albedo.rgb * i.color * lighting, albedo.w); UNITY_APPLY_FOG(i.fogCoord, output); return output; }

ENDCG } } }