Normally I’m trying to post new achievements every Sunday, but I didn’t catch the train this week. So if you wonder where the screenshots are, I need a few more days. I’m pretty busy last weeks. Marriages, barbeques, birthdays, beer, and yesterday golfing between the cows on a milk farm. Busy at work as well, letting wireless microcontrollers talk with XBee and got to make this monster fully work & drive within a few weeks:
Anyway, I spent most programming hours this week on “Clothing”. No, not my shoes and pants, but physics to simulate curtains, sheets, flags, Batman's cape, etcetera. To be more specific, the motion caused by gravity, wind and collisions. Brrr… You should know that my math isn't exactly great. I know that 2 + 2 potatoes makes 4 potatoes, but that's about it. And as for physics, I know it hurts when an apple falls on your head. So.., that's why Newton does all the physics for me (not the guy, the physics engine --> http://newtondynamics.com/forum/newton.php).
Luckily I had some (old) nVidia SDK demo’s, and I ended up with a simple testprogram that produces pretty good results. Although it still moves a little bit like Princess silk. Stuff like this usually comes in several quality-degrees. From ridiculously realistic to Wolfenstein sprites. First there is the university paper wrote by maniacs; lots of Alien formula's, and awesome results... in theory... Then some handy people start implementing those idea's in practice. Finally “the less smarter” guys like me will copy them, hoping that we chose the right references. We don’t really know what we are doing, but hey, it works. My boss doesn’t care either if I understand the theory or not, as long as it works. Do you think I understand the hydraulics of the machine above? Ha, I can't even park it properly.
100% Princess silk, smooth as baby skin
Well that's a little bit dramatic, but since I only have a short amount of time (and attention span) for each individual technique, the way to get it working is usually by Googling for not-too-difficult demo's and maybe a paper. Luckily another blog helped me on my way: http://cg.alexandra.dk/tag/physics-based-animation/
I should give articles like these a "Rick-understood-it" tag. Really, if I can do it, so can you. I'm not a bad coder but the theory usually disappears 2 seconds after I heard it. Can't help it, that's just the way my 2KB storage brains works.
The final result is a mixture of the techniques I’ve seen, using the GPU (videocard processor). And with just a few passes, making it fast & simple. I never did physics on the GPU before, so that was a useful lesson for this week. Normally the CPU is used for collision and physics stuff, but since the GPU is a whole lot faster with vector calculations, it can be worth it to pass the stick. Only problem is that a GPU does not have direct access to your RAM memory. Which is usually the place where collision volumes, previous positions and scene parameters are stored. Instead textures are used to pass the data around:
• Create a grid of “particles”
Imagine them as tiny invisible balls that are affected by gravity, wind and collisions. And more important, those particles are connected with each other. Of course, your towels don't fall apart, now do they? Your math/shader will try to keep the particles together by maintaining a fixed distance between all particles.
• Render initial 3D positions of those particles to a texture.
That would be the curtain/flag in rest pose.
1.- Apply The Force
Apply gravity, wind and previous motion onto the particles, using previous result textures (initially from step 0). Use FBO's / Rendertargets to draw the results to another texture. Yep, your pixelshader will spit out 3D coordinates instead of colors. So, it's wise to use a 16 or 32 bit floating point buffer to store the results.
2.- Apply constraints
Check for collisions (with a few simple primitives that are nearby) and maintain a fixed distance between the particles. Use the texture from step 1 as input, and render to another texture for the results. Eventually repeat this step 1 or more times for a somewhat smoother result.
3.- Final render
Finally render the particle grid as a quad-strips or something. Render as usual, eventually with a BRDF for velvet material effects. The trick however is to replace the “default” vertices with the transformed vertex positions you calculated in step 1 & 2. You can read the texture from step 2 towards the CPU… or better… use “Vertex Fetch” (read the texture into the vertex-shader).
* Tip, batch things.
If you have 10 curtains, do not redo this whole process for each curtain again. Instead render all of them to the same (bigger) target textures. First do step 1 for all curtains, then step 2, and so on. Prevents a lot of shader & rendertarget switching.
The blue "velvet" gloss is just specular lighting. With an inversed normal. Got this result per accident...
The most difficult part in the end wasn’t the math, but getting the texture coordinates exactly right to retrieve the data from a texture. A slight offset will make your curtains fly around like pee in the ISS space station. Allright, enough difficult talk. Hopefully I can post some curtains in action one of these days.
This place sure could use some curtains