diff --git a/README.md b/README.md index f22c764..1362f49 100644 --- a/README.md +++ b/README.md @@ -1,192 +1,90 @@ ------------------------------------------------------------------------------- -CIS565: Project 6: Deferred Shader +
Project 6: Deferred Shader ------------------------------------------------------------------------------- -Fall 2013 -------------------------------------------------------------------------------- -Due Friday 11/15/2013 +
Fall 2013 ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -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. +In this project, I was introduced to the basics of deferred shading. I wrote GLSL and OpenGL code to perform various tasks in a deferred lighting pipeline such as creating and writing to a G-Buffer. -------------------------------------------------------------------------------- -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. +The features I implemented include toon shading, bloom effect, screen space ambient occlusion, and point lights. ------------------------------------------------------------------------------- -CONTENTS: +
RENDERS: ------------------------------------------------------------------------------- -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. - ---- -BASE CODE TOUR ---- - -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. - -[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. - -[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. - -[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. - -Stage 1 renders the scene geometry to the G-Buffer -* pass.vert -* pass.frag - -Stage 2 renders the lighting passes and accumulates to the P-Buffer -* shade.vert -* ambient.frag -* point.frag -* diagnostic.frag - -Stage 3 renders the post processing -* post.vert -* post.frag - -[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 -------------------------------------------------------------------------------- -REQUIREMENTS: -------------------------------------------------------------------------------- +Here are some screenshots: -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 - -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 - -**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 -* 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). +
![diffuse](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/diffuse.png "screenshots") -------------------------------------------------------------------------------- -README -------------------------------------------------------------------------------- -All students must replace or augment the contents of this Readme.md in a clear -manner with the following: +diffuse with point light sources -* 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). +
![bloom](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/bloom.png "screenshots") -------------------------------------------------------------------------------- -PERFORMANCE EVALUATION -------------------------------------------------------------------------------- -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. +bloom effect -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. +
![toon](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/toon.png "screenshots") -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. +toon effect -------------------------------------------------------------------------------- -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. +
![ssao](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/sponza_ssao.png "screenshots") + +screen space ambient occlusion + +
![ssao](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/ssao.png "screenshots") + +screen space ambient occlusion + +
![depth](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/depth.png "screenshots") + +depth mode + +
![normals](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/normals.png "screenshots") + +normals mode + +
![color](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/color.png "screenshots") + +color mode + +
![position](https://raw.github.com/josephto/Project6-DeferredShader/master/Renders/position.png "screenshots") + +screen space position mode + +Here's a video: http://www.youtube.com/watch?v=LJ39Sb76KdU ------------------------------------------------------------------------------- -SELF-GRADING +
PERFORMANCE REPORT: ------------------------------------------------------------------------------- -* 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) + +A performance analysis on how the number of point lights affects the frame rate. + +Number of Lights | Frames per Second +------------------|------------------------ +1 | ~60 fps +8 | ~60 fps +27 | ~60 fps +64 | ~60 fps +125 | ~60 fps +216 | ~34 fps +343 | ~23 fps +512 | ~18 fps +729 | ~15 fps +1000 | ~13 fps +1331 | ~12 fps +1728 | ~12 fps +2197 | ~12 fps +2744 | ~12 fps + +Because there's the frame rate is capped to the 60 fps refresh rate of my computer's display, it's not surprising that the first 5 entires are all around 60 fps. However, what seems to be interesting is that once the number of points lights reaches a certain number, the frame rate doesn't drop off anymore. + + + + + + + + +Despite the fact that my backface culling was a naive implementation, it still succeeded in speeding up my code. With the ability to ignore faces that weren't facing the camera, my rasterizer was able to show a rather decent speed up in the amount of time it took to compute and rasterize each frame. diff --git a/Renders/bloom.png b/Renders/bloom.png new file mode 100644 index 0000000..c0d0e48 Binary files /dev/null and b/Renders/bloom.png differ diff --git a/Renders/color.png b/Renders/color.png new file mode 100644 index 0000000..917b248 Binary files /dev/null and b/Renders/color.png differ diff --git a/Renders/depth.png b/Renders/depth.png new file mode 100644 index 0000000..a47ae49 Binary files /dev/null and b/Renders/depth.png differ diff --git a/Renders/diffuse.png b/Renders/diffuse.png new file mode 100644 index 0000000..23b5cbc Binary files /dev/null and b/Renders/diffuse.png differ diff --git a/Renders/normals.png b/Renders/normals.png new file mode 100644 index 0000000..2df2de3 Binary files /dev/null and b/Renders/normals.png differ diff --git a/Renders/position.png b/Renders/position.png new file mode 100644 index 0000000..241a3ea Binary files /dev/null and b/Renders/position.png differ diff --git a/Renders/sponza_ssao.png b/Renders/sponza_ssao.png new file mode 100644 index 0000000..cc2135d Binary files /dev/null and b/Renders/sponza_ssao.png differ diff --git a/Renders/ssao.png b/Renders/ssao.png new file mode 100644 index 0000000..a8cd7c0 Binary files /dev/null and b/Renders/ssao.png differ diff --git a/Renders/toon.png b/Renders/toon.png new file mode 100644 index 0000000..7338072 Binary files /dev/null and b/Renders/toon.png differ diff --git a/base/PROJ_WIN/P6/P6/P6.vcxproj b/base/PROJ_WIN/P6/P6/P6.vcxproj index 61a6915..8275d67 100644 --- a/base/PROJ_WIN/P6/P6/P6.vcxproj +++ b/base/PROJ_WIN/P6/P6/P6.vcxproj @@ -67,7 +67,7 @@ true true $(SolutionDir)$(Configuration);..\..\..\..\shared32\glew\lib;..\..\..\..\shared32\freeglut\lib;%(AdditionalLibraryDirectories) - freeglut.lib;glew32.lib;%(AdditionalDependencies) + SOIL.lib;freeglut.lib;glew32.lib;%(AdditionalDependencies) Console @@ -83,6 +83,7 @@ + @@ -91,6 +92,8 @@ + + diff --git a/base/PROJ_WIN/P6/P6/P6.vcxproj.filters b/base/PROJ_WIN/P6/P6/P6.vcxproj.filters index 8fd6655..a8ef790 100644 --- a/base/PROJ_WIN/P6/P6/P6.vcxproj.filters +++ b/base/PROJ_WIN/P6/P6/P6.vcxproj.filters @@ -67,5 +67,14 @@ Resource Files + + Resource Files + + + Resource Files + + + Resource Files + \ No newline at end of file diff --git a/base/PROJ_WIN/P6/cornell_box.mtl b/base/PROJ_WIN/P6/cornell_box.mtl new file mode 100644 index 0000000..aae8474 --- /dev/null +++ b/base/PROJ_WIN/P6/cornell_box.mtl @@ -0,0 +1,24 @@ +newmtl white +Ka 0 0 0 +Kd 0.9 0.9 0.9 +Ks 0 0 0 + +newmtl red +Ka 0 0 0 +Kd 1 0 0 +Ks 0 0 0 + +newmtl green +Ka 0 0 0 +Kd 0 1 0 +Ks 0 0 0 + +newmtl blue +Ka 0 0 0 +Kd 0 0 1 +Ks 0 0 0 + +newmtl light +Ka 20 20 20 +Kd 1 1 1 +Ks 0 0 0 diff --git a/base/PROJ_WIN/P6/cornell_box.obj b/base/PROJ_WIN/P6/cornell_box.obj new file mode 100644 index 0000000..43e021f --- /dev/null +++ b/base/PROJ_WIN/P6/cornell_box.obj @@ -0,0 +1,145 @@ +# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project. +# original cornell box data + # comment + +# empty line including some space + + +mtllib cornell_box.mtl + +o floor +usemtl white +v 552.8 0.0 0.0 +v 0.0 0.0 0.0 +v 0.0 0.0 559.2 +v 549.6 0.0 559.2 + +v 130.0 0.0 65.0 +v 82.0 0.0 225.0 +v 240.0 0.0 272.0 +v 290.0 0.0 114.0 + +v 423.0 0.0 247.0 +v 265.0 0.0 296.0 +v 314.0 0.0 456.0 +v 472.0 0.0 406.0 + +f 1 2 3 4 +f 8 7 6 5 +f 12 11 10 9 + +o light +usemtl light +v 343.0 548.0 227.0 +v 343.0 548.0 332.0 +v 213.0 548.0 332.0 +v 213.0 548.0 227.0 +f -4 -3 -2 -1 + +o ceiling +usemtl white +v 556.0 548.8 0.0 +v 556.0 548.8 559.2 +v 0.0 548.8 559.2 +v 0.0 548.8 0.0 +f -4 -3 -2 -1 + +o back_wall +usemtl white +v 549.6 0.0 559.2 +v 0.0 0.0 559.2 +v 0.0 548.8 559.2 +v 556.0 548.8 559.2 +f -4 -3 -2 -1 + +o front_wall +usemtl blue +v 549.6 0.0 0 +v 0.0 0.0 0 +v 0.0 548.8 0 +v 556.0 548.8 0 +#f -1 -2 -3 -4 + +o green_wall +usemtl green +v 0.0 0.0 559.2 +v 0.0 0.0 0.0 +v 0.0 548.8 0.0 +v 0.0 548.8 559.2 +f -4 -3 -2 -1 + +o red_wall +usemtl red +v 552.8 0.0 0.0 +v 549.6 0.0 559.2 +v 556.0 548.8 559.2 +v 556.0 548.8 0.0 +f -4 -3 -2 -1 + +o short_block +usemtl white + +v 130.0 165.0 65.0 +v 82.0 165.0 225.0 +v 240.0 165.0 272.0 +v 290.0 165.0 114.0 +f -4 -3 -2 -1 + +v 290.0 0.0 114.0 +v 290.0 165.0 114.0 +v 240.0 165.0 272.0 +v 240.0 0.0 272.0 +f -4 -3 -2 -1 + +v 130.0 0.0 65.0 +v 130.0 165.0 65.0 +v 290.0 165.0 114.0 +v 290.0 0.0 114.0 +f -4 -3 -2 -1 + +v 82.0 0.0 225.0 +v 82.0 165.0 225.0 +v 130.0 165.0 65.0 +v 130.0 0.0 65.0 +f -4 -3 -2 -1 + +v 240.0 0.0 272.0 +v 240.0 165.0 272.0 +v 82.0 165.0 225.0 +v 82.0 0.0 225.0 +f -4 -3 -2 -1 + +o tall_block +usemtl white + +v 423.0 330.0 247.0 +v 265.0 330.0 296.0 +v 314.0 330.0 456.0 +v 472.0 330.0 406.0 +f -4 -3 -2 -1 + +usemtl white +v 423.0 0.0 247.0 +v 423.0 330.0 247.0 +v 472.0 330.0 406.0 +v 472.0 0.0 406.0 +f -4 -3 -2 -1 + +v 472.0 0.0 406.0 +v 472.0 330.0 406.0 +v 314.0 330.0 456.0 +v 314.0 0.0 456.0 +f -4 -3 -2 -1 + +v 314.0 0.0 456.0 +v 314.0 330.0 456.0 +v 265.0 330.0 296.0 +v 265.0 0.0 296.0 +f -4 -3 -2 -1 + +v 265.0 0.0 296.0 +v 265.0 330.0 296.0 +v 423.0 330.0 247.0 +v 423.0 0.0 247.0 +f -4 -3 -2 -1 + diff --git a/base/res/cornell/cornell_box.mtl b/base/res/cornell/cornell_box.mtl index aae8474..a6f1c16 100644 --- a/base/res/cornell/cornell_box.mtl +++ b/base/res/cornell/cornell_box.mtl @@ -3,6 +3,11 @@ Ka 0 0 0 Kd 0.9 0.9 0.9 Ks 0 0 0 +newmtl purple +Ka 0 0 0 +Kd 0.9 0.2 0.9 +Ks 0 0 0 + newmtl red Ka 0 0 0 Kd 1 0 0 diff --git a/base/res/cornell/cornell_box.obj b/base/res/cornell/cornell_box.obj index 43e021f..6d4b732 100644 --- a/base/res/cornell/cornell_box.obj +++ b/base/res/cornell/cornell_box.obj @@ -77,7 +77,7 @@ v 556.0 548.8 0.0 f -4 -3 -2 -1 o short_block -usemtl white +usemtl blue v 130.0 165.0 65.0 v 82.0 165.0 225.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 purple 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..299a6d9 100644 --- a/base/res/shaders/ambient.frag +++ b/base/res/shaders/ambient.frag @@ -10,6 +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 ///////////////////////////////////// diff --git a/base/res/shaders/bloom.frag b/base/res/shaders/bloom.frag new file mode 100644 index 0000000..040d8dd --- /dev/null +++ b/base/res/shaders/bloom.frag @@ -0,0 +1,127 @@ +#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 DISPLAY_SSAO 8 + + +///////////////////////////////////// +// 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; + +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; +} + +/////////////////////////////////// +// MAIN +////////////////////////////////// +const float occlusion_strength = 1.5f; +void main() { + + float exp_depth = texture(u_Depthtex, fs_Texcoord).r; + float lin_depth = linearizeDepth(exp_depth,u_Near,u_Far); + + vec3 normal = sampleNrm(fs_Texcoord); + vec3 position = samplePos(fs_Texcoord); + vec3 color = sampleCol(fs_Texcoord); + vec3 light = u_Light.xyz; + float lightRadius = u_Light.w; + out_Color = vec4(0,0,0,1.0); + if( u_DisplayType == DISPLAY_BLOOM ) + { + float ambient = u_LightIl; + float diffuse = max(0.0, dot(normalize(light),normal)); + out_Color = vec4(color*(lightRadius*diffuse + ambient),1.0f); + vec3 sum = vec3(0.0); + for (int i=-40; i<=40; i+=4) { + for (int j=-40; j<=40; j+=4) { + vec2 texCoord = fs_Texcoord + i * vec2(1.0/u_ScreenWidth, 0.0) + + j * vec2(0.0, 1.0/u_ScreenHeight); + vec3 color = sampleCol(texCoord); + sum += (color+vec3(0.3)); + } + } + out_Color = vec4(out_Color.xyz + sum * 0.001, 0.0); + } + return; +} + diff --git a/base/res/shaders/diagnostic.frag b/base/res/shaders/diagnostic.frag index ac73727..8b598f1 100644 --- a/base/res/shaders/diagnostic.frag +++ b/base/res/shaders/diagnostic.frag @@ -10,6 +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 ///////////////////////////////////// diff --git a/base/res/shaders/directional.frag b/base/res/shaders/directional.frag index a34daab..e984c8d 100644 --- a/base/res/shaders/directional.frag +++ b/base/res/shaders/directional.frag @@ -10,6 +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 ///////////////////////////////////// diff --git a/base/res/shaders/point.frag b/base/res/shaders/point.frag index 98b90e0..6940ab3 100644 --- a/base/res/shaders/point.frag +++ b/base/res/shaders/point.frag @@ -10,6 +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 ///////////////////////////////////// @@ -106,10 +109,15 @@ void main() { if( u_DisplayType == DISPLAY_LIGHTS ) { //Put some code here to visualize the fragment associated with this point light + out_Color = vec4(vec3(0.6, 0.6, 0.0), 1.0); } else { //Put some code here to actually compute the light from the point light + float intensity = max(0.0, lightRadius-length(position-light))/lightRadius; + vec3 lightDir = normalize(light - position); + intensity = intensity * max(0.0, dot(normal, lightDir)); + out_Color = vec4(intensity * u_LightIl * color, 1.0); } return; } diff --git a/base/res/shaders/post.frag b/base/res/shaders/post.frag index 2bf5afc..582948e 100644 --- a/base/res/shaders/post.frag +++ b/base/res/shaders/post.frag @@ -10,6 +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 ///////////////////////////////////// @@ -67,7 +70,7 @@ const float occlusion_strength = 1.5f; 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); + float vin = 0.0;//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); return; } diff --git a/base/res/shaders/ssao.frag b/base/res/shaders/ssao.frag new file mode 100644 index 0000000..0b2d3d3 --- /dev/null +++ b/base/res/shaders/ssao.frag @@ -0,0 +1,150 @@ +#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 DISPLAY_SSAO 8 + + +///////////////////////////////////// +// Uniforms, Attributes, and Outputs +//////////////////////////////////// +uniform mat4 u_Persp; + +uniform sampler2D u_Depthtex; +uniform sampler2D u_Normaltex; +uniform sampler2D u_Positiontex; +uniform sampler2D u_RandomNormaltex; +uniform sampler2D u_RandomScalartex; + +uniform float u_Far; +uniform float u_Near; +uniform int u_DisplayType; + +uniform int u_ScreenWidth; +uniform int u_ScreenHeight; + +uniform float u_Distance; + +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 normals +vec3 samplePos(vec2 texcoords) { + return texture(u_Positiontex,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; +} + + + +//////////////////////////////////////////////// +/// BEGIN TODO: START HERE +////////////////////////////////////////////// + +//Estimate occlusion based on a point and a sampled occluder +//Design this function based on specified constraints +float gatherOcclusion( vec3 pt_normal, vec3 pt_position, vec3 occluder_normal, vec3 occluder_position ) { + vec3 diff = occluder_position - pt_position; + float d = length(diff); + float returnValue = 1.0; + if (d > u_Distance) + returnValue *= 0.0; + if (distance(pt_normal, occluder_normal) < 0.1) + returnValue *= 0.0; + returnValue *= (u_Distance-d)/u_Distance * max(0.0, dot(normalize(diff), pt_normal)); + return returnValue; +} + +const float REGULAR_SAMPLE_STEP = 0.012f; +float occlusionWithRegularSamples(vec2 texcoord, vec3 position, vec3 normal) { + float occlusion = 0.0; + for (int i = -5; i <= 5; i++) { + for (int j = -5; j <= 5; j++) { + vec2 texCoord = fs_Texcoord + i * vec2(0.0, 1.0/u_ScreenHeight) + j * vec2(1.0/u_ScreenWidth, 0.0); + occlusion += gatherOcclusion(normal, position, normalize(sampleNrm(texCoord)), samplePos(texCoord)); + } + } + return occlusion; +} + +////////////////////////////////////// +// END TODO +////////////////////////////////////// + + +/////////////////////////////////// +// MAIN, Shouldn't really need to mess with this much +////////////////////////////////// +const float occlusion_strength = 0.1f; +void main() { + + float exp_depth = texture(u_Depthtex, fs_Texcoord).r; + float lin_depth = linearizeDepth(exp_depth,u_Near,u_Far); + + vec3 normal = normalize(sampleNrm(fs_Texcoord)); + vec3 position = samplePos(fs_Texcoord); + + float occlusion = occlusionWithRegularSamples(fs_Texcoord, position, normal); + + occlusion = clamp(occlusion*occlusion_strength,0.0f,1.0f); + + if( u_DisplayType == DISPLAY_SSAO ) + { + if (lin_depth > 0.99f) { + out_Color = vec4(0.0f); + } else { + vec3 eyeToPosition = -normalize(position); + float diffuse = dot(eyeToPosition,normal); + float val = diffuse*0.7 + .3*(1.0f - occlusion); + out_Color = vec4(vec3(val),1.0f); + } + } + + return; +} \ No newline at end of file diff --git a/base/res/shaders/toon.frag b/base/res/shaders/toon.frag new file mode 100644 index 0000000..ee1e8f5 --- /dev/null +++ b/base/res/shaders/toon.frag @@ -0,0 +1,157 @@ +#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 DISPLAY_SSAO 8 + +///////////////////////////////////// +// 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; + +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; +} + +/////////////////////////////////// +// MAIN +////////////////////////////////// +const float occlusion_strength = 1.5f; +void main() { + + float exp_depth = texture(u_Depthtex, fs_Texcoord).r; + float lin_depth = linearizeDepth(exp_depth,u_Near,u_Far); + + vec3 normal = sampleNrm(fs_Texcoord); + vec3 position = samplePos(fs_Texcoord); + vec3 color = sampleCol(fs_Texcoord); + vec3 light = u_Light.xyz; + float lightRadius = u_Light.w; + out_Color = vec4(0,0,0,1.0); + if( u_DisplayType == DISPLAY_TOON ) + { + out_Color = vec4(1,1,1,1); + vec3 normals[8]; + normals[0] = sampleNrm(fs_Texcoord + vec2(-2.0/u_ScreenWidth, -2.0/u_ScreenHeight)); + normals[1] = sampleNrm(fs_Texcoord + vec2(2.0/u_ScreenWidth, -2.0/u_ScreenHeight)); + normals[2] = sampleNrm(fs_Texcoord + vec2(-2.0/u_ScreenWidth, 2.0/u_ScreenHeight)); + normals[3] = sampleNrm(fs_Texcoord + vec2(2.0/u_ScreenWidth, 2.0/u_ScreenHeight)); + normals[4] = sampleNrm(fs_Texcoord + vec2(-2.0/u_ScreenWidth, 0.0)); + normals[5] = sampleNrm(fs_Texcoord + vec2(2.0/u_ScreenWidth, 0.0)); + normals[6] = sampleNrm(fs_Texcoord + vec2(0.0, -2.0/u_ScreenHeight)); + normals[7] = sampleNrm(fs_Texcoord + vec2(0.0, 2.0/u_ScreenHeight)); + + vec3 pos[8]; + pos[0] = samplePos(fs_Texcoord + vec2(-2.0/u_ScreenWidth, -2.0/u_ScreenHeight)); + pos[1] = samplePos(fs_Texcoord + vec2(2.0/u_ScreenWidth, -2.0/u_ScreenHeight)); + pos[2] = samplePos(fs_Texcoord + vec2(-2.0/u_ScreenWidth, 2.0/u_ScreenHeight)); + pos[3] = samplePos(fs_Texcoord + vec2(2.0/u_ScreenWidth, 2.0/u_ScreenHeight)); + pos[4] = samplePos(fs_Texcoord + vec2(-2.0/u_ScreenWidth, 0.0)); + pos[5] = samplePos(fs_Texcoord + vec2(2.0/u_ScreenWidth, 0.0)); + pos[6] = samplePos(fs_Texcoord + vec2(0.0, -2.0/u_ScreenHeight)); + pos[7] = samplePos(fs_Texcoord + vec2(0.0, 2.0/u_ScreenHeight)); + + bool isEdge = false; + for (int i=0; i<8; i++) { + if (dot(normal, normals[i]) < 0.8) { + isEdge = true; + break; + } + if (length(position-pos[i]) > 1.0){ + isEdge = true; + break; + } + } + if (isEdge) { + out_Color = vec4(vec3(0.0), 1.0); + } + else { + float amb = u_LightIl; + float diffuse = max(0.0, dot(normalize(light),normal)); + out_Color = vec4(color*(lightRadius*diffuse + amb),1.0f); + out_Color.r = round(out_Color.r/0.5) * 0.5; + out_Color.g = round(out_Color.g/0.5) * 0.5; + out_Color.b = round(out_Color.b/0.5) * 0.5; + out_Color.a = 1.0; + } + } + return; +} + diff --git a/base/src/main.cpp b/base/src/main.cpp index 70c47c7..a60b369 100644 --- a/base/src/main.cpp +++ b/base/src/main.cpp @@ -220,6 +220,9 @@ GLuint point_prog; GLuint ambient_prog; GLuint diagnostic_prog; GLuint post_prog; +GLuint bloom_prog; +GLuint toon_prog; +GLuint ssao_prog; void initShader() { #ifdef WIN32 const char * pass_vert = "../../../res/shaders/pass.vert"; @@ -231,6 +234,9 @@ void initShader() { 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 * bloom_frag = "../../../res/shaders/bloom.frag"; + const char * toon_frag = "../../../res/shaders/toon.frag"; + const char * ssao_frag = "../../../res/shaders/ssao.frag"; #else const char * pass_vert = "../res/shaders/pass.vert"; const char * shade_vert = "../res/shaders/shade.vert"; @@ -241,6 +247,9 @@ void initShader() { 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 * bloom_frag = "../res/shaders/bloom.frag"; + const char * toon_frag = "../res/shaders/toon.frag"; + const char * ssao_frag = "../res/shaders/ssao.frag"; #endif Utility::shaders_t shaders = Utility::loadShaders(pass_vert, pass_frag); @@ -287,6 +296,36 @@ void initShader() { glBindAttribLocation(post_prog, quad_attributes::TEXCOORD, "Texcoord"); Utility::attachAndLinkProgram(post_prog, shaders); + + //bloom + shaders = Utility::loadShaders(shade_vert, bloom_frag); + + bloom_prog = glCreateProgram(); + + glBindAttribLocation(bloom_prog, quad_attributes::POSITION, "Position"); + glBindAttribLocation(bloom_prog, quad_attributes::TEXCOORD, "Texcoord"); + + Utility::attachAndLinkProgram(bloom_prog, shaders); + + //toon + shaders = Utility::loadShaders(shade_vert, toon_frag); + + toon_prog = glCreateProgram(); + + glBindAttribLocation(toon_prog, quad_attributes::POSITION, "Position"); + glBindAttribLocation(toon_prog, quad_attributes::TEXCOORD, "Texcoord"); + + Utility::attachAndLinkProgram(toon_prog, shaders); + + //ssao + shaders = Utility::loadShaders(shade_vert, ssao_frag); + + ssao_prog = glCreateProgram(); + + glBindAttribLocation(ssao_prog, quad_attributes::POSITION, "Position"); + glBindAttribLocation(ssao_prog, quad_attributes::TEXCOORD, "Texcoord"); + + Utility::attachAndLinkProgram(ssao_prog, shaders); } void freeFBO() { @@ -709,6 +748,15 @@ void updateDisplayText(char * disp) { case(DISPLAY_LIGHTS): sprintf(disp, "Displaying Lights"); break; + case(DISPLAY_BLOOM): + sprintf(disp, "Displaying Bloom"); + break; + case(DISPLAY_TOON): + sprintf(disp, "Displaying Toon"); + break; + case(DISPLAY_SSAO): + sprintf(disp, "Displaying SSAO"); + break; } } @@ -754,8 +802,12 @@ void display(void) glDisable(GL_DEPTH_TEST); glBlendFunc(GL_ONE, GL_ONE); glClear(GL_COLOR_BUFFER_BIT); + vec4 dir_light(0.1, 1.0, 1.0, 0.0); + dir_light = cam.get_view() * dir_light; + dir_light = normalize(dir_light); if(display_type == DISPLAY_LIGHTS || display_type == DISPLAY_TOTAL) { + setup_quad(point_prog); if(doIScissor) glEnable(GL_SCISSOR_TEST); mat4 vp = perspective(45.0f,(float)width/(float)height,NEARP,FARP) * @@ -771,17 +823,57 @@ void display(void) draw_light(vec3(2.5, -2.5, 5.0), 0.50, sc, vp, NEARP); + // glDisable(GL_SCISSOR_TEST); + // vec4 dir_light(0.1, 1.0, 1.0, 0.0); + //dir_light = cam.get_view() * dir_light; + //dir_light = normalize(dir_light); + // dir_light.w = 0.3; + //float strength = 0.5; + //setup_quad(ambient_prog); + int n = 14; + for (float i = 0; i < n; i+=.5) { + for (float j=0; j