I’m currently trying to write a render feature which runs a compute shader on mesh vertex buffer data from the various visible renderers in the scene but I’m having troubles.
I’m hoping to run a compute shader with a single readwrite input/output buffer as to transform the vertex data of meshes on the GPU. The effect I’m going for is similar to what vertex shaders do but in my case I cannot use vertex shaders. The effects I am going for need to be independent of materials and their shaders.
I’ve been reading other forum posts and unity documentation and this seems like something that is possible, but maybe not in the way I’m doing it. Currently, to collect and modify mesh data I’m thinking about doing something like this :
HashSet<Mesh> visibleMeshHashSet = new HashSet<Mesh>(
FindObjectsOfType<MeshRenderer>()
.Where(mr => mr.isVisible)
.Select(mr => mr.GetComponent<MeshFilter>())
.Where(mf => mf != null)
.Select(mf => mf.sharedMesh)
.Where(m => m != null)
);
foreach (Mesh m in visibleMeshHashSet)
{
GraphicsBuffer vertexGBuffer = m.GetVertexBuffer(0);
int vertexCount = m.vertexCount;
CommandBuffer cmd = CommandBufferPool.Get("Distort Vertex Data");
///////////////
cmd.SetComputeBufferParam(computeShader, kernelIndex, "vertexBuffer", vertexGBuffer);
cmd.DispatchCompute(computeShader, kernelIndex, Mathf.CeilToInt(vertexCount / 128.0f), 1, 1);
///////////////
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
I am worried about the performance of a per-frame call of collecting visible meshes this way. It feels like there should be a better way to get such data.
In other render features / passes there’s culling results used in the form ctx.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings)
. It seems in the past this ‘renderingData’ stuff could be used to get visible renderers but not anymore, or at least not to my understanding.
Any help would be appreciated
Unfortunately I realized there was one thing I’ve been doing wrong. I’m using the MeshFilter sharedMesh property which I should have realized. It is not per-instance. It’s stored on the GPU and used by multiple objects. Modifying that will modify every copy in the exact same way. This is fine for some effects but more sophisticated modifications that use things like world position would not be possible.
This does make me wonder how things like vertex shaders achieve the effects that they do. They can transform vertices based on properties that are indeed connected to the instance that is using them. This makes me think that the offset data must be stored somewhere on the GPU separate from the vertexbuffer data?
I think I have some more research to do. If anyone has any insights I would love to hear them.
I’ve updated the question to better phrase what I’m trying to do. I’m trying to use a compute shader to modify mesh vertex data either before or after the vertex shader. I’m wondering if this is possible.
Something like :
Vertex Data → Compute Shader → Vertex Shader → Fragment Shader
or
Vertex Data → Vertex Shader → Compute Shader → Fragment Shader
In my mind this feels like it should be possible as long as I take careful consideration of the data types and buffer sizes between inputs and outputs of each phase. I’ve made some render features before, but nothing this intrusive.
I’ve read a little about geometry shaders but the main thing is that I want this process to be somewhat global. For example, if one wanted to oscillate the vertices of every mesh currently in view of cameras regardless of material shaders. I feel a simple compute shader inserted into the pipeline that modifies the vertex GPU data before rendering would do just that.
I’ve thought a lot about just giving up and modifying meshes and pushing their vertex buffers to cpu but it just isn’t as elegant or performant. All that buffer data should be right there on the GPU already being processed and I just want to add one more process step that maps vertexdata->vertexdata.
There’s no way to insert a compute dispatch between the vertex and fragment stages.
I suppose your only option is to modify the vertex shaders to apply your animation.