diff --git a/README.md b/README.md index da4c7e1..00da54f 100644 --- a/README.md +++ b/README.md @@ -3,55 +3,40 @@ CIS565: Project 6 -- Deferred Shader ------------------------------------------------------------------------------- Fall 2014 ------------------------------------------------------------------------------- -Due Wed, 11/12/2014 at Noon +RESULTS: ------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -NOTE: -------------------------------------------------------------------------------- -This project requires any graphics card with support for a modern OpenGL -pipeline. Any AMD, NVIDIA, or Intel card from the past few years should work -fine, and every machine in the SIG Lab and Moore 100 is capable of running -this project. +[Run The Demo](http://diracsea3921.github.io/Project6-DeferredShader/) -This project also requires a WebGL capable browser. The project is known to -have issues with Chrome on windows, but Firefox seems to run it fine. -------------------------------------------------------------------------------- -INTRODUCTION: -------------------------------------------------------------------------------- -In this project, you will get introduced to the basics of deferred shading. You will write GLSL and OpenGL code to perform various tasks in a deferred lighting pipeline such as creating and writing to a G-Buffer. +* Diffuse and Blinn-Phong shading + +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled6.png) -------------------------------------------------------------------------------- -CONTENTS: -------------------------------------------------------------------------------- -The Project5 root directory contains the following subdirectories: - -* js/ contains the javascript files, including external libraries, necessary. -* assets/ contains the textures that will be used in the second half of the - assignment. -* resources/ contains the screenshots found in this readme file. +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled2.png) - This Readme file edited as described above in the README section. +* Bloom -------------------------------------------------------------------------------- -OVERVIEW: -------------------------------------------------------------------------------- -The deferred shader you will write will have the following stages: +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled7.png) -Stage 1 renders the scene geometry to the G-Buffer -* pass.vert -* pass.frag +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled3.png) -Stage 2 renders the lighting passes and accumulates to the P-Buffer -* quad.vert -* diffuse.frag -* diagnostic.frag +* "Toon" Shading (with normal based silhouetting) -Stage 3 renders the post processing -* post.vert -* post.frag +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled8.png) + +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled4.png) + +* Screen Space Ambient Occlusion + +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled5.png) + +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/Untitled1.png) + +------------------------------------------------------------------------------- +CONTROLS: +------------------------------------------------------------------------------- The keyboard controls are as follows: WASDRF - Movement (along w the arrow keys) @@ -69,77 +54,28 @@ WASDRF - Movement (along w the arrow keys) * 2 - Normals * 3 - Color * 4 - Depth +* 5 - Bloom +* 6 - Toon Shading +* 7 - SSAO * 0 - Full deferred pipeline -There are also mouse controls for camera rotation. - ------------------------------------------------------------------------------- -REQUIREMENTS: +PERFORMANCE: ------------------------------------------------------------------------------- -In this project, you are given code for: -* Loading .obj file -* Deferred shading pipeline -* GBuffer pass +I did some test for Bloom and SSAO effect with different samples number. For the Bloom effect the fps drop very quickly with the samples number increasing. +I think it will be better to separate this step into two passes, which will greatly benefit the efficiency. + +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/image.png) -You are required to implement: -* Either of the following effects - * Bloom - * "Toon" Shading (with basic silhouetting) -* Screen Space Ambient Occlusion -* Diffuse and Blinn-Phong shading - -**NOTE**: Implementing separable convolution will require another link in your pipeline and will count as an extra feature if you do performance analysis with a standard one-pass 2D convolution. The overhead of rendering and reading from a texture _may_ offset the extra computations for smaller 2D kernels. - -You must implement two of the following extras: -* The effect you did not choose above -* Compare performance to a normal forward renderer with - * No optimizations - * Coarse sort geometry front-to-back for early-z - * Z-prepass for early-z -* Optimize g-buffer format, e.g., pack things together, quantize, reconstruct z from normal x and y (because it is normalized), etc. - * Must be accompanied with a performance analysis to count -* Additional lighting and pre/post processing effects! (email first please, if they are good you may add multiple). - -------------------------------------------------------------------------------- -RUNNING THE CODE: -------------------------------------------------------------------------------- - -Since the code attempts to access files that are local to your computer, you -will either need to: - -* Run your browser under modified security settings, or -* Create a simple local server that serves the files - - -FIREFOX: change ``strict_origin_policy`` to false in about:config - -CHROME: run with the following argument : `--allow-file-access-from-files` - -(You can do this on OSX by running Chrome from /Applications/Google -Chrome/Contents/MacOS with `open -a "Google Chrome" --args ---allow-file-access-from-files`) - -* To check if you have set the flag properly, you can open chrome://version and - check under the flags - -RUNNING A SIMPLE SERVER: - -If you have Python installed, you can simply run a simple HTTP server off your -machine from the root directory of this repository with the following command: - -`python -m SimpleHTTPServer` +![](https://github.com/DiracSea3921/Project6-DeferredShader/blob/master/image2.png) ------------------------------------------------------------------------------- -RESOURCES: +REFERENCES: ------------------------------------------------------------------------------- -The following are articles and resources that have been chosen to help give you -a sense of each of the effects: - * Bloom : [GPU Gems](http://http.developer.nvidia.com/GPUGems/gpugems_ch21.html) -* Screen Space Ambient Occlusion : [Floored - Article](http://floored.com/blog/2013/ssao-screen-space-ambient-occlusion.html) +* Screen Space Ambient Occlusion : (http://john-chapman-graphics.blogspot.com/2013/01/ssao-tutorial.html) ------------------------------------------------------------------------------- README diff --git a/Untitled1.png b/Untitled1.png new file mode 100644 index 0000000..cea8d94 Binary files /dev/null and b/Untitled1.png differ diff --git a/Untitled2.png b/Untitled2.png new file mode 100644 index 0000000..cc0a14c Binary files /dev/null and b/Untitled2.png differ diff --git a/Untitled3.png b/Untitled3.png new file mode 100644 index 0000000..9ea6ce4 Binary files /dev/null and b/Untitled3.png differ diff --git a/Untitled4.png b/Untitled4.png new file mode 100644 index 0000000..309eb58 Binary files /dev/null and b/Untitled4.png differ diff --git a/Untitled5.png b/Untitled5.png new file mode 100644 index 0000000..89f9b3d Binary files /dev/null and b/Untitled5.png differ diff --git a/Untitled6.png b/Untitled6.png new file mode 100644 index 0000000..0dbc715 Binary files /dev/null and b/Untitled6.png differ diff --git a/Untitled7.png b/Untitled7.png new file mode 100644 index 0000000..aa49b77 Binary files /dev/null and b/Untitled7.png differ diff --git a/Untitled8.png b/Untitled8.png new file mode 100644 index 0000000..1e4256d Binary files /dev/null and b/Untitled8.png differ diff --git a/assets/deferred/diffuse.frag b/assets/deferred/diffuse.frag index ef0c5fc..bc9f52e 100644 --- a/assets/deferred/diffuse.frag +++ b/assets/deferred/diffuse.frag @@ -5,6 +5,7 @@ uniform sampler2D u_normalTex; uniform sampler2D u_colorTex; uniform sampler2D u_depthTex; +uniform mat4 u_modelview; uniform float u_zFar; uniform float u_zNear; uniform int u_displayType; @@ -19,5 +20,17 @@ void main() { // Write a diffuse shader and a Blinn-Phong shader // NOTE : You may need to add your own normals to fulfill the second's requirements - gl_FragColor = vec4(texture2D(u_colorTex, v_texcoord).rgb, 1.0); + + vec3 position = texture2D(u_positionTex, v_texcoord).rgb; + vec3 normal = texture2D( u_normalTex, v_texcoord ).rgb; + vec3 color = texture2D( u_colorTex, v_texcoord ).rgb; + float depth = texture2D(u_depthTex, v_texcoord).r; + + vec3 lightPos = vec3(5.0, 5.0, 5.0); + vec3 lightDir = normalize((u_modelview * vec4(lightPos,1.0)).xyz - position); + vec3 reflect = reflect(-lightDir, normal); + float diffuse = clamp(dot(lightDir, normal),0.0,1.0); + float specular = pow(max(dot(reflect, -normalize(position)), 0.0), 25.0); + + gl_FragColor = diffuse * vec4(color, 1.0) + 0.2 * specular * vec4(1.0,1.0,1.0,1.0); } diff --git a/assets/shader/deferred/diffuse.frag b/assets/shader/deferred/diffuse.frag index ef0c5fc..87e0804 100644 --- a/assets/shader/deferred/diffuse.frag +++ b/assets/shader/deferred/diffuse.frag @@ -5,10 +5,11 @@ uniform sampler2D u_normalTex; uniform sampler2D u_colorTex; uniform sampler2D u_depthTex; +uniform mat4 u_modelview; uniform float u_zFar; uniform float u_zNear; uniform int u_displayType; - +uniform float u_toon; varying vec2 v_texcoord; float linearizeDepth( float exp_depth, float near, float far ){ @@ -19,5 +20,20 @@ void main() { // Write a diffuse shader and a Blinn-Phong shader // NOTE : You may need to add your own normals to fulfill the second's requirements - gl_FragColor = vec4(texture2D(u_colorTex, v_texcoord).rgb, 1.0); + + vec3 position = texture2D(u_positionTex, v_texcoord).rgb; + vec3 normal = texture2D( u_normalTex, v_texcoord ).rgb; + vec3 color = texture2D( u_colorTex, v_texcoord ).rgb; + float depth = texture2D(u_depthTex, v_texcoord).r; + + vec3 lightPos = vec3(5.0, 5.0, 5.0); + vec3 lightDir = normalize((u_modelview * vec4(lightPos,1.0)).xyz - position); + vec3 reflect = reflect(-lightDir, normal); + float diffuse = clamp(dot(lightDir, normal),0.0,1.0); + float specular = pow(max(dot(reflect, -normalize(position)), 0.0), 25.0); + + gl_FragColor = diffuse * vec4(color, 1.0) + 0.2 * specular * vec4(1.0,1.0,1.0,1.0); + float shade_num = 3.0; + if(u_toon >0.0) + gl_FragColor = floor(gl_FragColor * shade_num)/ shade_num; } diff --git a/assets/shader/deferred/post.frag b/assets/shader/deferred/post.frag index 52edda2..dccbf4d 100644 --- a/assets/shader/deferred/post.frag +++ b/assets/shader/deferred/post.frag @@ -1,6 +1,14 @@ precision highp float; uniform sampler2D u_shadeTex; +uniform sampler2D u_normalTex; +uniform sampler2D u_positionTex; +uniform sampler2D u_depthTex; +uniform float u_bloom; +uniform float u_sihouete; +uniform float u_ssao; +uniform float u_zFar; +uniform float u_zNear; varying vec2 v_texcoord; @@ -8,10 +16,84 @@ float linearizeDepth( float exp_depth, float near, float far ){ return ( 2.0 * near ) / ( far + near - exp_depth * ( far - near ) ); } +//copy from http://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner +float rand(float co){ + return fract(sin(co)) * 43758.5453; +} + void main() { // Currently acts as a pass filter that immmediately renders the shaded texture // Fill in post-processing as necessary HERE // NOTE : You may choose to use a key-controlled switch system to display one feature at a time - gl_FragColor = vec4(texture2D( u_shadeTex, v_texcoord).rgb, 1.0); + vec3 value = texture2D( u_shadeTex, v_texcoord).rgb; + + //Bloom + if(u_bloom > 0.0){ + for(int i = 0; i <= 10; ++i){ + for(int j = 0; j <= 10; ++j){ + vec2 coord = v_texcoord + vec2(float(i - 5)/1024.0, float(j - 5)/1024.0); + vec3 tmp = texture2D( u_shadeTex, coord).rgb; + value += tmp * (6.0 - abs(5.0 - float(i))) * (6.0 - abs(5.0 - float(j))) / 1000.0; + } + } + } + + //sihouete + if(u_sihouete >0.0){ + vec3 c11 = texture2D(u_normalTex, v_texcoord).rgb; + float off = 1.0 / 800.0; + float threadHold = 0.10; + + float s00 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(-off,-off)).rgb)-threadHold); + float s01 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(0.0,-off)).rgb)-threadHold); + float s02 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(off,-off)).rgb)-threadHold); + + float s10 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(-off,0)).rgb)-threadHold); + float s12 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(off,0)).rgb)-threadHold); + + float s20 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(-off,off)).rgb)-threadHold); + float s21 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(0.0,off)).rgb)-threadHold); + float s22 = max(0.0,dot(c11, texture2D(u_normalTex, v_texcoord + vec2(off,off)).rgb)-threadHold); + + float sobelX = s00 + 2.0 * s10 + s20 - s02 - 2.0 * s12 - s22; + float sobelY = s00 + 2.0 * s01 + s02 - s20 - 2.0 * s21 - s22; + float edgeSqr = (sobelX * sobelX + sobelY * sobelY); + + if(edgeSqr > 0.07 * 0.07) + gl_FragColor = vec4(0,0,0, 1.0); + else + gl_FragColor = vec4(value, 1.0); + } + else + gl_FragColor = vec4(value, 1.0); + + //SSAO + if(u_ssao>0.0){ + float radius = 0.01; + vec3 position = texture2D(u_positionTex,v_texcoord).rgb; + vec3 normal = texture2D(u_normalTex, v_texcoord).rgb; + float depth = texture2D(u_depthTex,v_texcoord).r; + depth = linearizeDepth(depth,u_zNear,u_zFar); + vec3 origin = vec3(position.x, position.y, depth); + float count = 0.0; + + for(int i = 0; i<50; ++i){ + vec3 kernel = normalize(vec3(rand(position.x+ float(i)), rand(position.y+ float(i)), (rand(position.z + float(i))+1.0)/2.0))*0.2; + vec3 rvec = normalize(vec3(0.0, rand(position.y + float(i)), rand(position.z+ float(i)))); + vec3 tangent = normalize(rvec - normal * dot(rvec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 tbn = mat3(tangent, bitangent, normal); + vec3 sampleVector = tbn * kernel; + float sampleDepth = texture2D(u_depthTex, v_texcoord + (sampleVector * radius).xy ).r; + sampleDepth = linearizeDepth( sampleDepth, u_zNear, u_zFar ); + vec3 samplePoint = origin + vec3((sampleVector * radius).x, (sampleVector * radius).y, -(sampleVector * radius).z / 2.0); + + if(sampleDepth <= samplePoint.z) + count+= 1.0; + } + //gl_FragColor = vec4(value* (1.0-count/50.0), 1.0); // vec4(1.0 - count/50.0, 1.0 - count/50.0, 1.0 - count/50.0, 1.0); + gl_FragColor = vec4(1.0 - count/50.0, 1.0 - count/50.0, 1.0 - count/50.0, 1.0); + } + } diff --git a/image.png b/image.png new file mode 100644 index 0000000..cfbecac Binary files /dev/null and b/image.png differ diff --git a/image2.png b/image2.png new file mode 100644 index 0000000..b95a08b Binary files /dev/null and b/image2.png differ diff --git a/js/main.js b/js/main.js index bf701d9..4088908 100644 --- a/js/main.js +++ b/js/main.js @@ -31,6 +31,9 @@ var isDiagnostic = true; var zNear = 20; var zFar = 2000; var texToDisplay = 1; +var bloom = 0.0; +var sihouete = 0.0; +var ssao = 0.0; var main = function (canvasId, messageId) { var canvas; @@ -217,25 +220,27 @@ var renderShade = function () { gl.clear(gl.COLOR_BUFFER_BIT); // Bind necessary textures - //gl.activeTexture( gl.TEXTURE0 ); //position - //gl.bindTexture( gl.TEXTURE_2D, fbo.texture(0) ); - //gl.uniform1i( shadeProg.uPosSamplerLoc, 0 ); + gl.activeTexture( gl.TEXTURE0 ); //position + gl.bindTexture( gl.TEXTURE_2D, fbo.texture(0) ); + gl.uniform1i( shadeProg.uPosSamplerLoc, 0 ); - //gl.activeTexture( gl.TEXTURE1 ); //normal - //gl.bindTexture( gl.TEXTURE_2D, fbo.texture(1) ); - //gl.uniform1i( shadeProg.uNormalSamplerLoc, 1 ); + gl.activeTexture( gl.TEXTURE1 ); //normal + gl.bindTexture( gl.TEXTURE_2D, fbo.texture(1) ); + gl.uniform1i( shadeProg.uNormalSamplerLoc, 1 ); gl.activeTexture( gl.TEXTURE2 ); //color gl.bindTexture( gl.TEXTURE_2D, fbo.texture(2) ); gl.uniform1i( shadeProg.uColorSamplerLoc, 2 ); - //gl.activeTexture( gl.TEXTURE3 ); //depth - //gl.bindTexture( gl.TEXTURE_2D, fbo.depthTexture() ); - //gl.uniform1i( shadeProg.uDepthSamplerLoc, 3 ); + gl.activeTexture( gl.TEXTURE3 ); //depth + gl.bindTexture( gl.TEXTURE_2D, fbo.depthTexture() ); + gl.uniform1i( shadeProg.uDepthSamplerLoc, 3 ); // Bind necessary uniforms - //gl.uniform1f( shadeProg.uZNearLoc, zNear ); - //gl.uniform1f( shadeProg.uZFarLoc, zFar ); + gl.uniform1f( shadeProg.uZNearLoc, zNear ); + gl.uniform1f( shadeProg.uZFarLoc, zFar ); + gl.uniformMatrix4fv(shadeProg.uModelViewLoc, false, camera.getViewTransform()); + gl.uniform1f( shadeProg.uToonLoc, sihouete ); drawQuad(shadeProg); @@ -274,6 +279,7 @@ var renderDiagnostic = function () { drawQuad(diagProg); }; + var renderPost = function () { gl.useProgram(postProg.ref()); @@ -284,7 +290,25 @@ var renderPost = function () { gl.activeTexture( gl.TEXTURE4 ); gl.bindTexture( gl.TEXTURE_2D, fbo.texture(4) ); gl.uniform1i(postProg.uShadeSamplerLoc, 4 ); - + + gl.activeTexture( gl.TEXTURE0 ); //position + gl.bindTexture( gl.TEXTURE_2D, fbo.texture(0) ); + gl.uniform1i( postProg.uPosSamplerLoc, 0 ); + + gl.activeTexture( gl.TEXTURE1 ); //normal + gl.bindTexture( gl.TEXTURE_2D, fbo.texture(1) ); + gl.uniform1i( postProg.uNormalSamplerLoc, 1 ); + + gl.activeTexture( gl.TEXTURE3 ); //depth + gl.bindTexture( gl.TEXTURE_2D, fbo.depthTexture() ); + gl.uniform1i( postProg.uDepthSamplerLoc, 3 ); + + gl.uniform1f( postProg.uSihoueteLoc, sihouete ); + gl.uniform1f( postProg.uBloomLoc, bloom ); + gl.uniform1f( postProg.uSSAOLoc, ssao ); + gl.uniform1f( postProg.uZNearLoc, zNear ); + gl.uniform1f( postProg.uZFarLoc, zFar ); + drawQuad(postProg); }; @@ -339,6 +363,15 @@ var initCamera = function () { isDiagnostic = true; texToDisplay = 4; break; + case 53: + bloom = 1.0 - bloom; + break; + case 54: + sihouete = 1.0 - sihouete; + break; + case 55: + ssao = 1.0 - ssao; + break; } } }; @@ -348,7 +381,7 @@ var initObjs = function () { objloader = CIS565WEBGLCORE.createOBJLoader(); // Load the OBJ from file - objloader.loadFromFile(gl, "assets/models/crytek-sponza/sponza.obj", null); + objloader.loadFromFile(gl, "assets/models/suzanne.obj", null); // Add callback to upload the vertices once loaded objloader.addCallback(function () { @@ -467,7 +500,10 @@ var initShaders = function () { shadeProg.uZNearLoc = gl.getUniformLocation( shadeProg.ref(), "u_zNear" ); shadeProg.uZFarLoc = gl.getUniformLocation( shadeProg.ref(), "u_zFar" ); - shadeProg.uDisplayTypeLoc = gl.getUniformLocation( shadeProg.ref(), "u_displayType" ); + shadeProg.uToonLoc = gl.getUniformLocation( shadeProg.ref(), "u_toon" ); + shadeProg.uModelViewLoc = gl.getUniformLocation(shadeProg.ref(), "u_modelview"); + + shadeProg.uDisplayTypeLoc = gl.getUniformLocation( shadeProg.ref(), "u_displayType" ); }); CIS565WEBGLCORE.registerAsyncObj(gl, shadeProg); @@ -478,9 +514,19 @@ var initShaders = function () { postProg.aVertexPosLoc = gl.getAttribLocation( postProg.ref(), "a_pos" ); postProg.aVertexTexcoordLoc = gl.getAttribLocation( postProg.ref(), "a_texcoord" ); + postProg.uPosSamplerLoc = gl.getUniformLocation( postProg.ref(), "u_positionTex"); postProg.uShadeSamplerLoc = gl.getUniformLocation( postProg.ref(), "u_shadeTex"); + postProg.uNormalSamplerLoc = gl.getUniformLocation( postProg.ref(), "u_normalTex"); + postProg.uDepthSamplerLoc = gl.getUniformLocation( postProg.ref(), "u_depthTex"); + postProg.uBloomLoc = gl.getUniformLocation( postProg.ref(), "u_bloom" ); + postProg.uSihoueteLoc = gl.getUniformLocation( postProg.ref(), "u_sihouete" ); + postProg.uSSAOLoc = gl.getUniformLocation( postProg.ref(), "u_ssao" ); + postProg.uZNearLoc = gl.getUniformLocation( postProg.ref(), "u_zNear" ); + postProg.uZFarLoc = gl.getUniformLocation( postProg.ref(), "u_zFar" ); }); CIS565WEBGLCORE.registerAsyncObj(gl, postProg); + + }; var initFramebuffer = function () {