Gpucaster Version: 1.35 Release Date: 25 May 2015 Author: Ryan Geiss Website: http://www.geisswerks.com/ REQUIREMENTS: - A Win7 (or later) PC with a beefy GPU. - Some 3D math skills - Basic knowledge of how to edit a pixel shader to make it do math stuff. - [*Optional*] Microsoft Visual C++ 2008 or later (this is a free download) (...You do NOT need this if all you want to do is make new worlds by modifying the "eval.hlsl" pixel shader, which is what most people will likely do. You only need this if you want to modify the source code and then rebuild bin/gpucaster.exe.) DISCLAIMER: This thing barely works. And the code is an absolute mess. WHAT IS THIS THING: It renders arbitrary 3D "isofunctions" using a pixel shader. The mouse controls the camera, and the pixel shader function controls the shape of the world. The "eval()" function in the main pixel shader (shaders/eval.hlsl) receives a 3D coordinate as input, and its job is to return a value that is either positive or negative; a positive value means there is something there (rock, surface, whatever); a negative value means there is nothing there (it's open air). The program takes care of the rendering and lighting for you. There are generally 3 phases to the rendering: first, it solves for the surface depths; then the surface normals; and finally, ambient occlusion (a hack for quickly producing semi-realistic lighting). After that, if you like, you can repeat the 3 phases for a single bounce of reflected rays. The whole thing runs at interactive rates (normal resolution) or, usually, renders in ~2-30 minutes (for high-resolution stills, say, 20 - 50 megapixels), depending on the complexity of the shader. BRIEF TUTORIAL: 1. Run gpucaster_tile_size_32.bat (for now; later, we'll come back to this step, and find the optimal version for you to run, for best performance). 2. (Wait for it to load; depending on the contents of shaders/eval.hlsl, it can take up to a minute or two.) 3. Once it's loaded, the titlebar will start animating - you'll see something like: "GpuCaster - 1.0 MP - ### x ### - ss:1 - [MAIN] passes:[G=###, A=0] ...o. 4. Use the mouse + left button to rotate the camera. Use the right button (and drag up) to zoom in and out a bit. (Often, the camera starts out embedded in the fractal surface, and you have to zoom out a little in order to see anything.) Use CTRL + left mouse button to roll the camera. 5. Each time you move the camera, rendering resets, and you'll see the scene quickly rebuild itself; the "G=" value in the window title will tell you how many geometric refinement passes over the scene have been done (since the last camera move or window resize). 6. Go ahead and resize the window now, to the size you want. Notice how G=### resets to 0, and starts ticking up again. It's doing pass after pass over the scene, trying to refine the depth of the closest intersection, by testing some random points, and also checking the (slightly-perturbed) depths of the closest intersection found for neighbor pixels. 6b. Hit H. This is the help screen, which tells you all the keyboard shortcuts. It'll be handy. Do a quick scan over it, then go ahead and dismiss it. 7. Let the G= number get up to about 40 (for a simple scene), then hit N. Now we're generating surface normals. If we let the geometry refine itself enough, then the normals should look nice and smooth (because we are sampling the normals at points that are really on the surface, rather than slightly embedded inside it). If you see any sparkly pixels here, you might want to hit 'G' again, let it refine a while more, and then hit N again. 8. Once a full pass over the scene is done, in N mode (which is usually quick), the titlebar will say "[idle]". 9. At this point, hit A. This mode is the slowest; it's generating ambient occlusion rays coming out from each pixel, going in all directions, and keeping track of what % of these rays (at each pixel) hit something. This information is then used to help in shading. The scene usually looks pretty decent after about 10 passes of ambient occlusion rays. 10. Hit ESC to stop, once you're satisfied you have enough ambient occlusion samples. 11. Then wait for the titlebar to say "idle" again. 12. [optional] Now hit 'F'. You've gone into reflections mode! - Notice how 'G' is going up again. - Let it go to about 40 or so, then do N, then do A; let it go to 10, then hit ESC to stop it. - You might or might not *see* the reflections yet - it depends on whether the current surface is reflective or not. To make it reflective, see below. 12b. Now hit F1 or F2 a bunch of times. You can cycle through the different visualization modes. (F1 = previous, F2 = next) Some show the depth, some show frac(depth * 100) (so you can see tiny variations in depth), some show the normals, frac(normals * 100), the ambient occlusion, the reflectivity, or the final rendered color (recommended). 13. Hit L a few times. This is randomizing the light locations, directions, and colors; the fog color and thickness; the surface reflectivity; and so on. 14. Hit CTRL+L. The lighting dialog that pops up can be used to refine the lighting. You can also load or save the dialog's settings, or the whole scene! - Import lights only: loads the lights (only) from an old saved scene. - Import seed, lights, camera: loads the lights, the random number seed, and the camera position and orientation from a saved scene. (**However, note that if eval.hlsl has changed, the scene will no longer look the same.) - Export seed, lights, camera: save everything to a scene file. 15. Also notice the 'Mouse rotates all lights' and 'Mouse moves camera' buttons. Click the former to go into a mode where the mouse rotates the lights (and camera is frozen), and the latter to go back to the normal mode, where the mouse moves the camera (and resets rendering). 16. Notice how you can play with the lights during rendering, including rotating them, and it updates at super-fast framerates! 17. The actual geometric surface is defined in shaders/eval.hlsl. This file is huge, with tons of old pieces of code disabled using "if 0". Look near the very bottom for the latest snippet that is not disabled, and you'll (likely) see what is producing the current scene. The main idea here is that you give this function ("eval") a point in 3D space ("float3 ws" for world-space coordinate), and it returns two things: a. ret.density: A float value, which, if positive, identifies solid material; if negative, identifies air. b. ret.surface_color: A float3 value, identifying the color of the surface there. (Note: This only shows up if the 'Surface coloration' slider in the lighting dialog is cranked up a little.) c. ret.reflectivity: A float value [0..1], identifying how reflective this point is. (Note: This only shows up if the 'Reflectivity' slider in the lighting dialog is cranked up a little.) Also notice the 'ws_pixel_size' value we compute near the top of the function. This tells you, at the depth of the point being evaluated, how large (in world-space) a pixel is. (This is handy for computing things up until the nyquist limit, but not beyond - to avoid aliasing.) You'll see lots of common tricks in the file. For example, "ret.density -= ws.y;" adds a ground plane. You'll also see lots of use of functions like RotatePointAboutAxis(), which uses quaternions to rotate a point about the origin along a given axis (...to rotate about another point, just pre-subtract and post-add that point). You'll also see use of a function called OctaveNoise. This function generates 3D noise for the input coordinate, adding many octaves of noise together (up to the nyquist limit -- assuming you pass it the proper ws_pixel_size value). CAUTION: The OctaveNoise function is very powerful, and executes quickly, BUT compiles very slowly. Whenever you start the program, it'll take a bit of time as the shaders compile, and several of them #include eval.hlsl; if it has any active calls to OctaveNoise() in it, the compilation will slow way down. After making changes to eval.hlsl, you can hit F5 to reload the shaders; again, there will be a big pause here while shaders compile. You usually then want to hit 'C' to clear the rendering and start over (in non- reflection, geometry-refinement mode). 18. Once you've tweaked eval.hlsl and the lighting and you love your scene, SAVE IT (using the lighting dialog). Then hit SHIFT+4. Notice that the resolution reported in the title bar is now 4x4 times larger than it was. You're rendering a huge print now (so it'll be slower). The largest you can go is 9x on each axis (SHIFT+9), with a maximized window; but make sure your GPU has plenty of RAM. If you exceed it, then rendering will suddenly slow way down (as it uses system RAM as a substitute), or it might just crash (depending on the quality of your video driver). Also note that some graphics cards can't go about a 8192 x 8192 render target, so you might want to stay below that limit. (That's 64 megapixels, so it should still be plenty.) Hit Z a few times, and watch the area around the mouse cursor; this will zoom you into 1:1 pixel detail, so you can see if the stage you're currently rendering is actually finished or not. When your render is complete, hit CTRL+S to save a screenshot to the 'screenshots' subdirectory. (Tip: If you also place a copy of rar.exe in the 'bin' directory, then it'll also zip up the current executable, shaders, etc. and save that alongside the image -- so you'll always be able to recreate the shot if you want it.) Note that ESC does not exit the program (because doing that on accident can be a major bummer); it just stops the rendering. To exit, you have to close the window with ALT+F4 or the 'x' in the upper-right corner. 19. Remember how we launched the program using the 'gpucaster_tile_size_32.bat' file? Now would be a good time to see if that's a good fit for your GPU or not. There are a bunch of batch files in the main folder, with different numbers. The number identifies the size (N) of the N-by-N-pixel tiles that the program will render, and getting it right can drastically affect shader performance. In general, you want to start with a low number, and work your way up. If you choose a value too low, the rendering speed will be greatly reduced; however, if you choose a value too high, your system might become very bogged down and the UI can be slow to respond. Therefore, start with small values, and as your system stays highly responsive, try the next higher value. If/when the system (overall) begins to feel less responsive, drop it back down a notch. Good starting guesses (as of January 2014) are: new $500 desktop GPU tile_size -> 160 (or higher) new $100 desktop GPU tile_size -> 64 good laptop GPU tile_size -> 32 poor laptop GPU tile_size -> 16 ...and for every 2 years after 2014, multiply the value by 2 (up to 256). 20. Have fun! I'd like to offer my sincere apologies that this thing is such a mess (the code, shaders, and tutorial); I never really intended to release it, it was just a fun side project (often worked on in 30-minute chunks, mostly throughout 2010). Best regards, Ryan Geiss http://www.geisswerks.com/