I just realized this technique has a limitation that makes it unsuitable for my use case. Because the X/Y/Z particle coordinates come from a texture sample lookup, they are limited to an integer range of 0-255 on each axis. So you only have 256 discrete positions available in each direction. This results in some pretty severe quantization/aliasing errors.
You can see this effect if you load and run the project and press the up arrow to move “inside” the bunny, then look around. You’ll find a lot of places where the particles line up in neat horizontal/vertical/diagonal lines, like this:
I experimented using a .png file with 16-bit depth instead of 8-bit as in the original, but when I import it into UE4 and try to set the compression settings, it still only offers me “VectorDisplacementmap(RGBA8)”. I was hoping to see something like an RGBA16 option there. (I must confess that I didn’t actually test this further to see if I was getting 16-bit precision.)
Even 16 bit resolution wouldn’t be perfect. That would give 65,536 discrete positions in each axis. Maybe good enough, but I bet there would still be some aliasing. What I really want to do is take an array of Float3’s (or Vector3’s or whatever Unreal likes to call them) and use that as the lookup table instead of the TextureSample that our material uses now.
One roundabout way to accomplish this would be generate not just one lookup texture, but two or even three or four, where one texture has the low-order 8 bits for each axis, the next texture has the next-higher-order 8 bits, and if we want more than 16 bits of precision we keep going from there. Then instead of just the single texture lookup that the material uses now, we also have lookups for each additional 8 bits of precision, doing some bit shifting after the lookups to combine each 8-bit slice into the final coordinate.
As I think about it, I’m pretty sure that could be made to work. I’m just wondering if there might be a much simpler approach using a single linear array of Float3 coordinates. If I were writing this from scratch I know that’s how I would want to do it, but I’m trying to find a way that works in Unreal’s material system.
Any ideas are most welcome! In the meantime I may experiment with this multiple-texture idea.