diff --git a/README.md b/README.md index 02a82bc..db3cf3d 100644 --- a/README.md +++ b/README.md @@ -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). @@ -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). @@ -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. diff --git a/img/1.png b/img/1.png new file mode 100644 index 0000000..6d4cd32 Binary files /dev/null and b/img/1.png differ diff --git a/img/2.png b/img/2.png new file mode 100644 index 0000000..c43f85c Binary files /dev/null and b/img/2.png differ diff --git a/img/3.png b/img/3.png new file mode 100644 index 0000000..365c294 Binary files /dev/null and b/img/3.png differ diff --git a/img/Screenshot 2015-10-19 19.41.22.png b/img/Screenshot 2015-10-19 19.41.22.png new file mode 100644 index 0000000..1cace47 Binary files /dev/null and b/img/Screenshot 2015-10-19 19.41.22.png differ diff --git a/img/thumb.png b/img/thumb.png deleted file mode 100644 index 9ec8ed0..0000000 Binary files a/img/thumb.png and /dev/null differ diff --git a/raymarch.glsl b/raymarch.glsl index aac90c8..9a14799 100644 --- a/raymarch.glsl +++ b/raymarch.glsl @@ -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.xtmax ) 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.xtmax ) 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) { @@ -44,4 +180,4 @@ void mainImage(out vec4 fragColor, in vec2 fragCoord) { col = pow(col, vec3(0.4545)); fragColor = vec4(col, 1.0); -} +} \ No newline at end of file