Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,49 @@
WebGL Deferred Shading
======================
# University of Pennsylvania, CIS 565: GPU Programming and Architecture.
Project 5: WebGL Deferred Shading
===============

**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 5**
## User resources
- **Name:** David Grosman.
- **Tested on:** Microsoft Windows 7 Professional, i7-5600U @ 2.6GHz, 256GB, GeForce 840M (Personal laptop).

* (TODO) YOUR NAME HERE
* Tested on: (TODO) **Google Chrome 222.2** on
Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)
### Demo Video/GIF

### Live Online
[![](img/Video.gif)]

[![](img/thumb.png)](http://TODO.github.io/Project5B-WebGL-Deferred-Shading)
## Project description
This Project's purpose was to gain some experience with the basics of deferred shading and WebGL. I used GLSL and WebGL to implement a deferred shading pipeline and various lighting and visual effects.
In this project, I have implemented the following features:

### Demo Video/GIF
* Implement deferred Blinn-Phong shading (diffuse + specular) for point lights
* With normal mapping
* Implemented a Bloom Shader using post-process Gaussian blur.
* Scissor test optimization: I only accumulating shading from each point light source from a rectangle around the light.
* Optimized g-buffer format - reduced the number and size of g-buffers by:
* Packing values together into vec4s
* Using 2-component normals
* Reducing the number of properties passed via g-buffer by applying the normal map in the `copy` shader pass instead of copying both geometry normals and normal maps.

### Performance Analysis
![](img/ScissorTestPerf.JPG)

[![](img/video.png)](TODO)
From the graph above, we notice that:
1. Scissoring is a very optimization feature and scales well as the number of lights in the scene increases.
2. The Sphere scissoring is faster with fewer lights. This is mostly because while sphere proxies reduces the shaded area, they are overall more expensive to render than simple quads.

### (TODO: Your README)
I have also noticed that applying the normal map in the `copy` shader pass instead of copying both geometry normals and normal maps is much faster (around 150% because of reduced memory bandwidth necessary to perform the operation). Using 2-component normals however is slower because of the mathematical operations necessary to compress the normal and to retrieve their Z component from their X and Y ones.

*DO NOT* leave the README to the last minute! It is a crucial part of the
project, and we will not be able to grade you without a good README.
### Running the code
If you have Python, you should be able to run `server.py` to start a server.
Then, open [`http://localhost:10565/`](http://localhost:10565/) in your browser.

This assignment has a considerable amount of performance analysis compared
to implementation work. Complete the implementation early to leave time!
This project requires a WebGL-capable web browser with support for
`WEBGL_draw_buffers`. You can check for support on
[WebGL Report](http://webglreport.com/).

Google Chrome seems to work best on all platforms. If you have problems running
the starter code, use Chrome or Chromium, and make sure you have updated your
browser and video drivers. Firefox's shader editor may require that you disable
WebGL debugging in `framework.js` (see below).

### Credits

Expand Down
17 changes: 15 additions & 2 deletions glsl/copy.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,24 @@ varying vec3 v_position;
varying vec3 v_normal;
varying vec2 v_uv;

void main() {
vec3 applyNormalMap(vec3 geomnor, vec3 normap) {
normap = normap * 2.0 - 1.0;
vec3 up = normalize(vec3(0.001, 1, 0.001));
vec3 surftan = normalize(cross(geomnor, up));
vec3 surfbinor = cross(geomnor, surftan);
return normap.y * surftan + normap.x * surfbinor + normap.z * geomnor;
}

void main()
{
// TODO: copy values into gl_FragData[0], [1], etc.
// You can use the GLSL texture2D function to access the textures using
// the UV in v_uv.

vec3 normalMap = texture2D(u_normap, v_uv).rgb;
vec3 objNormal = applyNormalMap (v_normal, normalMap);
// this gives you the idea
// gl_FragData[0] = vec4( v_position, 1.0 );
gl_FragData[0] = vec4(v_position, 1.0);
gl_FragData[1] = vec4(objNormal, 0.0);
gl_FragData[2] = texture2D(u_colmap, v_uv);
}
10 changes: 5 additions & 5 deletions glsl/deferred/ambient.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ uniform sampler2D u_depth;

varying vec2 v_uv;

const vec3 AMBIENT_COLOR = vec3(0.36, 0.36, 0.36);

void main() {
vec4 gb0 = texture2D(u_gbufs[0], v_uv);
vec4 gb1 = texture2D(u_gbufs[1], v_uv);
vec4 gb2 = texture2D(u_gbufs[2], v_uv);
vec4 gb3 = texture2D(u_gbufs[3], v_uv);
float depth = texture2D(u_depth, v_uv).x;
// TODO: Extract needed properties from the g-buffers into local variables

if (depth == 1.0) {
gl_FragColor = vec4(0, 0, 0, 0); // set alpha to 0
return;
}

gl_FragColor = vec4(0.1, 0.1, 0.1, 1); // TODO: replace this
vec3 mtrlClr = gb2.rgb; // The color map - unlit "albedo" (surface color)

gl_FragColor = vec4(AMBIENT_COLOR * mtrlClr, 1.0);
}
46 changes: 30 additions & 16 deletions glsl/deferred/blinnphong-pointlight.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,18 @@ precision highp int;

#define NUM_GBUFFERS 4

uniform vec3 u_lightCol;
uniform vec3 u_cameraPos;
uniform vec3 u_lightPos;
uniform vec3 u_lightCol;
uniform float u_lightRad;

uniform sampler2D u_gbufs[NUM_GBUFFERS];
uniform sampler2D u_depth;

varying vec2 v_uv;

vec3 applyNormalMap(vec3 geomnor, vec3 normap) {
normap = normap * 2.0 - 1.0;
vec3 up = normalize(vec3(0.001, 1, 0.001));
vec3 surftan = normalize(cross(geomnor, up));
vec3 surfbinor = cross(geomnor, surftan);
return normap.y * surftan + normap.x * surfbinor + normap.z * geomnor;
}

void main() {
vec4 gb0 = texture2D(u_gbufs[0], v_uv);
vec4 gb1 = texture2D(u_gbufs[1], v_uv);
vec4 gb2 = texture2D(u_gbufs[2], v_uv);
vec4 gb3 = texture2D(u_gbufs[3], v_uv);
float depth = texture2D(u_depth, v_uv).x;
// TODO: Extract needed properties from the g-buffers into local variables
float depth = texture2D(u_depth, v_uv).x;

// If nothing was rendered to this pixel, set alpha to 0 so that the
// postprocessing step can render the sky color.
Expand All @@ -35,5 +24,30 @@ void main() {
return;
}

gl_FragColor = vec4(0, 0, 1, 1); // TODO: perform lighting calculations
vec4 gb0 = texture2D(u_gbufs[0], v_uv);
vec4 gb1 = texture2D(u_gbufs[1], v_uv);
vec4 gb2 = texture2D(u_gbufs[2], v_uv);
vec4 gb3 = texture2D(u_gbufs[3], v_uv);

vec3 objPos = gb0.xyz; // World-space position
vec3 objClr = gb2.rgb; // The color map - unlit "albedo" (surface color)
vec3 objNormal = gb1.xyz; // The true normals as we want to light them - with the normal map applied to the geometry normals (applyNormalMap above)

vec3 lightDir = normalize(objPos - u_lightPos);
vec3 viewDir = normalize(objPos - u_cameraPos);
vec3 lightReflDir = normalize(reflect(lightDir, objNormal));

// Calculate Diffuse Term:
float Idiff = max(-dot(objNormal,lightDir), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);

// Calculate Specular Term:
float Ispec = pow( max( dot(lightReflDir,-viewDir), 0.0), 15.0 );
Ispec = clamp(Ispec, 0.0, 1.0);

float distLightToObj = distance(u_lightPos, objPos);
float attenuation = 1.0 - clamp( pow( distLightToObj / u_lightRad, 2.0), 0.0, 1.0 );

// write Total Color:
gl_FragColor = vec4( attenuation * u_lightCol * (objClr*Idiff+vec3(1,1,1)*Ispec), 1);
}
28 changes: 10 additions & 18 deletions glsl/deferred/debug.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ varying vec2 v_uv;

const vec4 SKY_COLOR = vec4(0.66, 0.73, 1.0, 1.0);

vec3 applyNormalMap(vec3 geomnor, vec3 normap) {
normap = normap * 2.0 - 1.0;
vec3 up = normalize(vec3(0.001, 1, 0.001));
vec3 surftan = normalize(cross(geomnor, up));
vec3 surfbinor = cross(geomnor, surftan);
return normap.y * surftan + normap.x * surfbinor + normap.z * geomnor;
}

void main() {
vec4 gb0 = texture2D(u_gbufs[0], v_uv);
vec4 gb1 = texture2D(u_gbufs[1], v_uv);
Expand All @@ -29,25 +21,25 @@ void main() {
// TODO: Extract needed properties from the g-buffers into local variables
// These definitions are suggested for starting out, but you will probably want to change them.
vec3 pos = gb0.xyz; // World-space position
vec3 geomnor = gb1.xyz; // Normals of the geometry as defined, without normal mapping
vec3 nor = gb1.xyz; // The true normals as we want to light them - with the normal map applied to the geometry normals (applyNormalMap above)
vec3 colmap = gb2.rgb; // The color map - unlit "albedo" (surface color)
vec3 normap = gb3.xyz; // The raw normal map (normals relative to the surface they're on)
vec3 nor = applyNormalMap (geomnor, normap); // The true normals as we want to light them - with the normal map applied to the geometry normals (applyNormalMap above)


// TODO: uncomment
if (u_debug == 0) {
gl_FragColor = vec4(vec3(depth), 1.0);
} else if (u_debug == 1) {
// gl_FragColor = vec4(abs(pos) * 0.1, 1.0);
} else if (u_debug == 2) {
// gl_FragColor = vec4(abs(geomnor), 1.0);
} else if (u_debug == 3) {
// gl_FragColor = vec4(colmap, 1.0);
gl_FragColor = vec4(abs(pos) * 0.1, 1.0);
} /*else if (u_debug == 2) {
gl_FragColor = vec4(abs(geomnor), 1.0);
} */else if (u_debug == 3) {
gl_FragColor = vec4(colmap, 1.0);
} else if (u_debug == 4) {
// gl_FragColor = vec4(normap, 1.0);
gl_FragColor = vec4(normap, 1.0);
} else if (u_debug == 5) {
// gl_FragColor = vec4(abs(nor), 1.0);
gl_FragColor = vec4(abs(nor), 1.0);
} else {
gl_FragColor = vec4(1, 0, 1, 1);
gl_FragColor = vec4(0, 0, 1, 1);
}
}
21 changes: 21 additions & 0 deletions glsl/post/brightnessExtractor.frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#version 100
precision highp float;
precision highp int;

uniform sampler2D u_color;

varying vec2 v_uv;

const vec4 SKY_COLOR = vec4(0.01, 0.14, 0.42, 1.0);

void main() {
vec4 color = texture2D(u_color, v_uv);

float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
if(brightness > 1.0) {
gl_FragColor = color;
}
else{
gl_FragColor = vec4(0, 0, 0, 1);
}
}
File renamed without changes.
37 changes: 37 additions & 0 deletions glsl/post/gaussBlur.frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#version 100
precision highp float;
precision highp int;

uniform sampler2D u_color;
uniform bool u_horizontal;
uniform vec2 u_texelSize;
uniform float u_kernelWeights[5];

varying vec2 v_uv;

void main()
{
vec2 tex_offset = 1.0 / u_texelSize; // gets size of single texel
vec3 result = texture2D(u_color, v_uv).rgb; // current fragment's contribution
if(u_horizontal)
{
for(int i = 1; i < 5; ++i)
{
float fI = float(i);

result += texture2D(u_color, v_uv + vec2(tex_offset.x * fI, 0.0)).rgb * u_kernelWeights[i];
result += texture2D(u_color, v_uv - vec2(tex_offset.x * fI, 0.0)).rgb * u_kernelWeights[i];
}
}
else
{
for(int i = 1; i < 5; ++i)
{
float fI = float(i);

result += texture2D(u_color, v_uv + vec2(0.0, tex_offset.y * fI)).rgb * u_kernelWeights[i];
result += texture2D(u_color, v_uv - vec2(0.0, tex_offset.y * fI)).rgb * u_kernelWeights[i];
}
}
gl_FragColor = vec4(result, 1.0);
}
2 changes: 1 addition & 1 deletion glsl/red.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ precision highp float;
precision highp int;

void main() {
gl_FragColor = vec4(1, 0, 0, 1);
gl_FragColor = vec4(1, 0, 0, 0.001);
}
13 changes: 13 additions & 0 deletions glsl/sphere.vert.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#version 100
precision highp float;
precision highp int;

uniform mat4 u_cameraMtx;
uniform mat4 u_worldMtx;

attribute vec3 a_position;
varying vec2 v_uv;

void main() {
gl_Position = u_cameraMtx * u_worldMtx * vec4(a_position, 1.0);
}
Binary file added img/PerfSheet.xlsx
Binary file not shown.
Binary file added img/ScissorTestPerf.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/Video.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading