diff --git a/README.md b/README.md index f22c764..3c7e2b2 100644 --- a/README.md +++ b/README.md @@ -3,190 +3,123 @@ CIS565: Project 6: Deferred Shader ------------------------------------------------------------------------------- Fall 2013 ------------------------------------------------------------------------------- -Due Friday 11/15/2013 +Qiong Wang ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -NOTE: +INTRODUCTION: ------------------------------------------------------------------------------- -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. + +This is an openGL based project for CIS 565 GPU Programming. +In this project, the basics of deferred shading were introduced and implemented through +writing codes in GLSL and OpenGL. + +The deferred lighting pipeline can be the following three stages: + +1. Stage 1: renders the scene geometry to the G-Buffer (pass.vert, pass.frag) + +2. Stage 2: renders the lighting passes and accumulates to the P-Buffer (shade.vert, ambient.frag, point.frag, diagnostic.frag) + +3. Stage 3: renders the post processing (post.vert, post.frag) + +Note: this project cannot be running on ultra-book machine with Intel Graphics card, since Intel Graphics card only offer support for version 130 at most currently. ------------------------------------------------------------------------------- -INTRODUCTION: +FEATURES IMPLEMENTED ------------------------------------------------------------------------------- -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. + +* Bloom effect +* "Toon" Shading (with basic silhouetting) +* Point light sources +* An additional G buffer slot and some effect showing it off +* Screen space ambient occlusion (SSAO) + ------------------------------------------------------------------------------- -CONTENTS: +OPERATION INSTRUCTION ------------------------------------------------------------------------------- -The Project6 root directory contains the following subdirectories: - -* base/ - * PROJ_WIN/ contains the vs2010 project files - * PROJ_NIX/ contains makefile for building (tested on ubuntu 12.04 LTS) - * res/ contains resources including shader source and obj files - * src/ contains the c++ code for the project along with SOIL and tiny_obj_loader -* shared32/ contains freeglut, glm, and glew. +**Keyboard Interaction** ---- -BASE CODE TOUR ---- +| Operation | Function | +|:-------------------------:|:-----------------------------:| +| 'x' | Toggle scissor test | +| 'r' | Reload shaders | +| 'wasdqz' | Movement and Zoom | +| '1' | View depth | +| '2' | View eye space normals | +| '3' | View Diffuse color | +| '4' | View eye space positions | +| '5' | View lighting debug mode | +| '6' | View result of bloom | +| '7' | View result of Toon effect | +| '8' | View result of SSAO | +| '0' | Standard view | -Most of your edits will be confined to the various fragment shader programs and main.cpp. -Some methods worth exploring are: -[initShader](https://github.com/CIS565-Fall-2013/Project6-DeferredShader/blob/master/base/src/main.cpp#L223): -This method initializes each shader program from specified source files. Note that the source name is declared inside a `#ifdef WIN32` guard block. This is done to reflect the relative directory structure between the linux and windows versions of the code. +------------------------------------------------------------------------------- +SCREENSHOTS OF RESULTS +------------------------------------------------------------------------------- +* Source Point Light Grid +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/blueceiling.png) -[initFBO](https://github.com/CIS565-Fall-2013/Project6-DeferredShader/blob/master/base/src/main.cpp#L360): -This method initializes the framebuffer objects used as render targets for the first and second stage of the pipeline. When you go to add another slot to the G buffer you will need to modify to first FBO accordingly. Try finding all the places where `colorTexture` is used (ctrl+F in windows will be helpful) and look at how textures are created, freed, added to the FBO, and assigned to the appropriate shader programs before adding your own. Also keep in mind that textures can be reused as inputs in other pipeline stages, for instance you might want access to the normals both in the lighting stage and in the post process stage. +* Light Display +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/light_display.png) -[draw_mesh](https://github.com/CIS565-Fall-2013/Project6-DeferredShader/blob/master/base/src/main.cpp#L574), -[draw_quad](https://github.com/CIS565-Fall-2013/Project6-DeferredShader/blob/master/base/src/main.cpp#L647), -[draw_light](https://github.com/CIS565-Fall-2013/Project6-DeferredShader/blob/master/base/src/main.cpp#L657): -These methods render the scene geometry, viewing quad, and point light quad to the screen. The draw_light method in particular is interesting because it will set up the scissor window for efficient rendering of point lights. +* Bloom with add new slot to G-buffer +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/bloom.png) -[display](https://github.com/CIS565-Fall-2013/Project6-DeferredShader/blob/master/base/src/main.cpp#L742): -This is where the graphical work of your program is done. The method is separated into three stages with the majority of work being done in stage 2. +* Toon with Silhouetting -Stage 1 renders the scene geometry to the G-Buffer -* pass.vert -* pass.frag +*Pure Toon* +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/cornell_toon.png) -Stage 2 renders the lighting passes and accumulates to the P-Buffer -* shade.vert -* ambient.frag -* point.frag -* diagnostic.frag +*Toon with Silhouetting* +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/toon_silhouetting.png) -Stage 3 renders the post processing -* post.vert -* post.frag +* SSAO comparison -[keyboard](https://github.com/CIS565-Fall-2013/Project6-DeferredShader/blob/master/base/src/main.cpp#L870): -This is a good reference for the key mappings in the program. -WASDQZ - Movement -X - Toggle scissor test -R - Reload shaders -1 - View depth -2 - View eye space normals -3 - View Diffuse color -4 - View eye space positions -5 - View lighting debug mode -0 - Standard view +*With SSAO* +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/SSAO.png) -------------------------------------------------------------------------------- -REQUIREMENTS: -------------------------------------------------------------------------------- +*Without SSAO* +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/no_SSAO.png) -In this project, you are given code for: -* Loading .obj files -* Rendering to a minimal G buffer: - * Depth - * Normal - * Color - * Eye space position -* Rendering simple ambient and directional lighting to texture -* Example post process shader to add a vignette +Detailed ones: -You are required to implement: -* Either of the following effects - * Bloom (feel free to use [GPU Gems](http://http.developer.nvidia.com/GPUGems/gpugems_ch21.html) as a rough guide) - * "Toon" Shading (with basic silhouetting) -* Point light sources -* An additional G buffer slot and some effect showing it off +*With SSAO* +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/SSAO1.png) -**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. +*Without SSAO* +![screenshot](https://raw.github.com/GabriellaQiong/Project6-DeferredShader/master/no_SSAO1.png) -You must implement two of the following extras: -* The effect you did not choose above -* Screen space ambient occlusion -* 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). ------------------------------------------------------------------------------- -README +PERFORMANCE EVALUATION ------------------------------------------------------------------------------- -All students must replace or augment the contents of this Readme.md in a clear -manner with the following: +Here is the table for the performance evaluation when rendering the cornell_box.obj in scissor mode. + +| Feature | approximate fps | +|:------------------:|:-----------------:| +| point light grid | 38.20 | +| Bloom | 12.14 | +| Toon Shading | 35.86 | +| SSAO | 37.25 | -* A brief description of the project and the specific features you implemented. -* At least one screenshot of your project running. -* A 30 second or longer video of your project running. To create the video you - can use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx -* A performance evaluation (described in detail below). +Note: Here each time I toggled to the non-scissor-test mode,light_display.png the FPS dropped dramatically to 1.2 or less. Besides, +when we zoom in, the FPS decreased and vice versa. ------------------------------------------------------------------------------- -PERFORMANCE EVALUATION +REFERENCES +------------------------------------------------------------------------------- +* Deferred Shading: http://en.wikipedia.org/wiki/Deferred_shading +* Z-buffering: http://en.wikipedia.org/wiki/Z-buffering +* Attenuation: http://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/ +* Bloom and glow: http://http.developer.nvidia.com/GPUGems/gpugems_ch21.html +* Toon Shader: http://en.wikipedia.org/wiki/Cel_shading +* SSAO: https://developer.valvesoftware.com/wiki/Screen_Space_Ambient_Occlusion_(SSAO) + +------------------------------------------------------------------------------- +ACKNOWLEDGEMENT ------------------------------------------------------------------------------- -The performance evaluation is where you will investigate how to make your -program more efficient using the skills you've learned in class. You must have -performed at least one experiment on your code to investigate the positive or -negative effects on performance. - -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. - -Each student should provide no more than a one page summary of their -optimizations along with tables and or graphs to visually explain any -performance differences. - -------------------------------------------------------------------------------- -THIRD PARTY CODE POLICY -------------------------------------------------------------------------------- -* Use of any third-party code must be approved by asking on the Google groups. - If it is approved, all students are welcome to use it. Generally, we approve - use of third-party code that is not a core part of the project. For example, - for the ray tracer, we would approve using a third-party library for loading - models, but would not approve copying and pasting a CUDA function for doing - refraction. -* Third-party code must be credited in README.md. -* Using third-party code without its approval, including using another - student's code, is an academic integrity violation, and will result in you - receiving an F for the semester. - -------------------------------------------------------------------------------- -SELF-GRADING -------------------------------------------------------------------------------- -* On the submission date, email your grade, on a scale of 0 to 100, to Liam, - liamboone@gmail.com, with a one paragraph explanation. Be concise and - realistic. Recall that we reserve 30 points as a sanity check to adjust your - grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We - hope to only use this in extreme cases when your grade does not realistically - reflect your work - it is either too high or too low. In most cases, we plan - to give you the exact grade you suggest. -* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as - the path tracer. We will determine the weighting at the end of the semester - based on the size of each project. - - ---- -SUBMISSION ---- -As with the previous projects, you should fork this project and work inside of -your fork. Upon completion, commit your finished project back to your fork, and -make a pull request to the master repository. You should include a README.md -file in the root directory detailing the following - -* A brief description of the project and specific features you implemented -* At least one screenshot of your project running. -* A link to a video of your project running. -* Instructions for building and running your project if they differ from the - base code. -* A performance writeup as detailed above. -* A list of all third-party code used. -* This Readme file edited as described above in the README section. - ---- -ACKNOWLEDGEMENTS ---- -This project makes use of [tinyobjloader](http://syoyo.github.io/tinyobjloader/) and [SOIL](http://lonesock.net/soil.html) +Thanks a lot to Patrick and Liam for the preparation of this project. Thank you :) diff --git a/SSAO.png b/SSAO.png new file mode 100644 index 0000000..4b40967 Binary files /dev/null and b/SSAO.png differ diff --git a/SSAO1.png b/SSAO1.png new file mode 100644 index 0000000..e736575 Binary files /dev/null and b/SSAO1.png differ diff --git a/base/PROJ_NIX/565DefferedShader b/base/PROJ_NIX/565DefferedShader new file mode 100755 index 0000000..af4191b Binary files /dev/null and b/base/PROJ_NIX/565DefferedShader differ diff --git a/base/PROJ_NIX/makefile b/base/PROJ_NIX/makefile index 195ef71..fd63c1d 100755 --- a/base/PROJ_NIX/makefile +++ b/base/PROJ_NIX/makefile @@ -1,6 +1,6 @@ LFLAGS := -lglut -lGL -lGLEW CFLAGS := -Wall -IFLAGS := -I../../shared32/glm/ -I../../shared32/freeglut -I../../shared32/glew -I../src/SOIL -I../src/tiny_obj_loader +IFLAGS := -I../../shared32/glm/ -I../../shared32/freeglut/include/ -I../../shared32/glew/include/ -I../src/SOIL -I../src/tiny_obj_loader 565DefferedShader: Utility.o tiny_obj_loader.o main.o image_helper.o stb_image_aug.o image_DXT.o SOIL.o g++ *.o -o 565DefferedShader $(LFLAGS) diff --git a/base/res/cornell/cornell_box.mtl b/base/res/cornell/cornell_box.mtl index aae8474..450801a 100644 --- a/base/res/cornell/cornell_box.mtl +++ b/base/res/cornell/cornell_box.mtl @@ -1,5 +1,5 @@ newmtl white -Ka 0 0 0 +Ka 0 0 0; Kd 0.9 0.9 0.9 Ks 0 0 0 @@ -18,7 +18,27 @@ Ka 0 0 0 Kd 0 0 1 Ks 0 0 0 +newmtl purple +Ka 1.2 0.2 1.2 +Kd 1 0 1 +Ks 0 0 0 + +newmtl yellow +Ka 1.2 1.2 0.2 +Kd 1 0.9 0.1 +Ks 0 0 0 + +newmtl lightblue +Ka 0 0 0 +Kd 0.5 0.3 1.5 +Ks 0 0 0 + newmtl light -Ka 20 20 20 +Ka 2 2 2 Kd 1 1 1 Ks 0 0 0 + +newmtl grey +Ka 0 0 0 +Kd 0.1 0.1 0.1 +Ks 0 0 0 diff --git a/base/res/cornell/cornell_box.obj b/base/res/cornell/cornell_box.obj index 43e021f..fc6b2ac 100644 --- a/base/res/cornell/cornell_box.obj +++ b/base/res/cornell/cornell_box.obj @@ -37,7 +37,7 @@ v 213.0 548.0 227.0 f -4 -3 -2 -1 o ceiling -usemtl white +usemtl lightblue v 556.0 548.8 0.0 v 556.0 548.8 559.2 v 0.0 548.8 559.2 @@ -77,7 +77,7 @@ v 556.0 548.8 0.0 f -4 -3 -2 -1 o short_block -usemtl white +usemtl purple v 130.0 165.0 65.0 v 82.0 165.0 225.0 @@ -110,7 +110,7 @@ v 82.0 0.0 225.0 f -4 -3 -2 -1 o tall_block -usemtl white +usemtl yellow v 423.0 330.0 247.0 v 265.0 330.0 296.0 @@ -118,7 +118,7 @@ v 314.0 330.0 456.0 v 472.0 330.0 406.0 f -4 -3 -2 -1 -usemtl white +usemtl yellow v 423.0 0.0 247.0 v 423.0 330.0 247.0 v 472.0 330.0 406.0 diff --git a/base/res/shaders/ambient.frag b/base/res/shaders/ambient.frag index 69b878c..79955d5 100644 --- a/base/res/shaders/ambient.frag +++ b/base/res/shaders/ambient.frag @@ -10,7 +10,9 @@ #define DISPLAY_COLOR 3 #define DISPLAY_TOTAL 4 #define DISPLAY_LIGHTS 5 - +#define DISPLAY_BLOOM 6 +#define DISPLAY_TOON 7 +#define DISPLAY_SSAO 8 ///////////////////////////////////// // Uniforms, Attributes, and Outputs @@ -23,6 +25,7 @@ uniform sampler2D u_Positiontex; uniform sampler2D u_Colortex; uniform sampler2D u_RandomNormaltex; uniform sampler2D u_RandomScalartex; +uniform sampler2D u_Bloomtex; uniform float u_Far; uniform float u_Near; @@ -50,8 +53,7 @@ uniform float falloff = 0.1f; ///////////////////////////////////// // UTILITY FUNCTIONS ///////////////////////////////////// - -//Depth used in the Z buffer is not linearly related to distance from camera +//Depth used in the Z buffe r isnot linearly related to distance from camera //This restores linear depth float linearizeDepth(float exp_depth, float near, float far) { return (2 * near) / (far + near - exp_depth * (far - near)); @@ -101,6 +103,22 @@ void main() { vec3 normal = sampleNrm(fs_Texcoord); vec3 position = samplePos(fs_Texcoord); vec3 color = sampleCol(fs_Texcoord); + + if(u_DisplayType == DISPLAY_SSAO) { + float kernel_width = 5.0; + vec3 SSAO_color = vec3(0.0); + // Check the depth in neighbor patch whether there is an occlusion happens + for (float x = - kernel_width / 2.0; x <= kernel_width / 2.0; x += 2.0) { + for (float y = - kernel_width / 2.0; y <= kernel_width / 2.0; y += 2.0) { + vec2 incremental = vec2(x /float(u_ScreenWidth), y / float(u_ScreenHeight)); + float neighbour_depth = texture(u_Depthtex, fs_Texcoord + incremental).r; + if (neighbour_depth >= exp_depth) + continue; + SSAO_color += vec3(0.025); + } + } + color *= (1.0 - SSAO_color); + } vec3 light = u_Light.xyz; float strength = u_Light.w; if (lin_depth > 0.99f) { diff --git a/base/res/shaders/bloom.frag b/base/res/shaders/bloom.frag new file mode 100644 index 0000000..166e210 --- /dev/null +++ b/base/res/shaders/bloom.frag @@ -0,0 +1,124 @@ +#version 330 + +//////////////////////////// +// ENUMERATIONS +//////////////////////////// + +#define DISPLAY_DEPTH 0 +#define DISPLAY_NORMAL 1 +#define DISPLAY_POSITION 2 +#define DISPLAY_COLOR 3 +#define DISPLAY_TOTAL 4 +#define DISPLAY_LIGHTS 5 +#define DISPLAY_BLOOM 6 +#define DISPLAY_TOON 7 +#define PI 3.1415926535 + +///////////////////////////////////// +// Uniforms, Attributes, and Outputs +//////////////////////////////////// +uniform mat4 u_Persp; + +uniform sampler2D u_Depthtex; +uniform sampler2D u_Normaltex; +uniform sampler2D u_Positiontex; +uniform sampler2D u_Colortex; +uniform sampler2D u_RandomNormaltex; +uniform sampler2D u_RandomScalartex; + +// Add bloom texture +uniform sampler2D u_Bloomtex; + +uniform float u_Far; +uniform float u_Near; +uniform int u_DisplayType; + +uniform int u_ScreenWidth; +uniform int u_ScreenHeight; + +uniform vec4 u_Light; +uniform float u_LightIl; + +in vec2 fs_Texcoord; + +out vec4 out_Color; +/////////////////////////////////////// + + + + +uniform float zerothresh = 1.0f; +uniform float falloff = 0.1f; + + +///////////////////////////////////// +// UTILITY FUNCTIONS +///////////////////////////////////// + +//Depth used in the Z buffer is not linearly related to distance from camera +//This restores linear depth +float linearizeDepth(float exp_depth, float near, float far) { + return (2 * near) / (far + near - exp_depth * (far - near)); +} + +//Helper function to automatically sample and unpack normals +vec3 sampleNrm(vec2 texcoords) { + return texture(u_Normaltex,texcoords).xyz; +} + +//Helper function to automicatlly sample and unpack positions +vec3 samplePos(vec2 texcoords) { + return texture(u_Positiontex,texcoords).xyz; +} + +//Helper function to automicatlly sample and unpack positions +vec3 sampleCol(vec2 texcoords) { + return texture(u_Colortex,texcoords).xyz; +} + +//Get a random normal vector given a screen-space texture coordinate +//Actually accesses a texture of random vectors +vec3 getRandomNormal(vec2 texcoords) { + ivec2 sz = textureSize(u_RandomNormaltex,0); + return texture(u_RandomNormaltex,vec2(texcoords.s* (u_ScreenWidth)/sz.x, + (texcoords.t)*(u_ScreenHeight)/sz.y)).rgb; +} + + +//Get a random scalar given a screen-space texture coordinate +//Fetches from a random texture +float getRandomScalar(vec2 texcoords) { + ivec2 sz = textureSize(u_RandomScalartex,0); + return texture(u_RandomScalartex,vec2(texcoords.s*u_ScreenWidth/sz.x, + texcoords.t*u_ScreenHeight/sz.y)).r; +} + +// Gaussian Convolution +float conv(float x, float sigma) { + float gaussian = 1.0 / sqrt(2.0 * PI) / sigma * exp(-x * x / 2.0 / sigma / sigma); + return gaussian; +} + +/////////////////////////////////// +// MAIN +////////////////////////////////// +const float occlusion_strength = 1.5f; +void main() { + if (u_DisplayType == DISPLAY_BLOOM) + continue; + + // Initialize + float kernel_width = 8.0; + float sigma = sqrt(kernel_width/2/3); + vec4 bloom_color = vec4(0.0); + + for (int x = - kernel_width / 2.0; x < kernel_width / 2.0; x ++) { + for (int y = - kernel_width / 2.0; y < kernel_width / 2.0; y ++) { + vec2 incremental = vec2(x / u_ScreenWidth, y / u_ScreenHeight); + bloom_color += texture(u_Bloomtex, fs_Texcoord + incremental) * conv((float)x, sigma) * conv((float)y, sigma); + } + } + out_Color = color; + + return; +} diff --git a/base/res/shaders/diagnostic.frag b/base/res/shaders/diagnostic.frag index ac73727..4e387f5 100644 --- a/base/res/shaders/diagnostic.frag +++ b/base/res/shaders/diagnostic.frag @@ -10,7 +10,8 @@ #define DISPLAY_COLOR 3 #define DISPLAY_TOTAL 4 #define DISPLAY_LIGHTS 5 - +#define DISPLAY_BLOOM 6 +#define DISPLAY_TOON 7 ///////////////////////////////////// // Uniforms, Attributes, and Outputs diff --git a/base/res/shaders/directional.frag b/base/res/shaders/directional.frag index a34daab..a577ae6 100644 --- a/base/res/shaders/directional.frag +++ b/base/res/shaders/directional.frag @@ -10,7 +10,8 @@ #define DISPLAY_COLOR 3 #define DISPLAY_TOTAL 4 #define DISPLAY_LIGHTS 5 - +#define DISPLAY_BLOOM 6 +#define DISPLAY_TOON 7 ///////////////////////////////////// // Uniforms, Attributes, and Outputs @@ -23,6 +24,7 @@ uniform sampler2D u_Positiontex; uniform sampler2D u_Colortex; uniform sampler2D u_RandomNormaltex; uniform sampler2D u_RandomScalartex; +uniform sampler2D u_Bloomtex; uniform float u_Far; uniform float u_Near; diff --git a/base/res/shaders/pass.frag b/base/res/shaders/pass.frag index e37dcbf..4c35402 100644 --- a/base/res/shaders/pass.frag +++ b/base/res/shaders/pass.frag @@ -2,6 +2,7 @@ uniform float u_Far; uniform vec3 u_Color; +uniform vec3 u_Shiness; in vec3 fs_Normal; in vec4 fs_Position; @@ -9,10 +10,12 @@ in vec4 fs_Position; out vec4 out_Normal; out vec4 out_Position; out vec4 out_Color; +out vec4 out_Bloom; void main(void) { out_Normal = vec4(normalize(fs_Normal),0.0f); out_Position = vec4(fs_Position.xyz,1.0f); //Tuck position into 0 1 range out_Color = vec4(u_Color,1.0); + out_Bloom = vec4(u_Shiness, 1.0); } diff --git a/base/res/shaders/point.frag b/base/res/shaders/point.frag index 98b90e0..4ec9f0a 100644 --- a/base/res/shaders/point.frag +++ b/base/res/shaders/point.frag @@ -10,7 +10,8 @@ #define DISPLAY_COLOR 3 #define DISPLAY_TOTAL 4 #define DISPLAY_LIGHTS 5 - +#define DISPLAY_BLOOM 6 +#define DISPLAY_TOON 7 ///////////////////////////////////// // Uniforms, Attributes, and Outputs @@ -23,6 +24,7 @@ uniform sampler2D u_Positiontex; uniform sampler2D u_Colortex; uniform sampler2D u_RandomNormaltex; uniform sampler2D u_RandomScalartex; +uniform sampler2D u_Bloomtex; uniform float u_Far; uniform float u_Near; @@ -100,17 +102,57 @@ void main() { vec3 normal = sampleNrm(fs_Texcoord); vec3 position = samplePos(fs_Texcoord); vec3 color = sampleCol(fs_Texcoord); - vec3 light = u_Light.xyz; + vec3 light = u_Light.xyz; // light position float lightRadius = u_Light.w; - out_Color = vec4(0,0,0,1.0); + vec3 light_dir = normalize(position - light); + float light_dist = distance(position, light); + //out_Color = vec4(0.0, 0.0, 0.0, 1.0); + if( u_DisplayType == DISPLAY_LIGHTS ) { - //Put some code here to visualize the fragment associated with this point light + //Visualize the fragment associated with this point light + float diffuse = max(dot(normal, -light_dir), 0.0); + out_Color = vec4(vec3(0.4, 0.2, 0.8) * diffuse, 1.0); } else { - //Put some code here to actually compute the light from the point light + //Put some code here to actually compute the light from the point light, using light attenuation formula from http://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/ + // Attenuation + float d = max(light_dist - lightRadius, 0.0); + float ratio = light_dist / lightRadius; + float denom = ratio + 1.0; + float attenuation = 1.7 / (denom * denom) * max(1.0 - d, 0.0); + + // Diffuse with attenuation + float diffuse = max(dot(normal, -light_dir), 0.0); + out_Color = vec4(color * diffuse * attenuation, 1.0); + + if (u_DisplayType == DISPLAY_TOON) { + if (light_dist < lightRadius) { + if (diffuse >= 0.95) + diffuse = 1.0; + else if (diffuse >= 0.9) + diffuse = 0.8; + else if (diffuse >= 0.75) + diffuse = 0.75; + else if (diffuse >= 0.5) + diffuse = 0.5; + else + diffuse = 0.3; + out_Color = vec4(color * diffuse, 1.0); + + } else + out_Color = vec4(0.0, 0.0, 0.0, 1.0); + + // Draw the edges by finding normals of neighbours + vec3 normal_up = sampleNrm(fs_Texcoord + vec2(0.0, - 3.0 / float(u_ScreenHeight))); + vec3 normal_right = sampleNrm(fs_Texcoord + vec2(3.0 / float(u_ScreenWidth),0.0)); + vec3 normal_down = sampleNrm(fs_Texcoord + vec2(0.0, 3.0 / float(u_ScreenHeight))); + vec3 normal_left = sampleNrm(fs_Texcoord + vec2(- 3.0 / float(u_ScreenWidth), 0.0)); + + if (dot(normal_up, normal) < 0.8 || dot(normal_up, normal) < 0.8 || dot(normal_up, normal) < 0.8 || dot(normal_up, normal) < 0.8) + out_Color = vec4(0.0, 0.0, 0.0, 1.0); + } } return; } - diff --git a/base/res/shaders/post.frag b/base/res/shaders/post.frag index 2bf5afc..ac4e2bf 100644 --- a/base/res/shaders/post.frag +++ b/base/res/shaders/post.frag @@ -10,7 +10,9 @@ #define DISPLAY_COLOR 3 #define DISPLAY_TOTAL 4 #define DISPLAY_LIGHTS 5 - +#define DISPLAY_BLOOM 6 +#define DISPLAY_TOON 7 +#define PI 3.1415926 ///////////////////////////////////// // Uniforms, Attributes, and Outputs @@ -18,6 +20,9 @@ uniform sampler2D u_Posttex; uniform sampler2D u_RandomNormaltex; uniform sampler2D u_RandomScalartex; +uniform sampler2D u_Bloomtex; + +uniform int u_DisplayType; uniform int u_ScreenWidth; uniform int u_ScreenHeight; @@ -60,6 +65,12 @@ float getRandomScalar(vec2 texcoords) { texcoords.t*u_ScreenHeight/sz.y)).r; } +// Gaussian Convolution +float conv(float x, float sigma) { + float gaussian = 1.0 / sqrt(2.0 * PI) / sigma * exp(- x * x / 2.0 / sigma / sigma); + return gaussian; +} + /////////////////////////////////// // MAIN ////////////////////////////////// @@ -68,7 +79,22 @@ void main() { vec3 color = sampleCol(fs_Texcoord); float gray = dot(color, vec3(0.2125, 0.7154, 0.0721)); float vin = min(2*distance(vec2(0.5), fs_Texcoord), 1.0); - out_Color = vec4(mix(pow(color,vec3(1.0/1.8)),vec3(gray),vin), 1.0); + if (u_DisplayType == DISPLAY_BLOOM) { + // Initialize + float kernel_width = 20.0; + float sigma = sqrt(kernel_width/2/3); + vec3 bloom_color = vec3(0.0); + + // Add the Gaussian Kernel + for (float x = - kernel_width / 2.0; x < kernel_width / 2.0; x += 2.0) { + for (float y = - kernel_width / 2.0; y < kernel_width / 2.0; y += 2.0) { + vec2 incremental = vec2(x /float(u_ScreenWidth), y / float(u_ScreenHeight)); + bloom_color += texture(u_Bloomtex, fs_Texcoord + incremental).xyz * conv(incremental.x, sigma) * conv(incremental.y, sigma); + } + } + color = 0.75 * color + bloom_color; + } + out_Color = vec4(color, 1.0); + //out_Color = vec4(mix(pow(color,vec3(1.0/1.8)),vec3(gray),vin), 1.0); return; } - diff --git a/base/src/main.cpp b/base/src/main.cpp index 9a0f6a0..236ce7b 100644 --- a/base/src/main.cpp +++ b/base/src/main.cpp @@ -79,7 +79,8 @@ device_mesh_t uploadMesh(const mesh_t & mesh) { glBindVertexArray(0); out.texname = mesh.texname; - out.color = mesh.color; + out.color = mesh.color; + out.bloom = mesh.bloom; // Add the bloom component which should also be added in the struct in main.h return out; } @@ -162,6 +163,8 @@ void initMesh() { shape.material.diffuse[1], shape.material.diffuse[2]); mesh.texname = shape.material.diffuse_texname; + + mesh.bloom = vec3(shape.material.ambient[0], shape.material.ambient[1], shape.material.ambient[2]); draw_meshes.push_back(uploadMesh(mesh)); f=f+process; } @@ -202,7 +205,7 @@ void initQuad() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, device_quad.vbo_indices); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*sizeof(GLushort), indices, GL_STATIC_DRAW); device_quad.num_indices = 6; - //Unplug Vertex Array + //Unplug Vertex Arraghtmapy glBindVertexArray(0); } @@ -212,6 +215,7 @@ GLuint normalTexture = 0; GLuint positionTexture = 0; GLuint colorTexture = 0; GLuint postTexture = 0; +GLuint bloomTexture = 0; // Add Bloom texture as a new G buffer slot GLuint FBO[2] = {0, 0}; @@ -222,27 +226,27 @@ GLuint diagnostic_prog; GLuint post_prog; void initShader() { #ifdef WIN32 - const char * pass_vert = "../../../res/shaders/pass.vert"; - const char * shade_vert = "../../../res/shaders/shade.vert"; - const char * post_vert = "../../../res/shaders/post.vert"; - - const char * pass_frag = "../../../res/shaders/pass.frag"; - const char * diagnostic_frag = "../../../res/shaders/diagnostic.frag"; - const char * ambient_frag = "../../../res/shaders/ambient.frag"; - const char * point_frag = "../../../res/shaders/point.frag"; - const char * post_frag = "../../../res/shaders/post.frag"; + const char * pass_vert = "../../../res/shaders/pass.vert"; + const char * shade_vert = "../../../res/shaders/shade.vert"; + const char * post_vert = "../../../res/shaders/post.vert"; + + const char * pass_frag = "../../../res/shaders/pass.frag"; + const char * diagnostic_frag = "../../../res/shaders/diagnostic.frag"; + const char * ambient_frag = "../../../res/shaders/ambient.frag"; + const char * point_frag = "../../../res/shaders/point.frag"; + const char * post_frag = "../../../res/shaders/post.frag"; #else - const char * pass_vert = "../res/shaders/pass.vert"; - const char * shade_vert = "../res/shaders/shade.vert"; - const char * post_vert = "../res/shaders/post.vert"; - - const char * pass_frag = "../res/shaders/pass.frag"; - const char * diagnostic_frag = "../res/shaders/diagnostic.frag"; - const char * ambient_frag = "../res/shaders/ambient.frag"; - const char * point_frag = "../res/shaders/point.frag"; - const char * post_frag = "../res/shaders/post.frag"; + const char * pass_vert = "../res/shaders/pass.vert"; + const char * shade_vert = "../res/shaders/shade.vert"; + const char * post_vert = "../res/shaders/post.vert"; + + const char * pass_frag = "../res/shaders/pass.frag"; + const char * diagnostic_frag = "../res/shaders/diagnostic.frag"; + const char * ambient_frag = "../res/shaders/ambient.frag"; + const char * point_frag = "../res/shaders/point.frag"; + const char * post_frag = "../res/shaders/post.frag"; #endif - Utility::shaders_t shaders = Utility::loadShaders(pass_vert, pass_frag); + Utility::shaders_t shaders = Utility::loadShaders(pass_vert, pass_frag); pass_prog = glCreateProgram(); @@ -252,7 +256,7 @@ void initShader() { Utility::attachAndLinkProgram(pass_prog,shaders); - shaders = Utility::loadShaders(shade_vert, diagnostic_frag); + shaders = Utility::loadShaders(shade_vert, diagnostic_frag); diagnostic_prog = glCreateProgram(); @@ -261,7 +265,7 @@ void initShader() { Utility::attachAndLinkProgram(diagnostic_prog, shaders); - shaders = Utility::loadShaders(shade_vert, ambient_frag); + shaders = Utility::loadShaders(shade_vert, ambient_frag); ambient_prog = glCreateProgram(); @@ -270,7 +274,7 @@ void initShader() { Utility::attachAndLinkProgram(ambient_prog, shaders); - shaders = Utility::loadShaders(shade_vert, point_frag); + shaders = Utility::loadShaders(shade_vert, point_frag); point_prog = glCreateProgram(); @@ -279,7 +283,7 @@ void initShader() { Utility::attachAndLinkProgram(point_prog, shaders); - shaders = Utility::loadShaders(post_vert, post_frag); + shaders = Utility::loadShaders(post_vert, post_frag); post_prog = glCreateProgram(); @@ -295,6 +299,7 @@ void freeFBO() { glDeleteTextures(1,&positionTexture); glDeleteTextures(1,&colorTexture); glDeleteTextures(1,&postTexture); + glDeleteTextures(1,&bloomTexture); glDeleteFramebuffers(1,&FBO[0]); glDeleteFramebuffers(1,&FBO[1]); } @@ -334,13 +339,13 @@ GLuint random_normal_tex; GLuint random_scalar_tex; void initNoise() { #ifdef WIN32 - const char * rand_norm_png = "../../../res/random_normal.png"; - const char * rand_png = "../../../res/random.png"; + const char * rand_norm_png = "../../../res/random_normal.png"; + const char * rand_png = "../../../res/random.png"; #else - const char * rand_norm_png = "../res/random_normal.png"; - const char * rand_png = "../res/random.png"; + const char * rand_norm_png = "../res/random_normal.png"; + const char * rand_png = "../res/random.png"; #endif - random_normal_tex = (unsigned int)SOIL_load_OGL_texture(rand_norm_png,0,0,0); + random_normal_tex = (unsigned int)SOIL_load_OGL_texture(rand_norm_png,0,0,0); glBindTexture(GL_TEXTURE_2D, random_normal_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -348,7 +353,7 @@ void initNoise() { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBindTexture(GL_TEXTURE_2D, 0); - random_scalar_tex = (unsigned int)SOIL_load_OGL_texture(rand_png,0,0,0); + random_scalar_tex = (unsigned int)SOIL_load_OGL_texture(rand_png,0,0,0); glBindTexture(GL_TEXTURE_2D, random_scalar_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -366,6 +371,7 @@ void initFBO(int w, int h) { glGenTextures(1, &normalTexture); glGenTextures(1, &positionTexture); glGenTextures(1, &colorTexture); + glGenTextures(1, &bloomTexture); //Set up depth FBO glBindTexture(GL_TEXTURE_2D, depthTexture); @@ -412,7 +418,18 @@ void initFBO(int w, int h) { glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F , w, h, 0, GL_RGBA, GL_FLOAT,0); - // creatwwe a framebuffer object + // Set up bloom FBO + glBindTexture(GL_TEXTURE_2D, bloomTexture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, w, h, 0, GL_RGBA, GL_FLOAT, 0); + + // create a framebuffer object glGenFramebuffers(1, &FBO[0]); glBindFramebuffer(GL_FRAMEBUFFER, FBO[0]); @@ -421,11 +438,13 @@ void initFBO(int w, int h) { GLint normal_loc = glGetFragDataLocation(pass_prog,"out_Normal"); GLint position_loc = glGetFragDataLocation(pass_prog,"out_Position"); GLint color_loc = glGetFragDataLocation(pass_prog,"out_Color"); - GLenum draws [3]; + GLint bloom_loc = glGetFragDataLocation(pass_prog, "out_Bloom"); + GLenum draws [4]; draws[normal_loc] = GL_COLOR_ATTACHMENT0; draws[position_loc] = GL_COLOR_ATTACHMENT1; draws[color_loc] = GL_COLOR_ATTACHMENT2; - glDrawBuffers(3, draws); + draws[bloom_loc] = GL_COLOR_ATTACHMENT3; + glDrawBuffers(4, draws); // attach the texture to FBO depth attachment point int test = GL_COLOR_ATTACHMENT0; @@ -437,6 +456,8 @@ void initFBO(int w, int h) { glFramebufferTexture(GL_FRAMEBUFFER, draws[position_loc], positionTexture, 0); glBindTexture(GL_TEXTURE_2D, colorTexture); glFramebufferTexture(GL_FRAMEBUFFER, draws[color_loc], colorTexture, 0); + glBindTexture(GL_TEXTURE_2D, bloomTexture); + glFramebufferTexture(GL_FRAMEBUFFER, draws[bloom_loc], bloomTexture, 0); // check FBO status FBOstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -461,7 +482,7 @@ void initFBO(int w, int h) { glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F , w, h, 0, GL_RGBA, GL_FLOAT,0); - // creatwwe a framebuffer object + // create a framebuffer object glGenFramebuffers(1, &FBO[1]); glBindFramebuffer(GL_FRAMEBUFFER, FBO[1]); @@ -538,7 +559,7 @@ Camera::adjust(float dx, // look left right vec3 dir = glm::gtx::rotate_vector::rotate(start_dir,rx + 90,up); vec2 dir2(dir.x,dir.y); vec2 mag = dir2 * tx; - pos += mag; + pos += mag; } if (abs(ty) > 0) { @@ -562,7 +583,7 @@ mat4x4 Camera::get_view() { mat4x4 get_mesh_world() { vec3 tilt(1.0f,0.0f,0.0f); - //mat4 translate_mat = glm::translate(glm::vec3(0.0f,.5f,0.0f)); +// mat4 translate_mat = glm::translate(glm::vec3(0.0f,.5f,0.0f)); mat4 tilt_mat = glm::rotate(mat4(), 90.0f, tilt); mat4 scale_mat = glm::scale(mat4(), vec3(0.01)); return tilt_mat * scale_mat; //translate_mat; @@ -591,6 +612,7 @@ void draw_mesh() { for(int i=0; i indices; std::string texname; glm::vec3 color; + glm::vec3 bloom; } mesh_t; typedef struct { @@ -47,6 +48,7 @@ typedef struct { unsigned int vbo_normals; unsigned int vbo_texcoords; glm::vec3 color; + glm::vec3 bloom; std::string texname; } device_mesh_t; @@ -83,7 +85,10 @@ enum Display { DISPLAY_POSITION = 2, DISPLAY_COLOR = 3, DISPLAY_TOTAL = 4, - DISPLAY_LIGHTS = 5 + DISPLAY_LIGHTS = 5, + DISPLAY_BLOOM = 6, + DISPLAY_TOON = 7, + DISPLAY_SSAO =8 }; char* loadFile(char *fname, GLint &fSize); diff --git a/bloom.png b/bloom.png new file mode 100644 index 0000000..4d4c5f6 Binary files /dev/null and b/bloom.png differ diff --git a/blueceiling.png b/blueceiling.png new file mode 100644 index 0000000..b863aa6 Binary files /dev/null and b/blueceiling.png differ diff --git a/cornell_multilight_scissor.png b/cornell_multilight_scissor.png new file mode 100644 index 0000000..506551e Binary files /dev/null and b/cornell_multilight_scissor.png differ diff --git a/cornell_no_scissor.png b/cornell_no_scissor.png new file mode 100644 index 0000000..6acbaaf Binary files /dev/null and b/cornell_no_scissor.png differ diff --git a/cornell_toon.png b/cornell_toon.png new file mode 100644 index 0000000..8c6af38 Binary files /dev/null and b/cornell_toon.png differ diff --git a/light_display.png b/light_display.png new file mode 100644 index 0000000..3687ac2 Binary files /dev/null and b/light_display.png differ diff --git a/no_SSAO.png b/no_SSAO.png new file mode 100644 index 0000000..cb0773e Binary files /dev/null and b/no_SSAO.png differ diff --git a/no_SSAO1.png b/no_SSAO1.png new file mode 100644 index 0000000..4d3bda8 Binary files /dev/null and b/no_SSAO1.png differ diff --git a/toon_silhouetting.png b/toon_silhouetting.png new file mode 100644 index 0000000..8bb25aa Binary files /dev/null and b/toon_silhouetting.png differ