Hi Guys!
I’m trying to use Graphics.DrawMeshInstanced() to draw multiple times a set of 3 meshes with a different shader for each. These shaders are using Ztests and stencil.
My problem is: one of the meshes of the set is only drawn once (at the matrix array’s first value) although the 2 others - that use surface shaders and stencil test - are drawn perfectly at the right place, with their right instanced properties.
The set displays as i’d like with Graphics.DrawMesh or via a meshRendererComponent. So I’m led to think I’m missing a pragma or something to make GPU Instancing work on this shader?
I also tried with it’s CommandsBuffer’s equivalent, which gives weirder results. Indeed, new problems appear: the 2 other shaders only writes then in depth without writing color. Maybe, as they are surface shaders and contain many passes, that not all passes are called?
Monobehaviour calling the Draws: (bubbles is the so-called set, it’s a prefab sent to the monobehaviour)
public class InstancerUtil_DrawInstanced : MonoBehaviour
{
public bool debugArrayMode = false;
[Range(1, 100)]
public int _BubbleAmount = 10;
public Vector2 _scaleMinMax = new Vector2(0.5f, 1f);
public GameObject _Bubble;
public float _offs = 1f;
private List<Matrix4x4> _matrixArray;
private MaterialPropertyBlock[] _propBlock;
private Material[] _materials;
private Mesh[] _meshes;
// Use this for initialization
void Start()
{
_matrixArray = new List<Matrix4x4>();
// Bubbles Matrices
var prefabScale = _Bubble.transform.localScale;
for (int i = 0; i < _BubbleAmount; i++)
{
Vector3 randPos;
float Scale= .6f;
int j = (int)(Mathf.Sqrt(_BubbleAmount));
randPos = new Vector3(_offs + i % j, 0, (int)(i / j)); // _offs proves that it's not drawn at origin, as changing this value has an impact on the position of the only instance drawn.
_matrixArray.Add(Matrix4x4.TRS(randPos, Quaternion.AngleAxis(-90, Vector3.right), new Vector3(Scale, Scale, Scale))); // Quaternion because meshes were exported with bad rotation.
}
// Retrieve meshes and their material from prefab
int ChildCount = _Bubble.transform.childCount;
_materials = new Material[ChildCount];
_meshes = new Mesh[ChildCount];
for (int i = 0; i < ChildCount; i++)
{
var child = _Bubble.transform.GetChild(i);
_materials[i] = child.GetComponent<Renderer>().sharedMaterial;
_materials[i].enableInstancing = true;
_meshes[i] = child.GetComponent<MeshFilter>().sharedMesh;
}
// instanced Properties (works fine and there is nothing on the mesh.
_propBlock = new MaterialPropertyBlock[ChildCount];
Vector4[] colors = new Vector4[_BubbleAmount];
for (int i = 0; i < _BubbleAmount; i++)
{
if (!ApplyVariations)
{
colors[i] = Color.white;
}
else
{
float r = Random.Range(0.0f, 1.0f);
float g = Random.Range(0.0f, 1.0f);
float b = Random.Range(0.0f, 1.0f);
colors[i] = new Color(r, g, b);
}
}
for (int i = 0; i < ChildCount; i++)
{
_propBlock[i] = new MaterialPropertyBlock();
if(_materials[i].HasProperty("_Color"))
{
Debug.Log(_materials[i].name + "has property _Color");
_propBlock[i].SetVectorArray("_Color", colors);
}
}
// Add CommandBuffer:
var cam = Camera.main;
if (!cam)
{
Debug.Log("no cam selected");
return;
}
CommandBuffer buf = new CommandBuffer();
buf.name = "Bubbles";
for (int i = 0; i < _meshes.Length; i++)
{
buf.DrawMeshInstanced(_meshes[i], 0, _materials[i], -1, _matrixArray.ToArray(), _BubbleAmount, _propBlock[i]);
}
cam.AddCommandBuffer(CameraEvent.BeforeDepthNormalsTexture, buf);
Debug.Log(cam);
}
void Update()
{
for (int i = 0; i < _meshes.Length; i++)
{
Graphics.DrawMeshInstanced(_meshes[i], 0,
_materials[i],
_matrixArray.ToArray(),
_BubbleAmount,
_propBlock[i],
UnityEngine.Rendering.ShadowCastingMode.Off, false, 0, Camera.main);
}
}
}
Bad shader:
Shader "Coffee/Bubbles/StencilShader"
{
Properties
{
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
Cull Back
ZTest Always
Stencil{
Ref 1
Comp Always
Pass Replace
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
UNITY_INSTANCING_CBUFFER_START(Props)
UNITY_INSTANCING_CBUFFER_END
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return (fixed4)1;
}
ENDCG
}
Pass{ }
}
}