#Per entity unique vertex colors ?
1 messages · Page 1 of 1 (latest)
I can only imagine this working by using a shared graphics buffer or texture per n entities (per material) with assigned memory segments per entity. I do a lot of 'per entity data' for voxel stuff in this way.
but dealing with that memory assignment is the annoying part 😄
if you're using shader graph, you'd access the buffer data in a custom hlsl node
have you modified the entities graphics package for something similar, or is this using one of the DrawMesh_X methods? I realised after posting this that unique vertex colors in the traditional sense would clash with mesh instancing, but there are some techniques(vertex colors, rendertextures) that work on gameobjects that I am really missing. not using sg for my custom shader, and was looking at how instancing for deformations works wondering if there might be a similar trick for dealing with vert colors.
No package modifications or indirect draw calls. What I'm imaging is a custom shader that will look up a vertex colour from a GraphicsBuffer (StructuredBuffer or ByteAddressBuffer in the shader) in the vert shader. There would be a material property override to inform the shader where in the buffer to start reading the data from, so many objects can share one buffer (as assigning a different buffer would need a new material).
So in the C# side you would:
- create a
new GraphicsBuffer Material.SetBuffer- Assign segments of the buffer to entities that need custom colours, and write that
graphicsBufferStartIndexto the material (with aMaterialPropertyattribute on anIComponentDatawith an int field).
In the vert shader you would :
index = VertexID + GraphicsBufferStartIndex- use that as an index into the StructureBuffer (or ByteAddressBuffer) containing your custom colours.
You could have one colour per triangle (VertexId / 3), or one per vert, or whatever you wanted.
You could use a texture instead of a buffer too, but buffers allow for partial updates. You can do partial updates with textures too but it would involve sending a smaller texture and doing a Texture.Copy (I think) on the GPU side to update the sub region of the bigger texture.
Other than this, I'm not sure how to have per entity vertex data.
thanks for the ideas, kind of a lot for me to unpack but gonna make an attempt at doing some tests for this
as a very simple test, is this use of graphicsbuffer wrong?
public class VertexColorBehaviour : MonoBehaviour
{
public Color Color;
public Material Material;
private GraphicsBuffer m_GraphicsBuffer;
static readonly int k_VertexColorsBuffer = Shader.PropertyToID("_VertexColors");
private MeshRenderer m_Renderer;
public void OnEnable()
{
m_Renderer = GetComponent<MeshRenderer>();
}
public void Update()
{
if (m_Renderer == null)
return;
var colorsArray = new NativeArray<float4>(100, Allocator.TempJob);
CreateGraphicsBufferIfNeeded(ref m_GraphicsBuffer, 100, UnsafeUtility.SizeOf<float4>());
for (int i = 0; i < colorsArray.Length; i++)
{
colorsArray[i] = new float4(Color.r, Color.g, Color.b, Color.a);
}
m_GraphicsBuffer.SetData(colorsArray, 0, 0, colorsArray.Length);
m_Renderer.material.SetBuffer(k_VertexColorsBuffer, m_GraphicsBuffer);
colorsArray.Dispose();
}
public void OnDisable()
{
m_GraphicsBuffer?.Dispose();
}
private void CreateGraphicsBufferIfNeeded(ref GraphicsBuffer graphicsBuffer, int length, int stride)
{
if (graphicsBuffer != null && graphicsBuffer.count == length && graphicsBuffer.stride == stride)
return;
ReleaseGraphicsBuffer(ref graphicsBuffer);
graphicsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, length, stride);
//m_IsDisposed = false;
}
private void ReleaseGraphicsBuffer(ref GraphicsBuffer graphicsBuffer)
{
if (graphicsBuffer != null)
graphicsBuffer.Release();
graphicsBuffer = null;
}
}
simple vert color in maya on the right, unity shader on the left(using a simple output.color = input.color which is the mesh's vertex colors. however using output.color = _VertexColors[0] from uniform StructuredBuffer<float4> _VertexColors; is always black regardless of the color chosen in the above script
well I am an idiot, took me way too long to realise I didnt have ExecuteAlways and was testing outside of playmode