Transcoding a CUDA demo to Unity

Howdy folks! So here’s a big one. Perhaps some lovely guru can help, but this might be a direct call for help from Aras.

I’m so close! I have a lot of material that I can post but I want to keep the first message light. First of all, here is my goal: I’m trying to implement this CUDA SDK demo in Unity using a DX11 compute shader. Its an old demo, so maybe there’s already some sweet-awesome new particle technique I should be trying, but I knew I had access to all the source so this was a good foray into compute shaders for the first time. Thankfully I’m pretty familiar with the CUDA SDK so parsing the example code wasn’t bad. I have to admit, I’m really not sure what code is responsible for spawning more particles around the cursor, but anyway here’s what I’ve gotten so far.

By the way there’s another issue in that scene which is that the terrain doesn’t really want to have nice textures. I’m really not sure what’s going on, even the standard terrain assets textures, on the terrain that comes out of “Create Terrain” everything’s all blurry. Anyway ignore that and focus on the particles. There’s 600K of them buzzing around there based on velocities sampled from a noise texture.

Here’s the first place where I got side-tracked and unfortunately let down. I happen to have a copy of Substance Designer that I never use. I created a quick noise texture (just clouds → diffuse). At first I wanted to use Substance to spit out a 3D texture, but it looks like there’s no path for that kind of thing, in Substance or Unity. I know I can create a 3D texture by stacking those clouds textures, but it seems that there’s no way to convert a ProceduralTexture to a Texture2D in order to sample the colors from the ProceduralTexture. Feature request! Think it would be easy enough to add a GetPixel function to ProceduralTextures?

So… next step: I just created a noise texture3D with Random.value’s and use that. The issue I have now is that I need to sample this texture with interpolation in the compute shader. Oh noes! tex3D() and object.SampleLevel() don’t work! I ran into an issue getting access to the built-in Samplers and one way or another gave up there. With a clever enough hack I got the random noise working OK, as you see in the video.

Finally, though, the reason my example doesn’t look like the CUDA video is that I can’t get the darn shader to work. It’s pretty complex, and, I’ll admit, it operates on some data that I’m not providing, but the positions at least are there. The issue, I think, is that the shader takes vertex positions and runs them through a geometry program that spits out quads. At least that’s the way it works in the sample. They labeled the geometry shader a “motion blur” shader which I guess creates a quad between the current position and the previous one.

Anyway I think my issue stems mainly from one of a few factors: The first is that I’m specifying a point cloud of vertices, not triangles, while trying to render quads. The second is that the smoke is rendered using Graphics.DrawProcedural as a camera shader. This is a technique borrowed from an example I’ve been following. I adapted the example to using a MeshRenderer so that I could see the particles in the scene and generally work better with the shader and stuff, but I found that there’s a hard cap on vertex count at 65,000. Since I’m looking to use something like millions of verts, I was hoping to avoid that cap.

Anyway this is what the “advanced” version of the shader looks like at the moment in Point and Triangle/Quad mode.

So, I’m happy to post some source code if this all sounds totally possible, and maybe I’m just screwing this up. I have to admit that I was a little fuzzy on exactly what transformation matrices to use in certain parts during the transcoding. I’m not exactly familiar with straight-up GLSL shaders and their parameters.

Any ideas about how I can render these particles with something other than Graphics.DrawProcedural?

So… I went back to using the MeshRenderer. Slightly better looking results but only slightly.