Hi! I’ve been throwing myself at this problem for the last few days but I can’t find enough information to work out where I’m going wrong.
I’m trying to reduce draw calls on a project by using GPU Instancing which was simple enough but this broke down as soon as I had multiple materials. To work around this I found a few good references about using “Material Property Blocks” (Rendering 19) to help batch the same objects together. I have this working perfectly for ints and floats within the script / shader but when trying to pass custom textures this broke down. I’ve been looking at Tikkub’s post here:
https://www.reddit.com/r/Unity3D/comments/6uueox/gpu_instancing_texture2darray/
They use a 2D texture array to batch textures. After trying the same thing I don’t get the same result, the objects aren’t batching anymore. Would love some advice on what I’ve missed.
Image below showing, No textures 22 calls, with textures 742 calls.
Game Object Script
using UnityEngine;
public class GPUInstancingTest : MonoBehaviour
{
public Transform mesh;
public Material material;
private MaterialPropertyBlock Props;
public Color Color1, Color2;
public Color emissionColor;
public int instances = 5000;
public float radius = 50f;
public Texture2D[] textures;
int textureWidth = 1024;
int textureHeight = 1024;
void Start()
{
Props = new MaterialPropertyBlock();
Texture2DArray textureArray = new Texture2DArray(textureWidth, textureHeight, textures.Length, TextureFormat.RGBA32, false);
//textureArray.Apply(false, true); //Didn't fix compression issue.
for (int i = 0; i < textures.Length; i++)
{
Graphics.CopyTexture(textures[i], 0, 0, textureArray, i, 0);
}
//Comment out below line. Everything batches but no textures at set.
Props.SetTexture("_MainTex", textureArray);
for (int i = 0; i < instances; i++)
{
Props.SetColor("_Color", Color1);
Props.SetFloat("_Glossiness", 0.0f);
Props.SetFloat("_Metallic", 5.0f);
Props.SetFloat("_OcclusionStrength", 0.0f);
Props.SetColor("_EmissionColor", emissionColor);
Props.SetInt("_TextureIndex", 1);
Transform t = Instantiate(mesh);
t.localPosition = Random.insideUnitSphere * radius;
t.SetParent(transform);
t.GetComponent<MeshRenderer>().SetPropertyBlock(Props);
}
for (int i = 0; i < instances; i++)
{
Props.SetColor("_Color", Color2);
Props.SetFloat("_Glossiness", 1.0f);
Props.SetFloat("_Metallic", 0.3f);
Props.SetFloat("_OcclusionStrength", 0.0f);
Props.SetInt("_TextureIndex", 0);
Transform r = Instantiate(mesh);
r.localPosition = Random.insideUnitSphere * radius;
r.SetParent(transform);
r.GetComponent<MeshRenderer>().SetPropertyBlock(Props);
}
for (int i = 0; i < instances; i++)
{
Props.SetColor("_Color", Color.green);
Props.SetFloat("_Glossiness", 0.5f);
Props.SetFloat("_Metallic", 1.0f);
Props.SetFloat("_OcclusionStrength", 0.0f);
Transform k = Instantiate(mesh);
k.localPosition = Random.insideUnitSphere * radius;
k.SetParent(transform);
k.GetComponent<MeshRenderer>().SetPropertyBlock(Props);
}
}
}
Shader
Shader "Custom/Example" {
Properties{
//---Core Properties---//
[Header(Core Properties)]
_Color("Color", Color) = (1,1,1,1)
_MainTex("Textures", 2DArray) = "" {}
_Glossiness("Roughness Strength", Range(0.0, 2.0)) = 1.0
_Metallic("Metallic Strength", Range(0.0, 2.0)) = 1.0
_OcclusionStrength("Occlusion Strength", Range(0.0, 2.0)) = 1.0
[Header(Emissive)]
_EmissionColor("Emission Color", Color) = (0,0,0)
}
SubShader
{
Tags
{
"Queue" = "Geometry"
"RenderType" = "Opaque"
}
LOD 300
ZWrite On
CGPROGRAM
#pragma surface surf Standard fullforwardshadows addshadow
#pragma target 3.5
#include "UnityCG.cginc"
UNITY_DECLARE_TEX2DARRAY(_MainTex);
UNITY_INSTANCING_BUFFER_START(Props)
half _Glossiness;
half _Metallic;
half _OcclusionStrength;
float4 _Color;
float _TextureIndex;
fixed4 _EmissionColor;
UNITY_INSTANCING_BUFFER_END(Props)
struct Input
{
float2 uv_MainTex;
};
void surf(Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(IN.uv_MainTex, UNITY_ACCESS_INSTANCED_PROP(Props, _TextureIndex))) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
fixed4 e = UNITY_ACCESS_INSTANCED_PROP(Props, _EmissionColor);
o.Albedo = c.rgb;
o.Emission = c.rgb;
o.Emission *= e.rgb;
o.Smoothness = (1 - UNITY_ACCESS_INSTANCED_PROP(Props, _Glossiness));
o.Metallic = UNITY_ACCESS_INSTANCED_PROP(Props, _Metallic);
o.Occlusion = UNITY_ACCESS_INSTANCED_PROP(Props, _OcclusionStrength);
}
ENDCG
}
FallBack "Diffuse"
}