Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 32 additions & 148 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,138 +1,25 @@
# [CIS565 2015F] YOUR TITLE HERE
# [CIS565 2015F] Ray Marching

**GLSL Ray Marching**

**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 5**

* (TODO) YOUR NAME HERE
* Tested on: (TODO) **Google Chrome 222.2** on
Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)
* Guan Sun
* Tested on: **Google Chrome 46.0.2490.71(64-bit)** on
Mac OS X Yosemite 10.10.5, Intel Core i7 @ 2.3GHz 8GB, GeForce GT 650M 1024MB (Personal Laptop)

### Live on Shadertoy (TODO)
### Live on Shadertoy

[![](img/thumb.png)](https://www.shadertoy.com/view/TODO)
[![](img/1.png)](https://www.shadertoy.com/view/MtBXR3)

### Acknowledgements

This Shadertoy uses material from the following resources:

* TODO

### (TODO: Your README)


Instructions (delete me)
========================

This is due at midnight on the evening of Monday, October 19.

**Summary:** In this project, you'll see yet another way in which GPU
parallelism and compute-efficiency can be used to render scenes.
You'll write a program in the popular online shader editor
[Shadertoy](http://www.shadertoy.com/).
Your goal will be to implement and show off different features in a cool and
interesting demo. See Shadertoy for inspiration - and get creative!

Ray marching is an iterative ray casting method in which objects are
represented as implicit surfaces defined by signed distance functions (SDFs). This
method is widely used in the Shadertoy community to render complex scenes which
are defined in the fragment shader code executed for each pixel.

**Important Notes:**
* Even though you will be coding in Shadertoy, it is important as always to
save versions of your code so that you do not lose progress! Commit often!
* A significant portion of this project will be in write-up and performance
analysis - don't save it for later.

**Provided Code:**
The provided code in `raymarch.glsl` is straight from iq's Raymarching
Primitives; see {iq-prim}. It just sets up a simple starter camera.

### Features

All features must be visible in your final demo for full credit.

**Required Features:**

* Two ray marching methods (comparative analysis required)
* Naive ray marching (fixed step size) {McGuire 4}
* Sphere tracing (step size varies based on signed distance field) {McGuire 6}
* 3 different distance estimators {McGuire 7} {iq-prim}
* With normal computation {McGuire 8}
* One simple lighting computation (e.g. Lambert or Blinn-Phong).
* Union operator {McGuire 11.1}
* Necessary for rendering multiple objects
* Transformation operator {McGuire 11.5}
* Debug views (preferably easily toggleable, e.g. with `#define`/`#if`)
* Distance to surface for each pixel
* Number of ray march iterations used for each pixel

**Extra Features:**

You must do at least 10 points worth of extra features.

* (0.25pt each, up to 1pt) Other basic distance estimators/operations {McGuire 7/11}
* Advanced distance estimators
* (3pts) Height-mapped terrain rendering {iq-terr}
* (3pts) Fractal rendering (e.g. Menger sponge or Mandelbulb {McGuire 13.1})
* **Note** that these require naive ray marching, if there is no definable
SDF. They may be optimized using bounding spheres (see below).
* Lighting effects
* (3pts) Soft shadowing using secondary rays {iq-prim} {iq-rwwtt p55}
* (3pts) Ambient occlusion (see 565 slides for another reference) {iq-prim}
* Optimizations (comparative analysis required!)
* (3pts) Over-relaxation method of sphere tracing {McGuire 12.1}
* (2pts) Analytical bounding spheres on objects in the scene {McGuire 12.2/12.3}
* (1pts) Analytical infinite planes {McGuire 12.3}

This extra feature list is not comprehensive. If you have a particular idea
that you would like to implement, please **contact us first** (preferably on
the mailing list).

## Write-up

For each feature (required or extra), include a screenshot which clearly
shows that feature in action. Briefly describe the feature and mention which
reference(s) you used.

### Analysis

* Provide an analysis comparing naive ray marching with sphere tracing
* In addition to FPS, implement a debug view which shows the "most expensive"
fragments by number of iterations required for each pixel. Compare these.
* Compare time spent ray marching vs. time spent shading/lighting
* This can be done by taking measurements with different parts of your code
enabled (e.g. raymarching, raymarching+shadow, raymarching+shadow+AO).
* Plot this analysis using pie charts or a 100% stacked bar chart.
* For each feature (required or extra), estimate whether branch divergence
plays a role in its performance characteristics, and, if so, point out the
branch in question.
(Like in CUDA, if threads diverge within a warp, performance takes a hit.)
* For each optimization feature, compare performance with and without the
optimization. Describe and demo the types of scenes which benefit from the
optimization.

**Tips:**

* To avoid computing frame times given FPS, you can use the
[stats.js bookmarklet](https://github.com/mrdoob/stats.js/#bookmarklet)
to measure frame times in ms.

### Resources

You **must** acknowledge any resources you use, including, but not limited to,
the links below. **Do not copy non-trivial code verbatim.** Instead, use the
references to understand the methods.

For any code/material in the 565
[slides](http://cis565-fall-2015.github.io/lectures/12-Ray-Marching.pptx),
please reference the source found at the bottom of the slide.

* {McGuire}
Morgan McGuire, Williams College.
*Numerical Methods for Ray Tracing Implicitly Defined Surfaces* (2014).
[PDF](http://graphics.cs.williams.edu/courses/cs371/f14/reading/implicit.pdf)
* You may credit and use code from this reference.
* {iq-prim}
Iñigo Quílez.
*Raymarching Primitives* (2013).
Expand All @@ -141,7 +28,6 @@ please reference the source found at the bottom of the slide.
Iñigo Quílez.
*Terrain Raymarching* (2007).
[Article](http://www.iquilezles.org/www/articles/terrainmarching/terrainmarching.htm)
* You may credit and use code from this reference.
* {iq-rwwtt}
Iñigo Quílez.
*Rendering Worlds with Two Triangles with raytracing on the GPU* (2008).
Expand All @@ -150,40 +36,38 @@ please reference the source found at the bottom of the slide.
Ashima Arts, Ian McEwan, Stefan Gustavson.
*webgl-noise*.
[GitHub](https://github.com/ashima/webgl-noise)
* You may use this code under the MIT-expat license.

## Project Description:
In this project, a WebGL ray marcher is implemented in an online shader editor [Shadertoy](http://www.shadertoy.com/) using GLSL.
The implemented features include,
* Two ray marching methods
* Naive ray marching (fixed step size) {McGuire 4}
* Sphere tracing (step size varies based on signed distance field) {McGuire 6}
* 4 different distance estimators {McGuire 7} {iq-prim}
* With normal computation {McGuire 8}
* One simple lighting computation (Lambert).
* Soft shadowing using secondary rays {iq-prim} {iq-rwwtt p55}
* Union operator {McGuire 11.1}
* Debug views
* Distance to surface for each pixel
* Normal direction

## Submit

### Post on Shadertoy
### Redering result
![](img/1.png)

Post your shader on Shadertoy (preferably *public*; *draft* will not work).
For your title, come up with your own demo title and use the format
`[CIS565 2015F] YOUR TITLE HERE` (also add this to the top of your README).
### Debug views

In the Shadertoy description, include the following:
* Depth view
![](img/2.png)

* A link to your GitHub repository with the Shadertoy code.
* **IMPORTANT:** A copy of the *Acknowledgements* section from above.
* Remember, this is public - strangers will want to know where you got your
material.
* Normal view
![](img/3.png)

Add a screenshot of your result to `img/thumb.png`
(right click rendering -> Save Image As), and put the link to your
Shadertoy at the top of your README.
## Analysis
I implemented both naive ray marching and sphere tracing, the perfomance of them are,
* Naive ray marching: 18.5 FPS
* Sphere tracing: 57.3 FPS

### Pull Request
It is clear that sphere tracing has a much better rendering perfomance, the reason is it uses a singed distance funtion to adjust the size of each step of the ray cast, thus need much fewer iterations than the naive ray marching which use a fixed step size.

**Even though your code is on Shadertoy, make sure it is also on GitHub!**

1. Open a GitHub pull request so that we can see that you have finished.
The title should be "Submission: YOUR NAME".
* **ADDITIONALLY:**
In the body of the pull request, include a link to your repository.
2. Send an email to the TA (gmail: kainino1+cis565@) with:
* **Subject**: in the form of `[CIS565] Project N: PENNKEY`.
* Direct link to your pull request on GitHub.
* Estimate the amount of time you spent on the project.
* If there were any outstanding problems, or if you did any extra
work, *briefly* explain.
* Feedback on the project itself, if any.
Binary file added img/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/Screenshot 2015-10-19 19.41.22.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img/thumb.png
Binary file not shown.
142 changes: 139 additions & 3 deletions raymarch.glsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,142 @@
float dSphere(vec3 X, vec3 C, float r){
return length(X-C)-r;
}

float dPlane(vec3 X){
return X.y;
}

float dBox(vec3 X, vec3 C, float b){
vec3 d = abs(X-C)-b;
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}

float dTorus(vec3 X, vec3 C, float R, float r)
{
return length(vec2(length(X.xz - C.xz) - r, X.y - C.y)) - R;
}

vec2 opUnion(vec2 r1, vec2 r2){
return r1.x < r2.x ? r1 : r2;
}


vec2 allDist(in vec3 X){
vec2 res;
float sphereDist = dSphere(X, vec3(-1.0, 0.25, 0.0), 0.25);
float planeDist = dPlane(X);
res = opUnion(vec2(sphereDist, 1.0), vec2(planeDist, 2.0));
float boxDist = dBox(X, vec3(1.0, 0.25, 1.0), 0.25);
res = opUnion(res, vec2(boxDist, 3.0));
float torusDist = dTorus(X, vec3(-1.5, 0.5, -1.5), 0.15, 0.5);
res = opUnion(res, vec2(torusDist, 4.0));
return res;
}

vec2 naiveMarch( in vec3 ro, in vec3 rd ){
float tmin = 1.0;
float tmax = 20.0;
float tstep = 0.01;

float precis = 0.001;
float t = tmin;
float m = -1.0;
for( int i=0; i<1000; i++ )
{
vec2 res = allDist( ro+rd*t );
if( res.x<precis) break;
m = res.y;
t += tstep;
}

if( t>tmax ) m=-1.0;
return vec2( t, m );
}
vec2 sphereMarch( in vec3 ro, in vec3 rd )
{
float tmin = 1.0;
float tmax = 20.0;

float precis = 0.001;
float t = tmin;
float m = -1.0;
for( int i=0; i<50; i++ )
{
vec2 res = allDist( ro+rd*t );
if( res.x<precis || t>tmax ) break;
m = res.y;
t += res.x;
}

if( t>tmax ) m=-1.0;
return vec2( t, m );
}

vec3 getNormal( in vec3 X )
{
vec3 eps = vec3( 0.001, 0.0, 0.0 );
vec3 n = vec3(
allDist(X+eps.xyy).x - allDist(X-eps.xyy).x,
allDist(X+eps.yxy).x - allDist(X-eps.yxy).x,
allDist(X+eps.yyx).x - allDist(X-eps.yyx).x );
return normalize(n);
}

float shadow(vec3 ro, vec3 rd){
float t = 0.001;
float eps = 0.0001;
vec2 res;
float dist = 1.0;
float maxDist = 1.0;
float C = 8.0;
for (int i = 0; i < 30; i++){
res = allDist(ro+rd*t);
if (res.x < eps){
return 0.0;
}
if (res.x > maxDist)
break;
dist = min(dist, C*res.x/t);
t+= res.x;
}
return clamp(dist, 0.0, 1.0);
}


vec3 shade(vec3 ro, vec3 rd, vec2 res){
vec3 color;
if(res.y == 1.0){
color = vec3(0.8,0.2,0.2);
} else if( res.y == 2.0){
color = vec3(0.3, 0.8, 0.3);
} else if( res.y == 3.0){
color = vec3(0.5, 0.5, 0.9);
} else if( res.y == 4.0){
color = vec3(0.9, 0.9, 0.3);
}

//for lighting
vec3 light = normalize( vec3(-0.6, 0.7, -0.5) );
vec3 norm = getNormal(ro+rd*res.x);
float diffuse = clamp( dot( norm, light ), 0.0, 1.0 );

float shadow = shadow(ro+rd*res.x, light);

//return color*diffuse;
return color*diffuse*shadow;
//return clamp( dot( rd, (rd*res.x) )*vec3(0.05), 0.0, 1.0 );
//return norm;
}

vec3 render(in vec3 ro, in vec3 rd) {
// TODO
return rd; // camera ray direction debug view
vec3 color = vec3(0.8, 0.9, 1.0);
vec2 res = sphereMarch(ro, rd);
//vec2 res = naiveMarch(ro, rd);
if(res.y > 0.0){
color = shade(ro, rd, res);
}
return vec3( clamp(color,0.0,1.0) );
//return rd; // camera ray direction debug view
}

mat3 setCamera(in vec3 ro, in vec3 ta, float cr) {
Expand Down Expand Up @@ -44,4 +180,4 @@ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
col = pow(col, vec3(0.4545));

fragColor = vec4(col, 1.0);
}
}