diff --git a/1.png b/1.png new file mode 100644 index 0000000..fd2baf6 Binary files /dev/null and b/1.png differ diff --git a/2.png b/2.png new file mode 100644 index 0000000..6c991de Binary files /dev/null and b/2.png differ diff --git a/3.png b/3.png new file mode 100644 index 0000000..6853947 Binary files /dev/null and b/3.png differ diff --git a/4.png b/4.png new file mode 100644 index 0000000..98cb542 Binary files /dev/null and b/4.png differ diff --git a/5.png b/5.png new file mode 100644 index 0000000..7796bbf Binary files /dev/null and b/5.png differ diff --git a/6.png b/6.png new file mode 100644 index 0000000..b8cbc32 Binary files /dev/null and b/6.png differ diff --git a/7.png b/7.png new file mode 100644 index 0000000..02355ec Binary files /dev/null and b/7.png differ diff --git a/Performance Evaluation.xlsx b/Performance Evaluation.xlsx new file mode 100644 index 0000000..3f36d89 Binary files /dev/null and b/Performance Evaluation.xlsx differ diff --git a/README.md b/README.md index f22c764..2087a78 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,36 @@ Fall 2013 Due Friday 11/15/2013 ------------------------------------------------------------------------------- +Implemented: +- Bloom (Press '8'): applies 13x13 box filter on anything that is white-ish. +First tried with 5x5 Gaussian but was not blurry enough and was slowing down +too much. + +![Bloom](6.png) + +- Toon (Press '7'): also press '6' to get outline. + +![toon](2.png) +![outline](1.png) + + +- Point light sources + +![Point light](3.png) +![Point light 2](4.png) + +- Additional G buffer: Specular color (tall blue rectangle has red specular color) + +![Specular highlight](5.png) + +- Store normal.x and normal.y into color.w and specularColor.w and compute +normal.z by sqrt(1-x*x-y*y). Unfortunately I was not able to observe performance +improvement: + +![Bloom](7.png) + + + ------------------------------------------------------------------------------- NOTE: ------------------------------------------------------------------------------- diff --git a/base/res/cornell/cornell_box.mtl b/base/res/cornell/cornell_box.mtl index aae8474..330e05f 100644 --- a/base/res/cornell/cornell_box.mtl +++ b/base/res/cornell/cornell_box.mtl @@ -22,3 +22,8 @@ newmtl light Ka 20 20 20 Kd 1 1 1 Ks 0 0 0 + +newmtl blue_specular_red +Ka 0 0 0 +Kd 0 0 1 +Ks 1 0 0 \ No newline at end of file diff --git a/base/res/cornell/cornell_box.obj b/base/res/cornell/cornell_box.obj index 43e021f..b696223 100644 --- a/base/res/cornell/cornell_box.obj +++ b/base/res/cornell/cornell_box.obj @@ -110,7 +110,7 @@ v 82.0 0.0 225.0 f -4 -3 -2 -1 o tall_block -usemtl white +usemtl blue_specular_red 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 blue_specular_red 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/pass.frag b/base/res/shaders/pass.frag index e37dcbf..f13bee5 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_SpecularColor; in vec3 fs_Normal; in vec4 fs_Position; @@ -9,10 +10,13 @@ in vec4 fs_Position; out vec4 out_Normal; out vec4 out_Position; out vec4 out_Color; +out vec4 out_SpecularColor; void main(void) { - out_Normal = vec4(normalize(fs_Normal),0.0f); + vec3 N_unit = normalize(fs_Normal); + out_Normal = vec4(N_unit,0.0f); out_Position = vec4(fs_Position.xyz,1.0f); //Tuck position into 0 1 range - out_Color = vec4(u_Color,1.0); + out_Color = vec4(u_Color, N_unit.x); + out_SpecularColor = vec4(u_SpecularColor, N_unit.y); } diff --git a/base/res/shaders/point.frag b/base/res/shaders/point.frag index 98b90e0..a4f2ec3 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_OUTLINE 6 +#define DISPLAY_TOON 7 +#define DISPLAY_BLOOM 8 ///////////////////////////////////// @@ -23,6 +26,7 @@ uniform sampler2D u_Positiontex; uniform sampler2D u_Colortex; uniform sampler2D u_RandomNormaltex; uniform sampler2D u_RandomScalartex; +uniform sampler2D u_SpecularColortex; uniform float u_Far; uniform float u_Near; @@ -58,7 +62,13 @@ float linearizeDepth(float exp_depth, float near, float far) { //Helper function to automatically sample and unpack normals vec3 sampleNrm(vec2 texcoords) { - return texture(u_Normaltex,texcoords).xyz; + // Original G-buffer. + return texture(u_Normaltex,texcoords).xyz; + + // Compact G-buffer. + //float Nx = texture(u_Colortex,texcoords).w; + //float Ny = texture(u_SpecularColortex,texcoords).w; + //return vec3(Nx, Ny, sqrt(1.0 - Nx*Nx - Ny*Ny)); } //Helper function to automicatlly sample and unpack positions @@ -66,11 +76,16 @@ vec3 samplePos(vec2 texcoords) { return texture(u_Positiontex,texcoords).xyz; } -//Helper function to automicatlly sample and unpack positions +//Helper function to automicatlly sample and unpack colors vec3 sampleCol(vec2 texcoords) { return texture(u_Colortex,texcoords).xyz; } +//Helper function to automicatlly sample and unpack specular colors +vec3 sampleSpecCol(vec2 texcoords) { + return texture(u_SpecularColortex,texcoords).xyz; +} + //Get a random normal vector given a screen-space texture coordinate //Actually accesses a texture of random vectors vec3 getRandomNormal(vec2 texcoords) { @@ -106,10 +121,35 @@ void main() { if( u_DisplayType == DISPLAY_LIGHTS ) { //Put some code here to visualize the fragment associated with this point light + out_Color = vec4(1.0, 0.0, 0.0, 1.0); } else { //Put some code here to actually compute the light from the point light + + vec3 N_unit = normalize(normal); // Normal. + vec3 L = light - position; // Fragment to light. + vec3 L_unit = normalize(L); + vec3 E_unit = normalize(-position); // Fragment to eye. + vec3 R_unit = normalize(-reflect(L_unit, N_unit)); // Fragment to reflected light direction. + + float lightIntensity = u_LightIl * max(lightRadius-length(L), 0.0) / lightRadius; + + // Diffuse term + vec3 diffuseColor = color * max(dot(N_unit, L_unit), 0.0); + diffuseColor = clamp(diffuseColor, 0.0, 1.0); + + // Specular term + vec3 specularColor = sampleSpecCol(fs_Texcoord); + { + float specularExponent = 15.0; + float magnitude = max(dot(R_unit, E_unit), 0.0); + specularColor *= pow(magnitude, specularExponent); + } + specularColor = clamp(specularColor, 0.0, 1.0); + + out_Color = vec4(lightIntensity * (diffuseColor + specularColor), 1.0); + //out_Color = vec4(clamp(lightIntensity*color*diffuseTerm, 0.0, 1.0), 1.0); } return; } diff --git a/base/res/shaders/post.frag b/base/res/shaders/post.frag index 2bf5afc..6c3feda 100644 --- a/base/res/shaders/post.frag +++ b/base/res/shaders/post.frag @@ -10,11 +10,18 @@ #define DISPLAY_COLOR 3 #define DISPLAY_TOTAL 4 #define DISPLAY_LIGHTS 5 +#define DISPLAY_OUTLINE 6 +#define DISPLAY_TOON 7 +#define DISPLAY_BLOOM 8 ///////////////////////////////////// // Uniforms, Attributes, and Outputs //////////////////////////////////// +uniform int u_DisplayType; + +uniform sampler2D u_Colortex; +uniform sampler2D u_Normaltex; uniform sampler2D u_Posttex; uniform sampler2D u_RandomNormaltex; uniform sampler2D u_RandomScalartex; @@ -60,15 +67,118 @@ float getRandomScalar(vec2 texcoords) { texcoords.t*u_ScreenHeight/sz.y)).r; } +vec3 multiplyNormal(int x, int y, float n) +{ + vec2 xy = fs_Texcoord + vec2(float(x)/u_ScreenWidth, float(y)/u_ScreenHeight); + return texture(u_Normaltex, xy).xyz * n; +} + +vec3 convolve3x3(float i11, float i12, float i13, float i21, float i22, float i23, + float i31, float i32, float i33) +{ + vec3 v11 = multiplyNormal(-1, 1, i11); + vec3 v12 = multiplyNormal(0, 1, i12); + vec3 v13 = multiplyNormal(1, 1, i13); + vec3 v21 = multiplyNormal(-1, 0, i21); + vec3 v22 = multiplyNormal(0, 0, i22); + vec3 v23 = multiplyNormal(1, 0, i23); + vec3 v31 = multiplyNormal(-1, -1, i31); + vec3 v32 = multiplyNormal(0, -1, i32); + vec3 v33 = multiplyNormal(1, -1, i33); + return v11+v12+v13+v21+v22+v23+v31+v32+v33; +} + +float sobel() +{ + vec3 gx = convolve3x3(1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0); + vec3 gy = convolve3x3(1.0, 2.0, 1.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0); + float gxGray = (gx.x + gx.y + gx.z) / 3.0; + float gyGray = (gy.x + gy.y + gy.z) / 3.0; + return sqrt(gxGray*gxGray + gyGray*gyGray); +} + +vec3 discretize(vec3 value, int numBins) +{ + float t = numBins; + return floor(value * t) / t; +} + +vec3 multiplyBrightColor(int x, int y, float n) +{ + vec2 offset = vec2(float(x)/u_ScreenWidth, float(y)/u_ScreenHeight); + vec3 value = texture(u_Colortex, fs_Texcoord + offset).xyz; + return value * n * float(value.x + value.y + value.z > 2.6); +} + +// Gaussian blur is too slow. +/* +uniform float kernel[25] = float[]( + 1, 4, 7, 4, 1, + 4, 16, 26, 16, 4, + 7, 26, 41, 26, 7, + 4, 16, 26, 16, 4, + 1, 4, 7, 4, 1); +*/ + +vec3 getBlurColor() +{ + vec3 color = vec3(0.0); + // Box blur 13x13 + for (int i = -6; i < 7; ++i) + { + for (int j = -6; j < 7; ++j) + { + vec2 offset = vec2(float(i)/u_ScreenWidth, float(j)/u_ScreenHeight); + vec3 value = texture(u_Colortex, fs_Texcoord + offset).xyz; + if (value.x + value.y + value.z > 2.6) color += value; + } + } + color /= 169.0; + /* + // Gaussian blur 5x5 + for (int i = -2; i < 3; ++i) + { + for (int j = -2; j < 3; ++j) + { + int idx = (i+2)*5 + (j+2); + color += multiplyBrightColor(i, j, kernel[idx] / 273.0); + } + } + */ + return color; +} + /////////////////////////////////// // MAIN ////////////////////////////////// const float occlusion_strength = 1.5f; void main() { vec3 color = sampleCol(fs_Texcoord); - float gray = dot(color, vec3(0.2125, 0.7154, 0.0721)); + vec3 outlineColor = vec3(sobel() < 0.1); + vec3 discretizedColor = discretize(color, 10); + + if (u_DisplayType == DISPLAY_OUTLINE) + { + out_Color = vec4(outlineColor, 1.0); + return; + } + + if (u_DisplayType == DISPLAY_TOON) + { + out_Color = vec4(outlineColor * discretizedColor, 1.0); + return; + } + + if (u_DisplayType == DISPLAY_BLOOM) + { + out_Color = vec4(color + getBlurColor() * 0.7, 1.0); + return; + } + + 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); + return; } diff --git a/base/src/main.cpp b/base/src/main.cpp index 70c47c7..a5d2deb 100644 --- a/base/src/main.cpp +++ b/base/src/main.cpp @@ -21,6 +21,8 @@ using namespace std; using namespace glm; +#define PACK_NORMAL 1 + const float PI = 3.14159f; int width, height; @@ -80,6 +82,7 @@ device_mesh_t uploadMesh(const mesh_t & mesh) { out.texname = mesh.texname; out.color = mesh.color; + out.specularColor = mesh.specularColor; return out; } @@ -162,6 +165,9 @@ void initMesh() { shape.material.diffuse[1], shape.material.diffuse[2]); mesh.texname = shape.material.diffuse_texname; + mesh.specularColor = vec3(shape.material.specular[0], + shape.material.specular[1], + shape.material.specular[2]); draw_meshes.push_back(uploadMesh(mesh)); f=f+process; } @@ -212,6 +218,7 @@ GLuint normalTexture = 0; GLuint positionTexture = 0; GLuint colorTexture = 0; GLuint postTexture = 0; +GLuint specularColorTexture = 0; GLuint FBO[2] = {0, 0}; @@ -295,6 +302,7 @@ void freeFBO() { glDeleteTextures(1,&positionTexture); glDeleteTextures(1,&colorTexture); glDeleteTextures(1,&postTexture); + glDeleteTextures(1,&specularColorTexture); glDeleteFramebuffers(1,&FBO[0]); glDeleteFramebuffers(1,&FBO[1]); } @@ -366,6 +374,7 @@ void initFBO(int w, int h) { glGenTextures(1, &normalTexture); glGenTextures(1, &positionTexture); glGenTextures(1, &colorTexture); + glGenTextures(1, &specularColorTexture); //Set up depth FBO glBindTexture(GL_TEXTURE_2D, depthTexture); @@ -410,7 +419,18 @@ void initFBO(int w, int h) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F , w, h, 0, GL_RGBA, GL_FLOAT,0); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA32F , w, h, 0, GL_RGBA, GL_FLOAT,0); + + //Set up specular color FBO + glBindTexture(GL_TEXTURE_2D, specularColorTexture); + + 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); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA32F , w, h, 0, GL_RGBA, GL_FLOAT,0); // creatwwe a framebuffer object glGenFramebuffers(1, &FBO[0]); @@ -421,11 +441,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 specularColor_loc = glGetFragDataLocation(pass_prog,"out_SpecularColor"); + 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[specularColor_loc] = GL_COLOR_ATTACHMENT3; + glDrawBuffers(4, draws); // attach the texture to FBO depth attachment point int test = GL_COLOR_ATTACHMENT0; @@ -437,6 +459,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, specularColorTexture); + glFramebufferTexture(GL_FRAMEBUFFER, draws[specularColor_loc], specularColorTexture, 0); // check FBO status FBOstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -591,6 +615,7 @@ void draw_mesh() { for(int i=0; i indices; std::string texname; glm::vec3 color; + glm::vec3 specularColor; } mesh_t; typedef struct { @@ -48,6 +49,7 @@ typedef struct { unsigned int vbo_texcoords; glm::vec3 color; std::string texname; + glm::vec3 specularColor; } device_mesh_t; typedef struct { @@ -83,7 +85,10 @@ enum Display { DISPLAY_POSITION = 2, DISPLAY_COLOR = 3, DISPLAY_TOTAL = 4, - DISPLAY_LIGHTS = 5 + DISPLAY_LIGHTS = 5, + DISPLAY_OUTLINE = 6, + DISPLAY_TOON = 7, + DISPLAY_BLOOM = 8 }; char* loadFile(char *fname, GLint &fSize);