Sunday, April 1, 2012
April 1st CIS565 Progress Summary: Camera and Pathtracing
Over the past few days, Peter and I established our framework, got random number generation working on the GPU, built an accumulator, figured out parallelized camera ray projection, got spherical intersection tests working, and got a basic path-traced image!
Here are the posts for this update:
1. Random Number Generation: Fun with parallelized random number generators and seeding
2. First Rays on the GPU: Parallel raycasting!
3. Accumulating Iterations: The heart of any monte-carlo based renderer
4. We Have Path Tracing: First working renders!
Here's an image from our very first working render! More soon!
Tuesday, March 27, 2012
CIS563/CIS565 Final Project Github Repos!
For both MultiFluids and the GPU Pathtracer, we will be making our source code accessibly to all on Github!
Of course commercial coding projects and whatnot have very good reasons for keeping their source code locked down and proprietary, but open source is something I very strongly believe in. Open code allows other people to see what one does and give feedback and suggestions for improvement, and also allows other people interested in similar projects to potentially learn and build off of. Everybody wins!
The MultiFluids repository can be found here: https://github.com/betajippity/MultiFluids
The GPU Pathtracer repository can be found here: https://github.com/peterkutz/GPUPathTracer/
GPU Pathtracer: http://gpupathtracer.blogspot.com/2012/03/github-repository.html
MultiFluids: http://chocolatefudgesyrup.blogspot.com/2012/03/github-and-windowsosx.html
Monday, March 19, 2012
CIS563/CIS565 Final Projects: Multiple Interacting Fluids and GPU Pathtracing
Monday, March 12, 2012
Pathtracer with KD-Tree
Here's a cow in a Cornell Box. Each iteration of the cow took about 3 minutes, which is a huge improvement over my old raytracer, but still leaves a lot of room for improvement:
...and of course, the obligatory Stanford Dragon test. Each iteration took about 4 minutes for both of these images (the second one I let converge for a bit longer than the first one), and I made these renders a bit larger than the cow one:
So! Of course the KD-Tree could still use even more work, but for now it works well enough that I think I'm going to start focusing on other things, such as more interesting BSDFs and other performance enhancements.
Sunday, March 11, 2012
First Pathtraced Image!
Granted, the actual image is not terribly interesting- just a cube inside of a standard Cornell box type setup, but it was rendered entirely using my own pathtracer! Aside from being converted from a BMP file to a PNG, this render has not been modified in any way whatsoever outside of my renderer (I have yet to name it). This render is the result of a thousand iterations. Here are some comparisons of the variance in the render at various iteration levels (click through to the full size versions to get an actual sense of the variance levels):
![]() |
| Upper Left: 1 iteration. Upper Right: 5 iterations. Lower Left: 10 iterations. Lower Right: 15 iterations. |
![]() |
| Upper Left: 1 iteration. Upper Right: 250 iterations. Lower Left: 500 iterations. Lower Right: 750 iterations. |
Each iteration took about 15 seconds to finish.
Unfortunately, I have not been able to move as quickly with this project as I would like, due to other schoolwork and TAing for CIS277. Nonetheless, here's where I am right now:
Currently the renderer is in a very very basic primitive state. Instead of extending my raytracer, I've opted for a completely from scratch start. The only piece of code brought over from the raytracer was the OBJ mesh system I wrote, since that was written to be fairly modular anyway. Right now my pathtracer works entirely through indirect lighting and only supports diffuse surfaces... like I said, very basic! Adding direct lighting should speed up render convergence, especially for scenes with small light sources. Also, right now the pathtracer only uses single direction pathtracing from the camera into the scene... adding bidirectional pathtracing should lead to another performance boost.
I'm still working on rewriting my KD-tree system, that should be finished within the next few days.
Something that is fairly high on my list of things to do right now is redesign the architecture for my renderer... right now, for each iteration, the renderer traces a path through a pixel all the way to its recursion depth before moving on to the next pixel. As soon as possible I want to move the renderer to use an iterative (as opposed to recursive) accumulated approach for each iteration (slightly confusing terminology, here i mean iteration as in each render pass), which, oddly enough, is something that my old raytracer already does. I've already started moving towards the accumulated approach; right now, I store the first set of raycasts from the camera and reuse those rays in each iteration.
One cool thing that storing the initial ray cast allows me to do is to generate a z-depth version of the render for "free":
Okay, hopefully by my next post I'll have the KD-tree rewrite done!
Wednesday, March 7, 2012
Smoke Sim: Preconditioning and Huge Grids
One more thing: rendering this thing. So far I have not been doing any fancy rendering, just using the default OpenGL render that our framework came with. However, I want to get this into my volumetric renderer at some point and maybe even try out the pseudo-black body stuff with it. Eventually I want to try rendering this out with my pathtracer too!
Saturday, March 3, 2012
Smoke Simulation Basics!
I won't go into the nitty-gritty details of the math behind the simulation (for that, consult the Bridson notes), but I'll give a quick summary. Basically, we start with a specialized grid structure called the MAC (marker and cell) grid, where each grid cell stores information relevant to the point in space the cell represents, such as density, velocity, temperature, etc. We update values across the grid by pretending a particle carried the cell's values into the cell and using the velocity to extrapolate in time the particle's previous position, and look up the values from the grid cell the particle was previously in. We then use that information to perform advection and projection and solve the system through a preconditioned conjugate gradient solver.
So far I have implemented density advection, projection, buoyancy (via temperature advection), and vorticity. For the integration scheme I'm just using basic Eularian, which was the default for the framework we started with. Eularian seems stable enough for the smoke sim, but I might try to go ahead and implement RK4 later anyway, since I suspect RK4 won't smooth out details as much as basic Eularian.
I'm still missing the actual preconditioner, so for now I'm only testing the simulation on a 2D grid, since otherwise the simulation times will be really really long.
Saturday, February 25, 2012
Jello Sim Maya Integration
Well, sort of.
Instead of building a full Maya plugin like my good friend Dan Knowlton did, I opted for a simpler approach: I write out the vertex positions for each jello cube for each time step to a giant text file, and then use a custom Python script in Maya to read the vertex positions from the text file and animate a cube inside of Maya. It is a bit hacky and not nearly as elegant as the full-Maya-plugin approach, but it works in a pinch.
I think beng able to integrate my coding projects into artistic projects is very important, since at the end of the day, the main point of computer graphics is to be able to produce a good looking image. As such, I thought putting some jello into my kitchen scene would be fun, so here is the result, rendered out with Vray (some day I want to replace Vray with my own renderer though!):
The rendering process I'm using isn't perfect yet... the fact that the jello cubes are being simulated with relatively few vertices is extremely apparent in the above video, as can be seen in how angular the edges of the jello become when it wiggles. At the moment, I can think of two possible fixes: one, simple run the simulation with a higher vertex count, or two, render the jello as a subdivision surface with creased edges. Since the second option should in theory allow for better looking renders without impacting simulation time, I think I will try the subdivision method forst.
But for now, here are some pretty still frames:



