Wednesday, March 28, 2012

Links

Live Code
http://www.iamnop.com/raymarch/

Git Repo
https://github.com/nopjia/WebGL-RayMarch

Looking Better!

Just as a test, to see if a good output image is possible.
  1. Added fog as an exponential function of ray distance.
  2. Increased maximum steps to eliminate numerical error artifacts.
The output looks nice, but the performance also took a big hit. 

Since more steps produce better results, now I know an area of optimization is definitely in the balance of maximum step number and maximum distance. Something to look into further down the road.

And here's a screenshot.


Diffuse Lighting

Added basic diffuse lighting!

The frame rate is still pretty good. The picture does look pretty funky at the moment though, especially around the edges and very far away when ray marching hits the maximum steps.


Playing with Various Functions

Played around with various distance functions from
http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm

The screenshot below uses the udRoundBox primitive and the repetition operator. The frame rate is pretty high, possibly due to the newly revised ray marching loop. This also shows that increasing the number of shapes does not affect performance at all since this is an implicitly described scene. Later on, when the distance functions become more complex the performance might take a hit.


Variable-Length Loops

Something from Monday's lecture triggered me to investigate variable-length loops in GLSL. It is a limitation in GLSL that loops must be of a constant length, i.e., iterating from a constant defined number to another, so that the length of the loop is determinable at compile time.

This becomes a problem for this project since the whole point of this ray marching method is to minimize the number of steps taken per ray. So I decided to investigate the use of breaks to terminate loops. The GLSL limits only the maximum length of the loop, but forward branching with breaks are allowed. However, this turns out to be more tricky than it seems. As I learned from previous semester GLSL (especially GLSL ES 1.0) is often quite mysterious: sometimes thing will stop working if GLSL decides "it doesn't like it." There are many more limitations that are not written in the documentation.

In the end I managed to make breaks work in for loops. The result is a minor performance improvement, of a few FPS on average. I expect the performance improvement to increase as I scale up the maximum number of steps to do ray march; right now it is set to only 32 steps per ray.

For the breaks to work, there were two requirements that I had to have: 1) use "if else" instead of "if", and 2) place the "break" in the "else" statement. Now you can see a little bit how GLSL can be very strange at times, but it is what it is. Here's some code that demonstrates my point #2 above.

Working code.
if(h >= EPS)
  steps++;
else
  break;

Does not work.
if(h < EPS)
  break;
else
  steps++;

Friday, March 23, 2012

Inversed!

Actually, the pixel values are flipped! It should be darker where more steps are taken, as it makes more sense (also visually) that darkness counts steps.

Here's a new picture (much nicer!)



What's curious about this is why it takes a single step (or very few steps) to where there is no shape. I'll still have to figure this out.

Thursday, March 22, 2012

Setting Up Framework

I spent this week reading up on the variable-step ray marching method and distance fields. At the moment I am still trying to wrap my head around distance field functions and how they represent geometry, since it is quite an unintuitive method of describing shapes.

What I also did this week was to set up a rendering framework on WebGL using GLSL. I draw a single rectangle in the scene as a viewing plane, and output of ray marching will be displayed on this rectangle through its shader material.

What I have so far is very basic per pixel ray marching in GLSL. I am only concerned with my ray marching method at the moment, which means I have not done anything on the rendering side yet, i.e., I have no shading of any kind. I am simply outputting the number of steps taken to intersect the scene as gray-scale pixels. I am testing with the most basic shape, the sdBox() (function given here.)

Here's what it looks like now. It basically shows a depth map of the scene from the camera. Runs pretty smoothly at real-time frame rates on a small enough resolution (my laptop is also very outdated.)


Wednesday, March 14, 2012

Number of Steps in Ray Marching

Thanks to Patrick for his great suggestion.

Since I am concerned with performance, I should also be aware of the number of steps marched by each ray, and should provide a way to visualize the number of steps marched for each pixel. This should be able to be easily implemented as another view mode.

Ray Marching Distance Fields in Real-time on WebGL


I am interested in the topic of real-time rendering on WebGL. For my CIS 565 final project, I will explore a method to quickly visualize and render implicit surfaces. This method is ray marching of distance fields.

Ray marching is a rendering method most commonly used in volumetric rendering. The method is similar to ray tracing where a ray is casted into the scene for each output pixel. The ray takes discrete steps and at each step samples the density, which then finally translates to pixel color.

The ray marching method is then used to render a scene described by a distance field. Composed of one or more distance functions, distance fields describe the shortest distance from any given point to a surface in the scene.

Together, ray marching and distance fields provide an efficient method of rendering mathematical surfaces, such as constructive solid geometry, or more complex shapes that cannot be easily determined, such as recursive shapes and fractals.

Here’s how the method works. For each output pixel, a ray is casted into the scene. It then samples the distance field to determine the shortest distance to any point in the scene. This distance is equivalent to the maximum distance the ray can step without intersecting any surface in the scene. The ray takes a step equal to this distance and repeats the process until it can no longer take any more steps. This adaptive step size is fundamental to the efficiency of this method.


Moreover, because of the stepwise nature, the ray marching method can be extended to support ambient occlusion shadows and subsurface scattering.

The focus of this project is the robustness of the renderer itself. It should be able to render the scene in real-time, and it should be able to handle multiple types of distance functions. This includes CSGs, recursive shapes, fractals, and any other procedural shapes. In addition, it should be able to render the scene with ambient occlusion and subsurface scattering.

The renderer will run in the browser on WebGL. I am planning to use Three.js library to set up the framework. The rendering work will be done on the GLSL shader, and the output shaded onto a viewing-plane quad.

If time allows, I am planning to explore more complex surfaces such as recursive shapes and fractals.


Sources:

Iñigo Quilez, “Rendering Worlds with Two Triangles”

Iñigo Quilez, Distance Functions

GPU Ray Marching with Distance Fields


D.J. Sandin, others, “Ray Tracing Deterministic 3-D Fractals”