I’m working on a project where I need to send a lot of data to a material (on the order of 64floats). The material will be used on an actor either with a static mesh, or skeletal mesh.
Data is changing per-frame, and so it is important that data is being transmitted from the CPU to the GPU efficiently.
Custom Primitive Data is apparently an efficient approach, however there is a hard limit of 32 floats. So that is not a viable option.
A dynamic material instance should work, but CPU->GPU communication doesn’t seem very performant when that much data is being updated every tick.
Does anyone know of a good approach? Are there any other better approaches?
Try a Material Parameter Collection. You can send a bundle of 1k scalars + 4vecs to the GPU. You can reference these values like external-variables inside your materials.
As well, you can do whatever on the CPU and write updated values to the MPC so you can adjust whatever you tie into these numbers.
I use these all over and it make it very easy to organize. I can have all my ‘Environment’ stuff like time of day, rainyness, snowyness, etc as well as the scalingins for all my landscape textures, etc… Even things in a heightmesh material like a Time node, can be replicated by updating the MPC every tick.
Quite honestly I don’t think that an MPC can transmit enough data for my usecase.
I need roughly 64 floats per object I have in the world (using my material).
That ends up hitting a hard limit of 80 objects as I need each object to be addressing a unique portion of the MPC.
There’s also the difficulty that I don’t believe I can easily change which region of the MPC I’m addressing in my material.
Yeah so an MPC has more than enough capacity for one object. I’ve already got a BP object to attach to the primitives and keep track of their stuff. The main issue is that it doesn’t seem possible to create MPCs dynamically.
Ideally, I would want an MPC per object, and then I would pass a reference to that MPC to the material. However, it doesn’t seem that new MPCs can be created at runtime.
I am storing lighting data. I’m working on material-based lighting.
OP was on the right path here I think. As far as I’m aware the fastest way to pass a large amount of dynamic values to a material would be via a texture lookup. 64 floats could easily be encoded in an 8x8 RGB image. You can write values to render targets using blueprints, and then read those values in the material.
Yeah, so my approach ended up being writing the data to a render target.
There’s a good amount of possible optimization that can be done to make writing to the render target faster, but the general gist of the issue is:
render target needs to be written to from render thread / game thread (if I remember correctly).
but we want to perform the minimal amount of computation within the renderthread/gamethread. Ideally we’d want to perform everything in a background thread.
So what we do is we create a new memory buffer that’s the same size as the render target, and we perform all computations on a background thread.
Then on the render thread it’s just a matter of locking the render target, memcpy, and then unlocking.
I don’t have any of my old code, so hopefully this helps enough. But feel free to ask any questions