Saturday, February 18, 2012
Multijello Simulation
Saturday, February 4, 2012
Pathtracer Time
Here's my project abstract:
Both path tracing and bidirectional scatter distribution functions (BSDFs) are ideas that have existed within the field of computer graphics for many years and have seen numerous implementations in a variety of rendering pack- ages. Similarly, creating images of convincing plant life is a technical challenge that a host of solutions now exist for. However, achieving dynamic plant effects such as the change of a plants coloring during the transition from summer to fall is a task that to date has been mostly been accomplished using procedural techniques and various compositing tricks.
The goal of this project is to build a path tracing based renderer that is designed specifically with the intent to facil- itate achieving dynamic plant effects with a more physically based approach by introducing a new time component to the existing bidirectional scatter distribution model. By allowing BSDFs to vary over not only space but also over time, plant effects such as leaf decay could be achieved through shaders with appearances that are driven through physically based mathematical models instead of procedural techniques. In other words, this project has two main prongs: develop a robust path tracer with at least basic functionality, and then develop and implement a time- dependent BSDF model within the path tracer.
...and here's some background that I wrote up for my proposal...
1. INTRODUCTION
Efficiently rendering convincing images with direct and indirect lighting has been a major problem in the field of computer graphics since the field’s very inception, as con- vincingly realistic graphics in games and movies depends upon lighting that can accurately mimic that of reality. Known generally as global illumination, the indirect light- ing problem has in the past decade seen a number of solu- tions such as path tracing and photon mapping that can generate convincingly realistic images with reasonable computational resource consumption and efficiency.
One of the key discoveries that enabled the development of modern global illumination techniques is the concept of Bidirectional Scattering Distribution Functions, or BSDFs. Developed as a superset and generalization of two other concepts known as bidirectional reflectance distribution functions (BRDFs) and bidirectional transmittance distribu- tion functions (BTDFs), BSDF is a general mathematical function that describes how light is scattered by a certain surface, given the material properties of the surface. BSDFs are useful today for representing the material properties of an object at a single point in time; however, in reality mate- rial properties can change and morph over time, as exem- plified by the natural phenomena of leaf color changes from summer to fall.
This project will attempt to build a prototype of a path tracing renderer with a BSDF model modified to include an additional time component to allow for material properties to change over time in a way representative of how material properties change over time in reality. The hope is that
such a renderer will prove to be useful in future attempts to recreate natural phenomena using physically based models, such as leaf decay.
...and the actual goal of the project...
1.1 Design Goals
The project’s goal is to develop a reasonably robust and efficient path tracing renderer with a BSDF model modified to include an additional time component. In order to prove the feasibility of such a modified BSDF model, the end goal is to be able to use the renderer to produce images of plant life with changing surface material properties, in addition to standard test image such as Cornell Box tests that validate the functionality of the underlying basic path tracer.
...and finally, what I'm hoping I'll actually be able to produce at the end of this independent study:
1.2 Projects Proposed Features and Functionality
The proposed renderer should allow a user to load a sce- ne with an arbitrary number of lights, materials, and objects and render out a realistic, global illumination based render. The renderer should be able to render implicitly defined objects such as spheres and cubes in addition to meshes defined in the .obj format. The renderer should also allow users to specify changes in object/light/camera transfor- mations over time in addition to changes in materials and BSDFs over time and render out a series of frames showing the scene at various points in time. A graphical interface would be a nice additional feature, but is not a priority of this project.
I'll be posting at least weekly updates to this blog showing my progress. In my next post, I'll go over some of the papers and sources Joe gave me to look over and explain some of the basic mechanics of how a pathtracer works. Apologies for the casual reader for this particular post being extremely text heavy; I shall have images to show soon!
Thursday, December 22, 2011
Basic Raytracer and Fun with KD-Trees
The assignment is actually pretty straightforward: implement a recursive, direct lighting only raytracer with support for Blinn-Phong shading and support for basic primitive shapes (spheres, boxes, and polygon extrusions). In other words, pretty much a barebones implementation of the original Turner Whitted raytracing paper.
I've been planning on writing a global-illumination renderer (perhaps based on pathtracing or photon mapping?) for a while now, so my own personal goal with the raytracer project was to use it as a testbed for some things that I know I will need for my GI renderer project. With that in mind, I decided from the start that my raytracer should support rendering OBJ meshes and include some sort of acceleration system for OBJ meshes.
The idea behind the acceleration system goes like this: in the raytracer, one obviously needs to cast rays into the scene and track how they bounce around to get a final image. That means that every ray needs to have intersection tests against objects in the scene in order to determine what ray is hitting what object. Intersection testing against mathematically defined primitives is simple, but OBJ meshes present more of a problem; since an OBJ mesh is composed of a bunch of triangles or polygons, the naive way to intersection test against an OBJ mesh is to check for ray intersections with every single polygon inside of the mesh. This naive approach can get extremely expensive extremely quickly, so a better approach would be to use some sort of spatial data structure to quickly figure out what polygons are within the vicinity of the ray and therefore need intersection testing.
After talking with Joe and trawling around on Wikipedia for a while, I picked a KD-Tree as my spatial data structure for accelerated mesh intersection testing. I won't go into the details of how KD-Trees work, as the Wikipedia article does a better job of it than I ever could. I will note, however, that the main resources I ended up pulling information from while looking up KD-Tree stuff are Wikipedia, Jon McCaffrey's old CIS565 slides on spatial data structure, and the fantastic PBRT book that Joe pointed me towards.
Implementing the KD-Tree for the first time took me the better part of two weeks, mainly because I was misunderstanding how the surface area splitting heuristic works. Unfortunately, I probably can't post actual code for my raytracer, since this is a class assignment that will repeated in future incarnations of the class. However, I can show images!
The KD-Tree meant I could render meshes in a reasonable amount of time, so I rendered an airplane:
The airplane took about a minute or so to render, which got me wondering how well my raytracer would work if I threw the full 500000+ poly Stanford Dragon at it. This render took about five or six minutes to finish (without the KD-Tree in place, this same image takes about 30 minutes to render):
Of course, the natural place to go after one dragon is three dragons. Three dragons took about 15 minutes to render, which is pretty much exactly a three-fold increase over one dragon. That means my renderer's performance scales more or less linearly, which is good.
For fun, and because I like space shuttles, here is a space shuttle. Because the space shuttle has a really low poly count, this image took under a minute to render:
For reflections, I took a slightly different approach from the typical recursive method. The normal recursive approach to a raytracer is to begin with one ray, and trace that ray completely through recursion to its recursion depth limit before moving onto the next pixel and ray. However, such an approach might not actually be idea in a GI renderer. For example, from what I understand, in pathtracing a better raytracing approach is to actually trace everything iteratively; that is, trace the first bounce for all rays and store where the rays are, then trace the second bounce for all rays, then the third, and so on and so forth. Basically, such an approach allows one to set an unlimited trace depth and just let the renderer trace and trace and trace until one stops the renderer, but the corresponding cost of such a system is slightly higher memory usage, since ray positions need to be stored for the previous iteration.
Adding reflections did impact my render times pretty dramatically. I have a suspicion that both my intersection code and my KD-Tree are actually far from ideal, but I'll have to look at that later. Here's a test with reflections with the airplane:
...and here is a test with three reflective dragons. This image took foooorrreeevvveeeerrrr to render.... I actually do not know how long, as I let it run overnight:
I also added support for multiple lights with varying color support:
Here are some more images rendered with my raytracer:
As an amusing parting note, here is the first proper image I ever got out of my raytracer. Awww yeeeaaahhhhhh:
Friday, October 14, 2011
A Volumetric Renderer for Rendering Volumes
...or you can make pretty clouds.
One of the first things I ever tried to make when I first was introduced to Maya was a cloud. I quickly learned that there simply is no way to get a nice fluffy cloud using polygonal modeling techniques. Ever since then I've kept the idea of making clouds parked in the back of my head, so when we were assigned the task of writing a volumetric renderer that could produce clouds, obviously I was pretty excited.
At least in the case of my renderer, there is a fourth way to deal with the artifacting: instead of preloading the voxel buffer with values from Perlin noise, why not just get rid of the notion of a discretized voxel buffer altogether and directly sample the Perlin noise function when raymarching? The result would indeed be a perfectly smooth, artifact free render, but the computational cost is extraordinarily high compared to using a voxel buffer.
So! The volumetric renderer was definitely a fun assignment, and now I've got a cool way to make clouds! Hopefully I'll be able to integrate this renderer into some future projects!
Thursday, October 6, 2011
Building/Installing Alembic for OSX
Alembic is a new open-source computer graphics interchange framework being developed by Sony Imageworks and ILM. The basic idea is that moving animation rigs and data and whatnot between packages can be a very tricky procedure since every package has its own way to handle animation, so why not bake out all of that animation data into a common interchange format? So, for example, instead of having to import a Maya rig into Houdini, you could rig/animate in Maya, bake out the animation to Alembic, bring that into Houdini to conduct simulations with, and then bake out the animation and bring it back into Maya. This is a trend that a number of studios including Sony, ILM, Pixar, etc. have been moving toward for some time.
I’ve been working on a project lately (more on that later) that makes use of Alembic, but I found that the only way to actually get Alembic is to build it from source. That’s not terribly difficult, but there’s not really any guides out there for folks who might not be as comfortable with building things from source. So, I wrote up a little guide!
Here’s how to build Alembic for OSX (10.6 and 10.7):
1. Alembic has a lot of dependencies that can be annoying to build/install by hand, so we’re going to cheat and use Homebrew. To install Homebrew:
/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"
2. Get/build/install cmake with Homebrew:
brew install cmake
3. Get/build/install Boost with Homebrew:
brew install Boost
4. Get/build/install HDF5 with Homebrew:
brew install HDF5
HDF5 has to make install itself, so this may take some time to run. Be patient.
5. Unfortunately, ilmbase is not a standard UNIX package, so we can’t use Homebrew. We’ll have to build ilmbase manually. Get it from:
http://download.savannah.nongnu.org/releases/openexr/ilmbase-1.0.2.tar.gz
Untar/unzip to a readily accessible directory and cd into the ilmbase directory. Run:
./configure
After that finishes, we get to the annoying part: ilmbase by default makes use of a deprecated GCC 3.x compiler flag called Wno-long-double, which no longer exists in GCC 4.x. We’ll have to deactivate this flag in ilmbase’s makefiles manually in order to build correctly. In each and every of the following files:
/Half/Makefile
/HalfTest/Makefile
/Iex/Makefile
/IexTest/Makefile
/IlmThread/Makefile
/Imath/Makefile
/ImathTest/Makefile
Find the following line:
CXXFLAGS = -g -O2 -D_THREAD_SAFE -Wno-long-double
and delete it from the makefile.
Once all of that is done, you can make and then make install like normal.
Now move the ilmbase folder to somewhere safe. Something like /Developer/Dependencies might work, or alternatively /usr/include/
6. Time to actually build Alembic. Get the source tarball from:
http://code.google.com/p/alembic/wiki/GettingAlembic
Untar/unzip into a readily accessible directory and then create a build root directory parallel to the source root you just created:
mkdir ALEMBIC_BUILD
The build root doesn’t necesarily have to be parallel, but here we’ll assume it is for the sake of consistency.
7. Now cd into ALEMBIC_BUILD and bootstrap the Alembic build process. The bootstrap script is a python script:
python ../[Your Alembic Source Root]/build/bootstrap/alembic_bootstrap.py
The script will ask you for a whole bunch of paths:
For “Please enter the location where you would like to build the Alembic”, enter the full path to your ALEMBIC_BUILD directory.
For “Enter the path to lexical_cast.hpp:”, enter the full path to your lexical_cast.hpp, which should be something like /usr/local/include/boost/lexical_cast.hpp
For “Enter the path to libboost_thread:”, your path should be something like /usr/local/lib/libboost_thread-mt.a
For “Enter the path to zlib.h”, your path should be something like /usr/include/zlib.h
For “Enter the path to libz.a”, we’re actually not going to link against libz.a. We’ll be using libz.dylib instead, which should be at something like /usr/lib/libz.dylib
For “Enter the path to hdf5.h”, your path should be something like /usr/local/include/hdf5.h
For “Enter the path to libhdf5.a”, your path should be something like /usr/local/Cellar/hdf5/1.x.x/lib/libhdf5.a (unless you did not use Homebrew for installing hdf5, in which case libhdf5.a will be in whatever lib directory you installed it to)
For “Enter the path to ImathMath.h”, your path should be something like /usr/local/include/OpenEXR/ImathMath.h
For “Enter the path to libImath.a”, your path should be something like /usr/local/lib/libImath.a
Now hit enter, and let the script finish running!
8. If everything is bootstrapped correctly, you can now make. This will take a while, be patient.
9. Once the make finishes successfully, run make test to check for any problems.
10. Finally, run make install, and we’re done! Alembic should install to something like /usr/bin/alembic-1.x.x/.
Monday, September 5, 2011
Installing Numpy for Maya 2012 64-bit on OSX 10.7
However, OSX 10.7 comes with Python 2.7.x, so a few extra steps are needed:
For Maya 2012 64-bit:
1. OSX 10.7 comes with Python 2.7.x, but we need 2.6.x, so install 2.6.x using the official installer from here: http://www.python.org/ftp/python/2.6.6/python-2.6.6-macosx10.3.dmg
2. Since we're using 64-bit Maya with 64-bit Python, we'll need a 64-bit build of Numpy. The official version distributed on scipy.numpy.org is 32-bit, so we'll need a 64-bit build. Thankfully, there is an unofficial 64-bit build in the form of the Scipy Superpack for Mac OSX. Even though we're on OSX 10.7, we'll want the OSX 10.6 variety of the script since the OSX 10.7 is Python 2.7.x dependent:
3. Go to where the script downloaded to and in Terminal:
chmod +x superpack_10.6_2011.07.10.sh
./superpack_10.6_2011.07.10.sh
If you don't already have GNU Fortran, make sure to answer 'yes' when the script asks.
4. Once the script is done installing, in Terminal:
ls /Library/Python/2.7/site-packages/ | grep numpy
You should get something like: numpy-2.0.0.dev_b5cdaee_20110710-py2.6-macosx-10.6-universal.egg
Even though we installed Numpy for Python 2.6.x, on Lion it installs to the 2.7 folder for some reason. No matter, you can either leave it there or move it to 2.6.
5. Go to /Users/[your username]/Library/Preferences/Autodesk/maya/2012-x64/scripts
6. If you don't have a file named userSetup.py, make one and open it in a text editor. If yes, open it.
7. Add these lines to the file:
import os
import sys
sys.path.append('/Library/Python/2.7/site-packages/[thing you got from step 4]')
8. Sidenote: installing Python 2.6.x sets your default OSX Python to 2.6.x, but if you want to go back to 2.7.x, just edit your ~/.bash_profile and remove these lines:
PATH="/Library/Frameworks/Python.framework/Versions/2.6/bin:${PATH}"
export PATH
....and you should be done! In Maya, you should be able to just use
import numpy and you'll be good to go!
Thursday, September 1, 2011
Why Backups are Important
Over the summer, I started making a little scene based off of the GH House Challenge from RonenBekerman.com, partially as a way to learn Vray and partially just for fun. I was working off of my laptop for the entire project, since I was in California at the time and didn't have access to more powerful machines at home. Being out in California for the summer, I brought as little stuff with me as possible.
One of the things I decided to leave home was my backup Time Machine drive. "Oh, I won't need this over the summer, what are the odds of file corruption or harddrive issues anyhow? I'll be fine", I thought to myself.
Which means, of course, that halfway through the summer a bunch of my files got corrupted and were therefore lost forever, and of course that block of lost data included my in-progress GH House project. NEVER ASSUME THAT YOU DO NOT NEED BACKUP.
What follows are some random in-progress renders that survived through being in posts I made to Facebook and Tumblr.
Here are a series of small in-progress renders showing shading and lighting tests:



I also started playing with some ideas for the interior:

...and finally, some larger in-progress renders. These renders represent where the project was when I lost all of the data:




In the end, the fact that I lost the project isn't as important as the fact that I learned quite a lot from tinkering with this project. However, losing all of the data for this project was definitely a major bummer. But, lesson learned: BACK UP ALL THE TIME.

























