diff --git a/README.md b/README.md
index 25002db..99b0453 100644
--- a/README.md
+++ b/README.md
@@ -3,26 +3,126 @@ WebGL Deferred Shading
**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)
+* Xueyin Wan
+* Platform: *FireFox 49.0.2* on: Windows 10, i7-4870 @ 2.50GHz 16GB, NVIDIA GeForce GT 750M 2GB (Personal Laptop)
+
+###Features I Implemented
+
+* Deferred Blinn-Phong shading
+* Bloom using blur
+* Bloom using two-pass Gaussian blur (extract, blur, blurtwice, combine)
+* Toon Shading (ramp shading, edge detection)
+* Scissor Test Optimization (with debug view)
+* Screen-space Motion Blur
+* G-Buffer Optimization
### Live Online
+####Press the .png file below and you may find my demo for this project!! Hope you enjoy :)
+[](https://vimeo.com/190819701)
+Link: https://vimeo.com/190819701
+
+## Showcase My Result
+### Part One
+
+### 1. Deferred Blinn-Phong shading
+| Depth Map | Position Map |
+|------|------|
+| |  |
+
+| Geometry Normal | Normal map |
+|------|------|
+| |  |
+
+| Surface Normal | Color map |
+|------|------|
+| |  |
+
+Above pictures show the whole procudure of deferred shading. In our code base, Blinn-Phong shading was the first basic feature. We do not contain any post processing (fancy) effects. Just applied Blinn-Phong lighting in blinnphong-pointlight.frag.glsl and render with this shader.
+
+### 2. Two-pass Gaussian blur Bloom Effect
+| Without Bloom Effect | With Bloom Effect |
+|------|------|
+| |  |
+I learned bloom effect on this website: http://learnopengl.com/#!Advanced-Lighting/Bloom
+
+We can see, that basically 4 steps contained in bloom effect. We just follow the steps to achieve this effect.
+
+`First : Extract`
+In this step, we extract all the fragments that exceed a certain brightness.This gives us an image that only shows the bright colored regions as their fragment intensities exceeded a certain threshold.
+
+`Second : Blur Horizontally`
+In this step, we simply took the average of surrounding pixels of an image. We choose Gaussian Operator here.
-[](http://TODO.github.io/Project5B-WebGL-Deferred-Shading)
+First, we select the horizontal neighbor pixels to start blur.
+We save this first blur in the first framebuffer, since we need to blur it vertically based on this current result.
-### Demo Video/GIF
+`Third: Blur Vertically`
+In this step, we toggle to the vertically blur mode.
-[](TODO)
+With these two steps, we simply finish the Two-pass Gaussian blur and we can save current image to next step.
-### (TODO: Your README)
+`Fourth: Combine`
+We combine the result derived after above three steps with our original picture. Then we could get the bloom effect.
-*DO NOT* leave the README to the last minute! It is a crucial part of the
-project, and we will not be able to grade you without a good README.
+By the way, I think two pass blur is really clever since we deduplicate a lot of repeated I/Os and calculations.
-This assignment has a considerable amount of performance analysis compared
-to implementation work. Complete the implementation early to leave time!
+### 3. Toon Shading
+| Without Toon Shading | With Toon Shading |
+|------|------|
+| |  |
+Toon shading contains two steps: ramp shading + edge detection.
+In ramp shading procedure, what we need to think about is that: the diffuse and specular values in the blinn-phong shading should be calculated based on step functions, rather than continous functions. So we use step function to classify the fragments with different lambert and specular terms.
+
+After we finish ramp shading, we come to the edge detection stage. Luckily I've using opencv during the year 2014 and 2015, so I have some basic image processing concepts about this. Basically here, we select our contour based on depth information of the fragment itself and surrounding pixels.
+
+### 4. Motion Blur
+| Without Motion Blur | With Motion Blur |
+|------|------|
+| |  |
+
+Here, we need to take advantage of camera's projection matrix since in our scene, in fact here it is the camera always moving, not the geometry in the scene. We then need the previous frame's camera projection matrix(we could save it as a global variable). Then we come into next frame, we first pass this to camera's prev_matrix property, then using current frame's camera projection matrix to update this global previous projection matrix. This method works fine!
+
+How do I think out this idea? Thanks to this very very very useful tutorial: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch27.html
+
+In this tutorial, we could see that we need the previous camera projection matrix information. Then I just follow the formula in the code provided in this tutorial to get the correct result.
+
+We could get the blur vector between two frames, and simply divide by 2 to get the velocity.(blur along velocity direction)
+
+### Part Two: Optimization
+### 1. Scissor Test
+| Debug View Of Scissor Test | Debug View Of Scissor Test |
+|------|------|
+| |  |
+With scissor test, we do not need to render the full image. We only need to render a rectangle area around the light. This will definitely shorten the time of rendering.
+Let's see a chart to judge the performance of Scissor test.
+
+We could clearly see that, with scissor test, the render procedure each frame reaches up to 3 times when scissor test off.
+
+### 2. Decrease the size of the G-Buffer
+When read through the code, I found that
+```javascript
+ vec3 pos = gb0.xyz; // World-space position
+ vec3 geomnor = gb1.xyz; // Normals of the geometry as defined, without normal mapping
+ vec3 colmap = gb2.rgb; // The color map - unlit "albedo" (surface color)
+ vec3 normap = gb3.xyz; // The raw normal map (normals relative to the surface they're on)
+ vec3 nor = applyNormalMap (geomnor, normap); // Surface normal
+```
+We can see in the code above, we have gb1 and gb3 contain two vectors related to normal : geometry normal and raw normal map. Since at last we need to apply Normal map to Geometry normal and finally get a surface normal, we could save the spaces and do the computation in between, and then directly pass Surface normal to gbuffer. It definitely won't affect the correctness of the result but SAVE SPACE and IMPROVE TIME EFFICIENCY.
+
+Now the code chaged to
+```javascript
+ vec4 gb0 = texture2D(u_gbufs[0], v_uv);
+ vec4 gb1 = texture2D(u_gbufs[1], v_uv);
+ vec4 gb2 = texture2D(u_gbufs[2], v_uv);
+ float depth = texture2D(u_depth, v_uv).x;
+ vec3 pos = gb0.xyz; // World-space position
+ vec3 nor = normalize(gb1.xyz); // Combine
+ vec3 colmap = gb2.rgb; // The color map - unlit "albedo" (surface color)
+```
+And the optimization results are in the chart below.
+
+We can see, as we increased light numbers, when we still has gb0 - gb3, the time to render one frame is 35ms, 50ms, 66ms. If we reduced the number of GBuffer and has only gb0 - gb2, the time to render one frame is 27ms, 38ms, 52ms. With such results we can say that the time efficiency has been improved about 1.3 times.
### Credits
@@ -31,3 +131,8 @@ to implementation work. Complete the implementation early to leave time!
* [webgl-debug](https://github.com/KhronosGroup/WebGLDeveloperTools) by Khronos Group Inc.
* [glMatrix](https://github.com/toji/gl-matrix) by [@toji](https://github.com/toji) and contributors
* [minimal-gltf-loader](https://github.com/shrekshao/minimal-gltf-loader) by [@shrekshao](https://github.com/shrekshao)
+
+### Extra Credits
+* [Toon Shading](https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Toon_Shading)
+* [Bloom Effect](http://learnopengl.com/#!Advanced-Lighting/Bloom)
+* [Motion Blur](http://http.developer.nvidia.com/GPUGems3/gpugems3_ch27.html)
diff --git a/glsl/clear.frag.glsl b/glsl/clear.frag.glsl
index b4e4ff3..3f86e15 100644
--- a/glsl/clear.frag.glsl
+++ b/glsl/clear.frag.glsl
@@ -3,7 +3,8 @@
precision highp float;
precision highp int;
-#define NUM_GBUFFERS 4
+//#define NUM_GBUFFERS 4
+#define NUM_GBUFFERS 3
void main() {
for (int i = 0; i < NUM_GBUFFERS; i++) {
diff --git a/glsl/copy.frag.glsl b/glsl/copy.frag.glsl
index 823ebcd..e979805 100644
--- a/glsl/copy.frag.glsl
+++ b/glsl/copy.frag.glsl
@@ -10,11 +10,31 @@ varying vec3 v_position;
varying vec3 v_normal;
varying vec2 v_uv;
+/*
+vec3 pos = gb0.xyz; // World-space position
+vec3 geomnor = gb1.xyz; // Normals of the geometry as defined, without normal mapping
+vec3 colmap = gb2.rgb; // The color map - unlit "albedo" (surface color)
+vec3 normap = gb3.xyz; // The raw normal map (normals relative to the surface they're on)
+vec3 nor = applyNormalMap (geomnor, normap); // The true normals as we want to light them - with the normal map applied to the geometry normals (applyNormalMap above)
+*/
+//reduce a normal!
+vec3 applyNormalMap(vec3 geomnor, vec3 normap) {
+ normap = normap * 2.0 - 1.0;
+ vec3 up = normalize(vec3(0.001, 1, 0.001));
+ vec3 surftan = normalize(cross(geomnor, up));
+ vec3 surfbinor = cross(geomnor, surftan);
+ return normap.y * surftan + normap.x * surfbinor + normap.z * geomnor;
+}
+
void main() {
// TODO: copy values into gl_FragData[0], [1], etc.
// You can use the GLSL texture2D function to access the textures using
// the UV in v_uv.
// this gives you the idea
- // gl_FragData[0] = vec4( v_position, 1.0 );
+ gl_FragData[0] = vec4( v_position, 1.0 );
+ // gl_FragData[1] = vec4( v_normal, 1.0 );
+ gl_FragData[1] = vec4(applyNormalMap(v_normal, texture2D(u_normap, v_uv).rgb), 1.0); //conbine normal together
+ gl_FragData[2] = texture2D(u_colmap, v_uv);
+ // gl_FragData[3] = texture2D(u_normap, v_uv);
}
diff --git a/glsl/deferred/ambient.frag.glsl b/glsl/deferred/ambient.frag.glsl
index 1fd4647..274b71d 100644
--- a/glsl/deferred/ambient.frag.glsl
+++ b/glsl/deferred/ambient.frag.glsl
@@ -3,25 +3,28 @@
precision highp float;
precision highp int;
-#define NUM_GBUFFERS 4
-
+//#define NUM_GBUFFERS 4
+#define NUM_GBUFFERS 3
uniform sampler2D u_gbufs[NUM_GBUFFERS];
uniform sampler2D u_depth;
varying vec2 v_uv;
void main() {
- vec4 gb0 = texture2D(u_gbufs[0], v_uv);
- vec4 gb1 = texture2D(u_gbufs[1], v_uv);
+// vec4 gb0 = texture2D(u_gbufs[0], v_uv);
+// vec4 gb1 = texture2D(u_gbufs[1], v_uv);
vec4 gb2 = texture2D(u_gbufs[2], v_uv);
- vec4 gb3 = texture2D(u_gbufs[3], v_uv);
+// vec4 gb3 = texture2D(u_gbufs[3], v_uv);
float depth = texture2D(u_depth, v_uv).x;
// TODO: Extract needed properties from the g-buffers into local variables
+ vec3 colmap = gb2.xyz;
+
if (depth == 1.0) {
gl_FragColor = vec4(0, 0, 0, 0); // set alpha to 0
return;
}
-
- gl_FragColor = vec4(0.1, 0.1, 0.1, 1); // TODO: replace this
+ gl_FragColor = vec4(0.2 * colmap,1.0);
+// Ambient color!
+// gl_FragColor = vec4(0.1, 0.1, 0.1, 1); // TODO: replace this
}
diff --git a/glsl/deferred/blinnphong-pointlight.frag.glsl b/glsl/deferred/blinnphong-pointlight.frag.glsl
index b24a54a..b5da31d 100644
--- a/glsl/deferred/blinnphong-pointlight.frag.glsl
+++ b/glsl/deferred/blinnphong-pointlight.frag.glsl
@@ -2,17 +2,18 @@
precision highp float;
precision highp int;
-#define NUM_GBUFFERS 4
-
+//#define NUM_GBUFFERS 4
+#define NUM_GBUFFERS 3
uniform vec3 u_lightCol;
uniform vec3 u_lightPos;
uniform float u_lightRad;
+uniform vec3 u_camPos; // add camera position
uniform sampler2D u_gbufs[NUM_GBUFFERS];
uniform sampler2D u_depth;
-
+uniform float u_toon;
varying vec2 v_uv;
-vec3 applyNormalMap(vec3 geomnor, vec3 normap) {
+vec3 applyNormalMap(vec3 geomnor, vec3 normap) { //normal map -> geometry normal, each geometry get its normal through this way
normap = normap * 2.0 - 1.0;
vec3 up = normalize(vec3(0.001, 1, 0.001));
vec3 surftan = normalize(cross(geomnor, up));
@@ -24,9 +25,22 @@ void main() {
vec4 gb0 = texture2D(u_gbufs[0], v_uv);
vec4 gb1 = texture2D(u_gbufs[1], v_uv);
vec4 gb2 = texture2D(u_gbufs[2], v_uv);
- vec4 gb3 = texture2D(u_gbufs[3], v_uv);
+// vec4 gb3 = texture2D(u_gbufs[3], v_uv);
float depth = texture2D(u_depth, v_uv).x;
// TODO: Extract needed properties from the g-buffers into local variables
+ // local? extract, alright
+
+ vec3 pos = gb0.xyz;
+ // vec3 geomnor = gb1.xyz;
+ vec3 color = gb2.rgb;
+// vec3 normap = gb3.xyz;
+ vec3 nor = normalize(gb1.xyz);
+
+ vec3 lightDir = normalize(u_lightPos - pos);
+ float distToLight = distance(u_lightPos, pos);
+ vec3 reflDir = reflect(-lightDir, nor);
+ vec3 viewDir = normalize(u_camPos - pos);
+ vec3 halfDir = normalize(lightDir + viewDir);
// If nothing was rendered to this pixel, set alpha to 0 so that the
// postprocessing step can render the sky color.
@@ -35,5 +49,31 @@ void main() {
return;
}
- gl_FragColor = vec4(0, 0, 1, 1); // TODO: perform lighting calculations
+ float attenuation = max(0.0, u_lightRad - length(pos - u_lightPos));
+// float attenuation = 1.0 / (1.0 + u_lightRad * distToLight * distToLight);
+ float lambert = max(dot(lightDir, nor),0.0);
+ float specular = 0.0;
+ if(lambert > 0.0) {
+ float ndotH = max(dot(halfDir,nor),0.0);
+ specular = pow(ndotH, 12.0);
+ }
+ vec3 finalcolor = (lambert * color + specular) * u_lightCol * attenuation;
+ float ndotH = max(dot(halfDir,nor),0.0);
+
+ if (u_toon > 0.6) { //let's make a threshold
+ if (lambert < 0.6) {
+ lambert = 0.2;
+ } else {
+ lambert = 1.0;
+ }
+ if (ndotH > 0.75) {
+ specular = 1.0; //pow(ndotH, 12.0);
+ } else {
+ specular = 0.0;
+ }
+ finalcolor = (lambert * color + specular) * u_lightCol * attenuation;
+ }
+
+ gl_FragColor = vec4(finalcolor, 1.0);
+// gl_FragColor = vec4(0, 0, 1, 1); // TODO: perform lighting calculations
}
diff --git a/glsl/deferred/debug.frag.glsl b/glsl/deferred/debug.frag.glsl
index 007466f..f699c10 100644
--- a/glsl/deferred/debug.frag.glsl
+++ b/glsl/deferred/debug.frag.glsl
@@ -2,12 +2,18 @@
precision highp float;
precision highp int;
-#define NUM_GBUFFERS 4
-
+//#define NUM_GBUFFERS 4
+#define NUM_GBUFFERS 3
uniform int u_debug;
uniform sampler2D u_gbufs[NUM_GBUFFERS];
uniform sampler2D u_depth;
+uniform mat4 u_prevProj;
+uniform vec3 u_camPos;
+
+//http://http.developer.nvidia.com/GPUGems3/gpugems3_ch27.html
+//http://john-chapman-graphics.blogspot.com/2013/01/what-is-motion-blur-motion-pictures-are.html
+//Help! Motion Blur.....
varying vec2 v_uv;
const vec4 SKY_COLOR = vec4(0.66, 0.73, 1.0, 1.0);
@@ -24,29 +30,36 @@ void main() {
vec4 gb0 = texture2D(u_gbufs[0], v_uv);
vec4 gb1 = texture2D(u_gbufs[1], v_uv);
vec4 gb2 = texture2D(u_gbufs[2], v_uv);
- vec4 gb3 = texture2D(u_gbufs[3], v_uv);
+ // vec4 gb3 = texture2D(u_gbufs[3], v_uv);
float depth = texture2D(u_depth, v_uv).x;
// TODO: Extract needed properties from the g-buffers into local variables
// These definitions are suggested for starting out, but you will probably want to change them.
vec3 pos = gb0.xyz; // World-space position
- vec3 geomnor = gb1.xyz; // Normals of the geometry as defined, without normal mapping
+ // vec3 geomnor = gb1.xyz; // Normals of the geometry as defined, without normal mapping
vec3 colmap = gb2.rgb; // The color map - unlit "albedo" (surface color)
- vec3 normap = gb3.xyz; // The raw normal map (normals relative to the surface they're on)
- vec3 nor = applyNormalMap (geomnor, normap); // The true normals as we want to light them - with the normal map applied to the geometry normals (applyNormalMap above)
+// vec3 normap = gb3.xyz; // The raw normal map (normals relative to the surface they're on)
+ vec3 nor = normalize(gb1.xyz);//applyNormalMap (geomnor, normap); // The true normals as we want to light them - with the normal map applied to the geometry normals (applyNormalMap above)
+
+// H is the viewport position at this pixel in the range -1 to 1.
+ vec4 cur_pos = vec4(v_uv.x * 2.0 - 1.0, (1.0 - v_uv.y) * 2.0 - 1.0, depth, 1.0);
+ vec4 prev_pos = u_prevProj * vec4(pos / gb0.w, 1.0);
+ prev_pos /= prev_pos.w;
+ vec2 velocity = (cur_pos.xy - prev_pos.xy) / 2.0;
// TODO: uncomment
if (u_debug == 0) {
gl_FragColor = vec4(vec3(depth), 1.0);
} else if (u_debug == 1) {
- // gl_FragColor = vec4(abs(pos) * 0.1, 1.0);
+ gl_FragColor = vec4(abs(pos) * 0.1, 1.0);
} else if (u_debug == 2) {
- // gl_FragColor = vec4(abs(geomnor), 1.0);
+ gl_FragColor = vec4(abs(nor), 1.0);//vec4(abs(geomnor), 1.0);
} else if (u_debug == 3) {
- // gl_FragColor = vec4(colmap, 1.0);
- } else if (u_debug == 4) {
- // gl_FragColor = vec4(normap, 1.0);
- } else if (u_debug == 5) {
- // gl_FragColor = vec4(abs(nor), 1.0);
+ gl_FragColor = vec4(colmap, 1.0);
+ // } else if (u_debug == 4) {
+ // gl_FragColor = vec4(normap, 1.0);
+ // } else if (u_debug == 5) {
+ // gl_FragColor = vec4(abs(nor), 1.0);
+ // }
} else {
gl_FragColor = vec4(1, 0, 1, 1);
}
diff --git a/glsl/deferred/scissor.frag.glsl b/glsl/deferred/scissor.frag.glsl
new file mode 100644
index 0000000..723d4eb
--- /dev/null
+++ b/glsl/deferred/scissor.frag.glsl
@@ -0,0 +1,7 @@
+#version 100
+precision highp float;
+precision highp int;
+
+void main() {
+ gl_FragColor = vec4(0.5, 0.0, 0.6, 0.1);
+}
diff --git a/glsl/post/bloomblur.frag.glsl b/glsl/post/bloomblur.frag.glsl
new file mode 100644
index 0000000..11c675c
--- /dev/null
+++ b/glsl/post/bloomblur.frag.glsl
@@ -0,0 +1,26 @@
+#version 100
+precision highp float;
+precision highp int;
+
+uniform sampler2D u_color;
+varying vec2 v_uv;
+
+uniform vec2 u_texture;
+
+const vec4 SKY_COLOR = vec4(0.01, 0.14, 0.42, 1.0);
+
+void main() {
+ vec2 per_pix = vec2(1.0,1.0) / u_texture;
+ vec4 gauss = vec4(0.4, 0.32, 0.2, 0.08);
+ vec4 color = vec4 (0.0, 0.0, 0.0, 0.0);
+ color += texture2D(u_color, v_uv ) * gauss[0];
+ for(int i = 1; i <= 3; i++) {
+ color += texture2D(u_color, v_uv + per_pix * vec2(-1.0 * float(i), 0.0)) * gauss[i]; //extract the position's color
+ color += texture2D(u_color, v_uv + per_pix * vec2(float(i), 0.0)) * gauss[i];
+ }
+ // for(int i = 1; i <= 3; i++) {
+ // color += texture2D(u_color, v_uv + 0.01 * vec2(float(i), 0.0)) * gauss[i];
+ // }
+// color = vec4(per_pix,0.0, 1.0);
+ gl_FragColor = color;
+}
diff --git a/glsl/post/bloomblurtwice.frag.glsl b/glsl/post/bloomblurtwice.frag.glsl
new file mode 100644
index 0000000..c6eb2ba
--- /dev/null
+++ b/glsl/post/bloomblurtwice.frag.glsl
@@ -0,0 +1,35 @@
+#version 100
+precision highp float;
+precision highp int;
+
+uniform sampler2D u_color;
+uniform sampler2D u_originalcolor;
+varying vec2 v_uv;
+
+uniform vec2 u_texture;
+
+const vec4 SKY_COLOR = vec4(0.01, 0.14, 0.42, 1.0);
+
+//http://prideout.net/archive/bloom/
+void main() {
+ vec2 per_pix = vec2(1.0,1.0) / u_texture;
+ vec4 gauss = vec4(0.4, 0.32, 0.2, 0.08);
+ vec4 color = vec4 (0.0, 0.0, 0.0, 0.0);
+ color += texture2D(u_color, v_uv + per_pix * vec2(0, 0)) * gauss[0];
+ for(int i = 1; i <= 3; i++) {
+ color += texture2D(u_color, v_uv + per_pix * vec2(0, -1 * i)) * gauss[i]; //extract the position's color
+ color += texture2D(u_color, v_uv + per_pix * vec2(0, i)) * gauss[i];
+ }
+ gl_FragColor = color;
+ vec4 originalcolor = texture2D(u_originalcolor, v_uv);
+// refer to one.frag.glsl
+ // if (color.a == 0.0) {
+ // gl_FragColor = SKY_COLOR;
+ // return;
+ // }
+
+ if (originalcolor.a == 0.0) {
+ originalcolor = SKY_COLOR;
+ }
+ gl_FragColor = color + originalcolor;
+}
diff --git a/glsl/post/bloomextract.frag.glsl b/glsl/post/bloomextract.frag.glsl
new file mode 100644
index 0000000..62b2d89
--- /dev/null
+++ b/glsl/post/bloomextract.frag.glsl
@@ -0,0 +1,20 @@
+#version 100
+precision highp float;
+precision highp int;
+
+uniform sampler2D u_color;
+varying vec2 v_uv;
+
+const vec4 SKY_COLOR = vec4(0.01, 0.14, 0.42, 1.0);
+
+void main() {
+ vec4 org_color = texture2D(u_color, v_uv);
+ vec4 color = clamp(org_color,0.0,1.0);
+ float colorSize = color.r * color.r + color.g * color.g + color.b * color.b;
+ colorSize *= color.a * color.a; //RGBA
+ if (colorSize > 2.5) { //adjust it later
+ gl_FragColor = org_color;
+ } else {
+ gl_FragColor = vec4(0.0,0.0,0.0,0.0);
+ }
+}
diff --git a/glsl/post/motion.frag.glsl b/glsl/post/motion.frag.glsl
new file mode 100644
index 0000000..e1f3e6e
--- /dev/null
+++ b/glsl/post/motion.frag.glsl
@@ -0,0 +1,53 @@
+#version 100
+precision highp float;
+precision highp int;
+
+//http://http.developer.nvidia.com/GPUGems3/gpugems3_ch27.html
+//http://john-chapman-graphics.blogspot.com/2013/01/what-is-motion-blur-motion-pictures-are.html
+//Help! Motion Blur.....
+
+uniform sampler2D u_color;
+
+varying vec2 v_uv;
+
+#define NUM_GBUFFERS 3
+
+uniform mat4 u_prevProj;
+uniform mat4 u_invMat;
+uniform sampler2D u_depth;
+uniform sampler2D u_worldPos;
+uniform vec3 u_camPos;
+
+const vec4 SKY_COLOR = vec4(0.01, 0.14, 0.42, 1.0);
+
+void main() {
+ vec4 color = texture2D(u_color, v_uv);//extract color at (u,v)
+ if (color.a == 0.0) {
+ gl_FragColor = SKY_COLOR;
+ return;
+ }
+ vec2 texCoords = v_uv;
+ float depth = texture2D(u_depth, v_uv).x;
+ if(depth == 1.0) {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
+ return;
+ }
+ vec4 gb0 = texture2D(u_worldPos, v_uv);
+ vec3 pos = gb0.xyz;
+ //HLSL vs GLSL
+ vec4 cur_pos = vec4(v_uv.x * 2.0 - 1.0, v_uv.y * 2.0 - 1.0, depth, 1.0);
+ vec4 prev_pos = u_prevProj * vec4(pos, 1.0);
+ prev_pos /= prev_pos.w;
+ //blur vector got! then we could calculate velocity
+ vec2 velocity = (cur_pos.xy - prev_pos.xy) / 2.0;
+ texCoords += velocity;
+
+//numofsamples = 8 here ?
+ for (int i = 0; i < 8; i++) {
+ vec4 temp_col = texture2D(u_color, texCoords);
+ color += temp_col;
+ texCoords += velocity;
+ }
+ gl_FragColor = color / 8.0;
+
+}
diff --git a/glsl/post/toon.frag.glsl b/glsl/post/toon.frag.glsl
new file mode 100644
index 0000000..6446a31
--- /dev/null
+++ b/glsl/post/toon.frag.glsl
@@ -0,0 +1,39 @@
+#version 100
+precision highp float;
+precision highp int;
+
+uniform sampler2D u_color;
+uniform sampler2D u_depth;
+varying vec2 v_uv;
+uniform vec2 u_size;
+
+//extract contour
+const vec4 SKY_COLOR = vec4(0.01, 0.14, 0.42, 1.0);
+
+void main() {
+ vec4 color = texture2D(u_color, v_uv);
+ if (color.a == 0.0) {
+ gl_FragColor = SKY_COLOR;
+ return;
+ }
+
+ float depth = texture2D(u_depth, v_uv).x;
+ if(depth == 1.0) {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
+ return;
+ }
+ vec2 x_delta = vec2(1.0 / u_size.x, 0.0);
+ vec2 y_delta = vec2(0.0, 1.0 / u_size.y);
+//https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Toon_Shading
+//edge detection algorithm!!!
+ float contour = abs(4.0 * depth - texture2D(u_depth, v_uv + x_delta).x // right
+ - texture2D(u_depth, v_uv - x_delta).x //left
+ - texture2D(u_depth, v_uv + y_delta).x //down
+ - texture2D(u_depth, v_uv - y_delta).x); //up
+ if(contour > 0.002) {
+ gl_FragColor = vec4(0, 0, 0, 1);
+ return;
+ }
+ gl_FragColor = color;
+ //gl_FragColor = color;
+}
diff --git a/glsl/red.frag.glsl b/glsl/red.frag.glsl
index f8ef1ec..16739c8 100644
--- a/glsl/red.frag.glsl
+++ b/glsl/red.frag.glsl
@@ -3,5 +3,5 @@ precision highp float;
precision highp int;
void main() {
- gl_FragColor = vec4(1, 0, 0, 1);
+ gl_FragColor = vec4(0.7, 0, 0.7, 0.1);
}
diff --git a/index.html b/index.html
index 7ada197..798819e 100644
--- a/index.html
+++ b/index.html
@@ -101,7 +101,7 @@
DEBUG MODE!
(Disable before measuring performance.)
-
+
diff --git a/js/deferredRender.js b/js/deferredRender.js
index bb3edd4..f472302 100644
--- a/js/deferredRender.js
+++ b/js/deferredRender.js
@@ -1,6 +1,7 @@
(function() {
'use strict';
// deferredSetup.js must be loaded first
+ var prev_matrix;
R.deferredRender = function(state) {
if (!aborted && (
@@ -10,7 +11,13 @@
!R.prog_Ambient ||
!R.prog_BlinnPhong_PointLight ||
!R.prog_Debug ||
- !R.progPost1)) {
+ !R.progPost1 ||
+ !R.progScissor||
+ !R.progToon||
+ !R.progMotion||
+ !R.progbloomextract||
+ !R.progbloomblur||
+ !R.progbloomblurtwice)) {
console.log('waiting for programs to load...');
return;
}
@@ -28,26 +35,42 @@
// CHECKITOUT: START HERE! You can even uncomment this:
//debugger;
+/*
{ // TODO: this block should be removed after testing renderFullScreenQuad
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// TODO: Implement/test renderFullScreenQuad first
renderFullScreenQuad(R.progRed);
return;
}
-
+*/
R.pass_copy.render(state);
-
- if (cfg && cfg.debugView >= 0) {
- // Do a debug render instead of a regular render
- // Don't do any post-processing in debug mode
- R.pass_debug.render(state);
- } else {
+ if (cfg && cfg.debugScissor == true) {
+ // if I not put is here, debugScissor will never be executed
+ R.pass_debug.renderScissor(state);
+ } else if(cfg && cfg.debugView >= 0) {
+ R.pass_debug.render(state); //if do not adjust, will never come in this
// * Deferred pass and postprocessing pass(es)
// TODO: uncomment these
- // R.pass_deferred.render(state);
- // R.pass_post1.render(state);
-
+ } else {
+ R.pass_deferred.render(state);
+ if(cfg.bloom == true) {
+ R.pass_bloomextract.render(state);
+ R.pass_bloomblur.render(state);
+ R.pass_bloomblurtwice.render(state);
+ } else if(cfg.toon == true) {
+ R.pass_toon.render(state);
+ } else if(cfg.motion == true) {
+ R.pass_motion.render(state);
+ } else {
+ R.pass_post1.render(state);
+ }
// OPTIONAL TODO: call more postprocessing passes, if any
+ // add bloom here
+ // R.pass_bloomextract.render(state);
+ // R.pass_bloomblur.render(state);
+ // R.pass_bloomblurtwice.render(state);
+
+ // R.pass_post1.render(state);
}
};
@@ -57,33 +80,32 @@
R.pass_copy.render = function(state) {
// * Bind the framebuffer R.pass_copy.fbo
// TODO: uncomment
- // gl.bindFramebuffer(gl.FRAMEBUFFER,R.pass_copy.fbo);
-
-
+ gl.bindFramebuffer(gl.FRAMEBUFFER,R.pass_copy.fbo);
// * Clear screen using R.progClear
// TODO: uncomment
- // renderFullScreenQuad(R.progClear);
+ renderFullScreenQuad(R.progClear);
// * Clear depth buffer to value 1.0 using gl.clearDepth and gl.clear
// TODO: uncomment
- // gl.clearDepth(1.0);
- // gl.clear(gl.DEPTH_BUFFER_BIT);
+ gl.clearDepth(1.0);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
// * "Use" the program R.progCopy.prog
// TODO: uncomment
- // gl.useProgram(R.progCopy.prog);
+ gl.useProgram(R.progCopy.prog);
// TODO: Go write code in glsl/copy.frag.glsl
+ // OK!
var m = state.cameraMat.elements;
// * Upload the camera matrix m to the uniform R.progCopy.u_cameraMat
// using gl.uniformMatrix4fv
// TODO: uncomment
- // gl.uniformMatrix4fv(R.progCopy.u_cameraMat, false, m);
+ gl.uniformMatrix4fv(R.progCopy.u_cameraMat, false, m);
// * Draw the scene
// TODO: uncomment
- // drawScene(state);
+ drawScene(state);
};
var drawScene = function(state) {
@@ -101,19 +123,44 @@
R.pass_debug.render = function(state) {
// * Unbind any framebuffer, so we can write to the screen
// TODO: uncomment
- // gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// * Bind/setup the debug "lighting" pass
// * Tell shader which debug view to use
// TODO: uncomment
- // bindTexturesForLightPass(R.prog_Debug);
- // gl.uniform1i(R.prog_Debug.u_debug, cfg.debugView);
-
- // * Render a fullscreen quad to perform shading on
+ bindTexturesForLightPass(R.prog_Debug);
+ gl.uniform1i(R.prog_Debug.u_debug, cfg.debugView);
+ // // * Render a fullscreen quad to perform shading on
// TODO: uncomment
- // renderFullScreenQuad(R.prog_Debug);
+ renderFullScreenQuad(R.prog_Debug);
};
+//try another way
+ R.pass_debug.renderScissor = function(state) {
+ //put it at screen
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ // * Clear depth to 1.0 and color to black
+ gl.clearColor(0.0, 0.0, 0.0, 0.0);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+//https://www.opengl.org/sdk/docs/man/html/glBlendFunc.xhtml
+ gl.enable(gl.BLEND);
+ gl.blendEquation( gl.FUNC_ADD );
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
+
+ gl.enable(gl.SCISSOR_TEST);
+
+ for (var light of R.lights) {
+ var sc = getScissorForLight(state.viewMat, state.projMat, light);
+ if (sc == null) {continue;}
+ gl.scissor(sc[0], sc[1], sc[2], sc[3]);
+ renderFullScreenQuad(R.progScissor);
+ }
+ gl.disable(gl.BLEND);
+ gl.disable(gl.SCISSOR_TEST);
+ };
+
/**
* 'deferred' pass: Add lighting results for each individual light
*/
@@ -130,34 +177,47 @@
// Enable blending and use gl.blendFunc to blend with:
// color = 1 * src_color + 1 * dst_color
- // Here is a wonderful demo of showing how blend function works:
+ // Here is a wonderful demo of showing how blend function works:
// http://mrdoob.github.io/webgl-blendfunctions/blendfunc.html
// TODO: uncomment
- // gl.enable(gl.BLEND);
- // gl.blendEquation( gl.FUNC_ADD );
- // gl.blendFunc(gl.ONE,gl.ONE);
+ gl.enable(gl.BLEND);
+ gl.blendEquation( gl.FUNC_ADD );
+ gl.blendFunc(gl.ONE,gl.ONE);
// * Bind/setup the ambient pass, and render using fullscreen quad
bindTexturesForLightPass(R.prog_Ambient);
renderFullScreenQuad(R.prog_Ambient);
+ gl.enable(gl.SCISSOR_TEST);
// * Bind/setup the Blinn-Phong pass, and render using fullscreen quad
bindTexturesForLightPass(R.prog_BlinnPhong_PointLight);
+ // TODO: In the lighting loop, use the scissor test optimization
+ // Enable gl.SCISSOR_TEST, render all lights, then disable it.
// TODO: add a loop here, over the values in R.lights, which sets the
// uniforms R.prog_BlinnPhong_PointLight.u_lightPos/Col/Rad etc.,
// then does renderFullScreenQuad(R.prog_BlinnPhong_PointLight).
-
- // TODO: In the lighting loop, use the scissor test optimization
- // Enable gl.SCISSOR_TEST, render all lights, then disable it.
- //
- // getScissorForLight returns null if the scissor is off the screen.
- // Otherwise, it returns an array [xmin, ymin, width, height].
- //
- // var sc = getScissorForLight(state.viewMat, state.projMat, light);
-
+ for (var light of R.lights) {
+ var l = light;
+ var sc = getScissorForLight(state.viewMat, state.projMat, light);
+ if(sc != null) {
+ gl.scissor(sc[0],sc[1],sc[2],sc[3]);
+ }
+ var eye = [state.cameraPos.x,state.cameraPos.y,state.cameraPos.z];
+ gl.uniform3fv(R.prog_BlinnPhong_PointLight.u_camPos,eye);
+ gl.uniform3fv(R.prog_BlinnPhong_PointLight.u_lightPos, l.pos);
+ gl.uniform3fv(R.prog_BlinnPhong_PointLight.u_lightCol, l.col);
+ gl.uniform1f(R.prog_BlinnPhong_PointLight.u_lightRad,l.rad);
+ if (cfg.toon) {
+ gl.uniform1f(R.prog_BlinnPhong_PointLight.u_toon, 1.0);
+ } else {
+ gl.uniform1f(R.prog_BlinnPhong_PointLight.u_toon, 0.0);
+ }
+ renderFullScreenQuad(R.prog_BlinnPhong_PointLight);
+ }
// Disable blending so that it doesn't affect other code
- gl.disable(gl.BLEND);
+ gl.disable(gl.SCISSOR_TEST);
+ gl.disable(gl.BLEND);
};
var bindTexturesForLightPass = function(prog) {
@@ -192,11 +252,12 @@
// * Bind the deferred pass's color output as a texture input
// Set gl.TEXTURE0 as the gl.activeTexture unit
// TODO: uncomment
- // gl.activeTexture(gl.TEXTURE0);
+ gl.activeTexture(gl.TEXTURE0);
// Bind the TEXTURE_2D, R.pass_deferred.colorTex to the active texture unit
// TODO: uncomment
- // gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex);
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex);
+ //gl.bindTexture(gl.TEXTURE_2D, R.pass_bloomblurtwice.colorTex);
// Configure the R.progPost1.u_color uniform to point at texture unit 0
gl.uniform1i(R.progPost1.u_color, 0);
@@ -205,6 +266,131 @@
renderFullScreenQuad(R.progPost1);
};
+ R.pass_motion.render = function(state) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.clearDepth(1.0);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+ // * Bind the postprocessing shader program
+ gl.useProgram(R.progMotion.prog);
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex);
+ gl.uniform1i(R.progMotion.u_color, 0);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_copy.gbufs[0]);
+ gl.uniform1i(R.progMotion.u_worldPos, 1);
+
+ gl.activeTexture(gl.TEXTURE2);
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_copy.depthTex);
+ gl.uniform1i(R.progMotion.u_depth, 2);
+
+ if (prev_matrix !== undefined) {
+ gl.uniformMatrix4fv(R.progMotion.u_prevProj, gl.FALSE, prev_matrix.elements);}
+ var inverse_camMatrix = new THREE.Matrix4();
+ inverse_camMatrix = inverse_camMatrix.getInverse(state.cameraMat);
+ gl.uniform3f(R.progMotion.u_camPos, state.cameraPos[0], state.cameraPos[1], state.cameraPos[2]);
+ gl.uniformMatrix4fv(R.progMotion.u_invMat, gl.FALSE, inverse_camMatrix.elements);
+ prev_matrix = state.cameraMat.clone();
+ renderFullScreenQuad(R.progMotion);
+ }
+
+ R.pass_toon.render = function(state) {
+ // * Unbind any existing framebuffer (if there are no more passes)
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ // * Clear the framebuffer depth to 1.0
+ gl.clearDepth(1.0);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+
+ // * Bind the postprocessing shader program
+ gl.useProgram(R.progToon.prog);
+ // * Bind the deferred pass's color output as a texture input
+ // Set gl.TEXTURE0 as the gl.activeTexture unit
+ gl.activeTexture(gl.TEXTURE0);
+ // Bind the TEXTURE_2D, R.pass_deferred.colorTex to the active texture unit
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex);
+ // Configure the R.progPost1.u_color uniform to point at texture unit 0
+ gl.uniform1i(R.progToon.u_color, 0);
+
+ var tSize = [width,height];
+ gl.uniform2fv(R.progToon.u_size, tSize);
+
+ gl.activeTexture(gl['TEXTURE' + R.NUM_GBUFFERS]);
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_copy.depthTex);
+ gl.uniform1i(R.progToon.u_depth, R.NUM_GBUFFERS);
+
+ renderFullScreenQuad(R.progToon);
+
+ };
+
+
+ R.pass_bloomextract.render = function(state) {
+ // * Unbind any existing framebuffer (if there are no more passes)
+ gl.bindFramebuffer(gl.FRAMEBUFFER, R.pass_bloomextract.fbo);
+
+ // * Clear the framebuffer depth to 1.0
+ gl.clearDepth(1.0);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+ // * Bind the postprocessing shader program
+ gl.useProgram(R.progbloomextract.prog);
+
+ // * Bind the deferred pass's color output as a texture input
+ // Set gl.TEXTURE0 as the gl.activeTexture unit
+
+ gl.activeTexture(gl.TEXTURE0);
+ // Bind the TEXTURE_2D, R.pass_deferred.colorTex to the active texture unit
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex);
+
+ gl.uniform1i(R.progbloomextract.u_color, 0);
+ renderFullScreenQuad(R.progbloomextract);
+ }
+
+ R.pass_bloomblur.render = function(state) {
+ // * Unbind any existing framebuffer (if there are no more passes)
+ gl.bindFramebuffer(gl.FRAMEBUFFER, R.pass_bloomblur.fbo);
+
+ // * Clear the framebuffer depth to 1.0
+ gl.clearDepth(1.0);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+ // * Bind the postprocessing shader program
+ gl.useProgram(R.progbloomblur.prog);
+
+ gl.activeTexture(gl.TEXTURE0);
+ // Bind the TEXTURE_2D, R.pass_deferred.colorTex to the active texture unit
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_bloomextract.colorTex);
+
+ gl.uniform1i(R.progbloomblur.u_color, 0);
+ var tSize = [width,height];
+ gl.uniform2fv(R.progbloomblur.u_texture,tSize);
+ // * Render a fullscreen quad
+ renderFullScreenQuad(R.progbloomblur);
+ }
+
+ R.pass_bloomblurtwice.render = function(state) {
+ // * Unbind any existing framebuffer (if there are no more passes)
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ // * Clear the framebuffer depth to 1.0
+ gl.clearDepth(1.0);
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+ // * Bind the postprocessing shader program
+ gl.useProgram(R.progbloomblurtwice.prog);
+
+ gl.activeTexture(gl.TEXTURE0);
+ // Bind the TEXTURE_2D, R.pass_deferred.colorTex to the active texture unit
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_bloomblur.colorTex);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex);
+
+ gl.uniform1i(R.progbloomblurtwice.u_color, 0);
+ gl.uniform1i(R.progbloomblurtwice.u_originalcolor, 1);
+ var tSize = [width,height];
+ gl.uniform2fv(R.progbloomblurtwice.u_texture,tSize);
+ // * Render a fullscreen quad
+ renderFullScreenQuad(R.progbloomblurtwice);
+ }
+
var renderFullScreenQuad = (function() {
// The variables in this function are private to the implementation of
// renderFullScreenQuad. They work like static local variables in C++.
@@ -230,12 +416,12 @@
// Bind the VBO as the gl.ARRAY_BUFFER
// TODO: uncomment
- // gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
+ gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
// Upload the positions array to the currently-bound array buffer
// using gl.bufferData in static draw mode.
// TODO: uncomment
- // gl.bufferData(gl.ARRAY_BUFFER,positions,gl.STATIC_DRAW);
+ gl.bufferData(gl.ARRAY_BUFFER,positions,gl.STATIC_DRAW);
};
return function(prog) {
@@ -249,24 +435,24 @@
// Bind the VBO as the gl.ARRAY_BUFFER
// TODO: uncomment
- // gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
// Enable the bound buffer as the vertex attrib array for
// prog.a_position, using gl.enableVertexAttribArray
// TODO: uncomment
- // gl.enableVertexAttribArray(prog.a_position);
+ gl.enableVertexAttribArray(prog.a_position);
// Use gl.vertexAttribPointer to tell WebGL the type/layout for
// prog.a_position's access pattern.
// TODO: uncomment
- // gl.vertexAttribPointer(prog.a_position, 3, gl.FLOAT, gl.FALSE, 0, 0);
+ gl.vertexAttribPointer(prog.a_position, 3, gl.FLOAT, gl.FALSE, 0, 0);
// Use gl.drawArrays (or gl.drawElements) to draw your quad.
// TODO: uncomment
- // gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
- // Unbind the array buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ // Unbind the array buffer.
};
})();
})();
diff --git a/js/deferredSetup.js b/js/deferredSetup.js
index 65136e0..9e29d24 100644
--- a/js/deferredSetup.js
+++ b/js/deferredSetup.js
@@ -6,10 +6,15 @@
R.pass_debug = {};
R.pass_deferred = {};
R.pass_post1 = {};
+ R.pass_motion = {};
+ R.pass_toon = {};
+ R.pass_bloomextract = {};
+ R.pass_bloomblur = {};
+ R.pass_bloomblurtwice = {};
R.lights = [];
- R.NUM_GBUFFERS = 4;
-
+ // R.NUM_GBUFFERS = 4;
+ R.NUM_GBUFFERS = 3;
/**
* Set up the deferred pipeline framebuffer objects and textures.
*/
@@ -18,6 +23,10 @@
loadAllShaderPrograms();
R.pass_copy.setup();
R.pass_deferred.setup();
+// R.pass_toon.setup();
+ R.pass_bloomextract.setup();
+ R.pass_bloomblur.setup();
+ R.pass_bloomblurtwice.setup();
};
// TODO: Edit if you want to change the light initial positions
@@ -98,6 +107,48 @@
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};
+ R.pass_bloomextract.setup = function() {
+ // * Create the FBO
+ R.pass_bloomextract.fbo = gl.createFramebuffer();
+ // * Create, bind, and store a single color target texture for the FBO
+ R.pass_bloomextract.colorTex = createAndBindColorTargetTexture(
+ R.pass_bloomextract.fbo, gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL);
+ // * Check for framebuffer errors
+ abortIfFramebufferIncomplete(R.pass_bloomextract.fbo);
+ // * Tell the WEBGL_draw_buffers extension which FBO attachments are
+ // being used. (This extension allows for multiple render targets.)
+ gl_draw_buffers.drawBuffersWEBGL([gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL]);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ };
+
+ R.pass_bloomblur.setup = function() {
+ // * Create the FBO
+ R.pass_bloomblur.fbo = gl.createFramebuffer();
+ // * Create, bind, and store a single color target texture for the FBO
+ R.pass_bloomblur.colorTex = createAndBindColorTargetTexture(
+ R.pass_bloomblur.fbo, gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL);
+
+ abortIfFramebufferIncomplete(R.pass_bloomblur.fbo);
+ // * Tell the WEBGL_draw_buffers extension which FBO attachments are
+ // being used. (This extension allows for multiple render targets.)
+ gl_draw_buffers.drawBuffersWEBGL([gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL]);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ };
+
+
+ R.pass_bloomblurtwice.setup = function() {
+ // * Create the FBO
+ R.pass_bloomblurtwice.fbo = gl.createFramebuffer();
+ // * Create, bind, and store a single color target texture for the FBO
+ R.pass_bloomblurtwice.colorTex = createAndBindColorTargetTexture(
+ R.pass_bloomblurtwice.fbo, gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL);
+
+ abortIfFramebufferIncomplete(R.pass_bloomblurtwice.fbo);
+ // * Tell the WEBGL_draw_buffers extension which FBO attachments are
+ // being used. (This extension allows for multiple render targets.)
+ gl_draw_buffers.drawBuffersWEBGL([gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL]);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ };
/**
* Loads all of the shader programs used in the pipeline.
*/
@@ -141,9 +192,15 @@
p.u_lightPos = gl.getUniformLocation(p.prog, 'u_lightPos');
p.u_lightCol = gl.getUniformLocation(p.prog, 'u_lightCol');
p.u_lightRad = gl.getUniformLocation(p.prog, 'u_lightRad');
+ p.u_camPos = gl.getUniformLocation(p.prog, 'u_camPos');
+ p.u_toon = gl.getUniformLocation(p.prog, 'u_toon');
R.prog_BlinnPhong_PointLight = p;
});
+ loadDeferredProgram('scissor', function(p) {
+ R.progScissor = p;
+ });
+
loadDeferredProgram('debug', function(p) {
p.u_debug = gl.getUniformLocation(p.prog, 'u_debug');
// Save the object into this variable for access later
@@ -156,7 +213,44 @@
R.progPost1 = p;
});
- // TODO: If you add more passes, load and set up their shader programs.
+ // TODO: If you add more passes, load and set up their shader programs.
+ loadPostProgram('motion', function(p) {
+ p.u_color = gl.getUniformLocation(p.prog, 'u_color');
+ p.u_prevProj = gl.getUniformLocation(p.prog,'u_prevProj');
+ p.u_invMat = gl.getUniformLocation(p.prog, 'u_invMat');
+ p.u_worldPos = gl.getUniformLocation(p.prog, 'u_worldPos');
+ p.u_depth = gl.getUniformLocation(p.prog, 'u_depth');
+ p.u_camPos = gl.getUniformLocation(p.prog, 'u_camPos');
+ R.progMotion = p;
+ });
+
+ loadPostProgram('toon', function(p) {
+ p.u_color = gl.getUniformLocation(p.prog, 'u_color');
+ p.u_size = gl.getUniformLocation(p.prog, 'u_size');
+ p.u_depth = gl.getUniformLocation(p.prog, 'u_depth');
+ R.progToon = p;
+ });
+
+ loadPostProgram('bloomextract', function(p) {
+ p.u_color = gl.getUniformLocation(p.prog, 'u_color');
+ // Save the object into this variable for access later
+ R.progbloomextract = p;
+ });
+
+ loadPostProgram('bloomblur', function(p) {
+ p.u_color = gl.getUniformLocation(p.prog, 'u_color');
+ p.u_texture = gl.getUniformLocation(p.prog, 'u_texture');
+ // Save the object into this variable for access later
+ R.progbloomblur = p;
+ });
+
+ loadPostProgram('bloomblurtwice', function(p) {
+ p.u_color = gl.getUniformLocation(p.prog, 'u_color');
+ p.u_texture = gl.getUniformLocation(p.prog, 'u_texture');
+ p.u_originalcolor = gl.getUniformLocation(p.prog, 'u_originalcolor');
+ // Save the object into this variable for access later
+ R.progbloomblurtwice = p;
+ });
};
var loadDeferredProgram = function(name, callback) {
diff --git a/js/framework.js b/js/framework.js
index 4f944ee..0f02d01 100644
--- a/js/framework.js
+++ b/js/framework.js
@@ -67,7 +67,7 @@ var width, height;
var init = function() {
// TODO: For performance measurements, disable debug mode!
- var debugMode = true;
+ var debugMode = false;
canvas = document.getElementById('canvas');
renderer = new THREE.WebGLRenderer({
@@ -187,8 +187,8 @@ var width, height;
gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, magFilter);
gl.texParameteri(target, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(target, gl.TEXTURE_WRAP_T, wrapT);
- if (minFilter == gl.NEAREST_MIPMAP_NEAREST ||
- minFilter == gl.NEAREST_MIPMAP_LINEAR ||
+ if (minFilter == gl.NEAREST_MIPMAP_NEAREST ||
+ minFilter == gl.NEAREST_MIPMAP_LINEAR ||
minFilter == gl.LINEAR_MIPMAP_NEAREST ||
minFilter == gl.LINEAR_MIPMAP_LINEAR ) {
gl.generateMipmap(target);
@@ -245,7 +245,7 @@ var width, height;
uvInfo: {size: uvInfo.size, type: uvInfo.type, stride: uvInfo.stride, offset: uvInfo.offset},
// specific textures temp test
- colmap: webGLTextures[colorTextureName].texture,
+ colmap: webGLTextures[colorTextureName].texture,
normap: webGLTextures[normalTextureName].texture
});
@@ -254,7 +254,7 @@ var width, height;
}
-
+
});
diff --git a/js/ui.js b/js/ui.js
index abd6119..3f81a1b 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -8,6 +8,9 @@ var cfg;
this.debugView = -1;
this.debugScissor = false;
this.enableEffect0 = false;
+ this.bloom = false;
+ this.toon = false;
+ this.motion = false;
};
var init = function() {
@@ -19,16 +22,21 @@ var cfg;
'None': -1,
'0 Depth': 0,
'1 Position': 1,
- '2 Geometry normal': 2,
+ '2 Surface normal': 2,
'3 Color map': 3,
- '4 Normal map': 4,
- '5 Surface normal': 5
+ // '2 Geometry normal': 2,
+ // '3 Color map': 3,
+ // '4 Normal map': 4,
+ // '5 Surface normal': 5
});
gui.add(cfg, 'debugScissor');
- var eff0 = gui.addFolder('EFFECT NAME HERE');
+ // var eff0 = gui.addFolder('EFFECT NAME HERE');
+ var eff0 = gui.addFolder('EFFECT');
eff0.open();
- eff0.add(cfg, 'enableEffect0');
+ eff0.add(cfg, 'bloom');
+ eff0.add(cfg, 'toon');
+ eff0.add(cfg, 'motion');
// TODO: add more effects toggles and parameters here
};
diff --git a/js/util.js b/js/util.js
index 8f43d38..831326e 100644
--- a/js/util.js
+++ b/js/util.js
@@ -93,7 +93,7 @@ window.readyModelForDraw = function(prog, m) {
}
gl.bindBuffer(gl.ARRAY_BUFFER, m.attributes);
-
+
gl.enableVertexAttribArray(prog.a_position);
gl.vertexAttribPointer(prog.a_position, m.posInfo.size, m.posInfo.type, false, m.posInfo.stride, m.posInfo.offset);
@@ -146,7 +146,8 @@ window.getScissorForLight = (function() {
maxpt.set(Math.min( 1, b.x), Math.min( 1, b.y));
if (maxpt.x < -1 || 1 < minpt.x ||
- maxpt.y < -1 || 1 < minpt.y) {
+ maxpt.y < -1 || 1 < minpt.y ||
+ minpt.x > maxpt.x || minpt.y > maxpt.y) {
return null;
}
diff --git a/lib/three.js b/lib/three.js
index bb11aa6..131a707 100644
--- a/lib/three.js
+++ b/lib/three.js
@@ -2520,9 +2520,9 @@ THREE.Vector3.prototype = {
projectOnVector: function ( vector ) {
var scalar = vector.dot( this ) / vector.lengthSq();
-
+
return this.copy( vector ).multiplyScalar( scalar );
-
+
},
projectOnPlane: function () {
@@ -3573,7 +3573,7 @@ THREE.Euler.prototype = {
return function reorder( newOrder ) {
q.setFromEuler( this );
-
+
return this.setFromQuaternion( q, newOrder );
};
@@ -4691,7 +4691,7 @@ THREE.Matrix3.prototype = {
return this.identity();
}
-
+
var detInv = 1 / det;
te[ 0 ] = t11 * detInv;
@@ -5425,7 +5425,7 @@ THREE.Matrix4.prototype = {
return this.identity();
}
-
+
var detInv = 1 / det;
te[ 0 ] = t11 * detInv;
@@ -36024,7 +36024,7 @@ THREE.CubicBezierCurve.prototype.getPoint = function ( t ) {
var b3 = THREE.ShapeUtils.b3;
- return new THREE.Vector2(
+ return new THREE.Vector2(
b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ),
b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y )
);
@@ -36035,7 +36035,7 @@ THREE.CubicBezierCurve.prototype.getTangent = function( t ) {
var tangentCubicBezier = THREE.CurveUtils.tangentCubicBezier;
- return new THREE.Vector2(
+ return new THREE.Vector2(
tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ),
tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y )
).normalize();
@@ -36233,7 +36233,7 @@ THREE.QuadraticBezierCurve3 = THREE.Curve.create(
function ( t ) {
- var b2 = THREE.ShapeUtils.b2;
+ var b2 = THREE.ShapeUtils.b2;
return new THREE.Vector3(
b2( t, this.v0.x, this.v1.x, this.v2.x ),
@@ -41758,4 +41758,3 @@ THREE.MorphBlendMesh.prototype.update = function ( delta ) {
}
};
-
diff --git a/result/GBuffer charts.PNG b/result/GBuffer charts.PNG
new file mode 100644
index 0000000..f6a4087
Binary files /dev/null and b/result/GBuffer charts.PNG differ
diff --git a/result/Scissor charts.PNG b/result/Scissor charts.PNG
new file mode 100644
index 0000000..159d751
Binary files /dev/null and b/result/Scissor charts.PNG differ
diff --git a/result/blinn-phong.gif b/result/blinn-phong.gif
new file mode 100644
index 0000000..ba0aeec
Binary files /dev/null and b/result/blinn-phong.gif differ
diff --git a/result/bloom!!!debug!!!.gif b/result/bloom!!!debug!!!.gif
new file mode 100644
index 0000000..0780a7f
Binary files /dev/null and b/result/bloom!!!debug!!!.gif differ
diff --git a/result/bloom...wtf.gif b/result/bloom...wtf.gif
new file mode 100644
index 0000000..71a8a7e
Binary files /dev/null and b/result/bloom...wtf.gif differ
diff --git a/result/debug_scissor.gif b/result/debug_scissor.gif
new file mode 100644
index 0000000..7423bda
Binary files /dev/null and b/result/debug_scissor.gif differ
diff --git a/result/debug_scissor2.gif b/result/debug_scissor2.gif
new file mode 100644
index 0000000..f6cfa67
Binary files /dev/null and b/result/debug_scissor2.gif differ
diff --git a/result/deferred-1478403692432.png b/result/deferred-1478403692432.png
new file mode 100644
index 0000000..4fd5cfd
Binary files /dev/null and b/result/deferred-1478403692432.png differ
diff --git a/result/deferred-1478436556417.png b/result/deferred-1478436556417.png
new file mode 100644
index 0000000..ddf7e64
Binary files /dev/null and b/result/deferred-1478436556417.png differ
diff --git a/result/deferred-1478436560546.png b/result/deferred-1478436560546.png
new file mode 100644
index 0000000..84ae9b4
Binary files /dev/null and b/result/deferred-1478436560546.png differ
diff --git a/result/deferred-1478436569856.png b/result/deferred-1478436569856.png
new file mode 100644
index 0000000..12545f2
Binary files /dev/null and b/result/deferred-1478436569856.png differ
diff --git a/result/deferred-1478436575930.png b/result/deferred-1478436575930.png
new file mode 100644
index 0000000..54ef552
Binary files /dev/null and b/result/deferred-1478436575930.png differ
diff --git a/result/deferred-1478436581008.png b/result/deferred-1478436581008.png
new file mode 100644
index 0000000..dcdcd4a
Binary files /dev/null and b/result/deferred-1478436581008.png differ
diff --git a/result/deferred-1478436585799.png b/result/deferred-1478436585799.png
new file mode 100644
index 0000000..451e5a0
Binary files /dev/null and b/result/deferred-1478436585799.png differ
diff --git a/result/intro_to_video.PNG b/result/intro_to_video.PNG
new file mode 100644
index 0000000..a21b303
Binary files /dev/null and b/result/intro_to_video.PNG differ
diff --git a/result/motion_blur_blooper.gif b/result/motion_blur_blooper.gif
new file mode 100644
index 0000000..f52b77b
Binary files /dev/null and b/result/motion_blur_blooper.gif differ
diff --git a/result/motion_blur_correct.gif b/result/motion_blur_correct.gif
new file mode 100644
index 0000000..8b8d51f
Binary files /dev/null and b/result/motion_blur_correct.gif differ
diff --git a/result/motion_blur_correct2.gif b/result/motion_blur_correct2.gif
new file mode 100644
index 0000000..5f6e720
Binary files /dev/null and b/result/motion_blur_correct2.gif differ
diff --git a/result/only_bloom.gif b/result/only_bloom.gif
new file mode 100644
index 0000000..a387734
Binary files /dev/null and b/result/only_bloom.gif differ
diff --git a/result/profiling.xlsx b/result/profiling.xlsx
new file mode 100644
index 0000000..26c87a2
Binary files /dev/null and b/result/profiling.xlsx differ
diff --git a/result/toon-shading.gif b/result/toon-shading.gif
new file mode 100644
index 0000000..3cef82b
Binary files /dev/null and b/result/toon-shading.gif differ
diff --git a/result/without-toon-shading.gif b/result/without-toon-shading.gif
new file mode 100644
index 0000000..a4411ff
Binary files /dev/null and b/result/without-toon-shading.gif differ
diff --git a/result/without_bloom.gif b/result/without_bloom.gif
new file mode 100644
index 0000000..45f4e13
Binary files /dev/null and b/result/without_bloom.gif differ
diff --git a/result/without_motion_blur.gif b/result/without_motion_blur.gif
new file mode 100644
index 0000000..dec6add
Binary files /dev/null and b/result/without_motion_blur.gif differ