diff --git a/README.md b/README.md index 31db119..382702f 100644 --- a/README.md +++ b/README.md @@ -3,423 +3,52 @@ WebGL Deferred Shading **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 6** -* (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) +* Xinyue Zhu +* Tested on: **Google Chrome 46.0.2490.71 m** on + Windows 10, i5-5200U @ 2.2GHz 8.00GB, GTX 960M 222MB ### Live Online -[![](img/thumb.png)](http://TODO.github.io/Project6-WebGL-Deferred-Shading) +[![](img/thumb.png)](http://Zhuxinyue909.github.io/Project6-WebGL-Deferred-Shading) ### Demo Video -[![](img/video.png)](TODO) +[![](img/video.png)](https://www.youtube.com/watch?v=z_TlmlxQoGs) -### (TODO: Your README) - -*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. - -This assignment has a considerable amount of performance analysis compared -to implementation work. Complete the implementation early to leave time! - - -Instructions (delete me) ======================== - -This is due at midnight on the evening of Sunday, October 25. - -**Summary:** In this project, you'll be introduced to the basics of deferred -shading and WebGL. You'll use GLSL and WebGL to implement a deferred shading -pipeline and various lighting and visual effects. - -**Recommendations:** -Take screenshots as you go. Use them to document your progress in your README! - -Read (or at least skim) the full README before you begin, so that you know what -to expect and what to prepare for. - -### 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 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. - -In Moore 100C, both Chrome and Firefox work. -See below for notes on profiling/debugging tools. - -Use the screenshot button to save a screenshot. - -## Requirements - -**Ask on the mailing list for any clarifications.** - -In this project, you are given code for: - -* Loading OBJ files and color/normal map textures -* Camera control -* Partial implementation of deferred shading including many helper functions - -### Required Tasks - -**Before doing performance analysis,** you must disable debug mode by changing -`debugMode` to `false` in `framework.js`. Keep it enabled when developing - it -helps find WebGL errors *much* more easily. - -You will need to perform the following tasks: - -* Complete the deferred shading pipeline so that the Blinn-Phong and Post1 - shaders recieve the correct input. Go through the Starter Code Tour **before - continuing!** - -**Effects:** - -* Implement deferred Blinn-Phong shading (diffuse + specular) - * With normal mapping (code provided) - -* Implement one of the following effects: - * Bloom using post-process blur (box or Gaussian) [1] - * Toon shading (with ramp shading + simple depth-edge detection for outlines) - -**Optimizations:** - -* Scissor test optimization: when accumulating shading from each point - light source, only render in a rectangle around the light. - * Show a debug view for this (showing scissor masks clearly), e.g. by - modifying and using `red.frag.glsl` with additive blending. - * Code is provided to compute this rectangle for you, and there are - comments at the relevant place in `deferredRender.js` with more guidance. - -* Optimized g-buffer format - reduce the number and size of g-buffers: - * Ideas: - * Pack values together into vec4s - * Use 2-component normals - * Quantize values by using smaller texture types instead of gl.FLOAT - * Reduce number of properties passed via g-buffer, e.g. by: - * Applying the normal map in the `copy` shader pass instead of - copying both geometry normals and normal maps - * Reconstructing world space position using camera matrices and X/Y/depth - * For credit, you must show a good optimization effort and record the - performance of each version you test, in a simple table. - * It is expected that you won't need all 4 provided g-buffers for a basic - pipeline - make sure you disable the unused ones. - * See mainly: `copy.frag.glsl`, `deferred/*.glsl`, `deferredSetup.js` - -### Extra Tasks - -You must do at least **10 points** worth of extra features (effects or -optimizations/analysis). - -**Effects:** - -* (3pts) The effect you didn't choose above (bloom or toon shading) - -* (3pts) Screen-space motion blur (blur along velocity direction) [3] - -* (2pts) Allow variability in additional material properties - * Include other properties (e.g. specular coeff/exponent) in g-buffers - * Use this to render objects with different material properties - * These may be uniform across one model draw call, but you'll have to show - multiple models - -**Optimizations/Analysis:** - -* (2pts) Improved screen-space AABB for scissor test - (smaller/more accurate than provided - but beware of CPU/GPU tradeoffs) - -* (3pts) Two-pass **Gaussian** blur using separable convolution (using a second - postprocess render pass) to improve bloom or other 2D blur performance - -* (4-6pts) Light proxies - * (4pts) Instead of rendering a scissored full-screen quad for every light, - render some proxy geometry which covers the part of the screen affected by - the light (e.g. a sphere, for an attenuated point light). - * A model called `sphereModel` is provided which can be drawn in the same - way as the code in `drawScene`. (Must be drawn with a vertex shader which - scales it to the light radius and translates it to the light position.) - * (+2pts) To avoid lighting geometry far behind the light, render the proxy - geometry (e.g. sphere) using an inverted depth test - (`gl.depthFunc(gl.GREATER)`) with depth writing disabled (`gl.depthMask`). - This test will pass only for parts of the screen for which the backside of - the sphere appears behind parts of the scene. - * Note that the copy pass's depth buffer must be bound to the FBO during - this operation! - * Show a debug view for this (showing light proxies) - * Compare performance of this, naive, and scissoring. - -* (8pts) Tile-based deferred shading with detailed performance comparison - * On the CPU, check which lights overlap which tiles. Then, render each tile - just once for all lights (instead of once for each light), applying only - the overlapping lights. - * The method is described very well in - [Yuqin & Sijie's README](https://github.com/YuqinShao/Tile_Based_WebGL_DeferredShader/blob/master/README.md#algorithm-details). - * This feature requires allocating the global light list and tile light - index lists as shown at this link. These can be implemented as textures. - * Show a debug view for this (number of lights per tile) - -* (6pts) Deferred shading without multiple render targets - (i.e. without WEBGL_draw_buffers). - * Render the scene once for each target g-buffer, each time into a different - framebuffer object. - * Include a detailed performance analysis, comparing with/without - WEBGL_draw_buffers (like in the - [Mozilla blog article](https://hacks.mozilla.org/2014/01/webgl-deferred-shading/)). - -* (2-6pts) Compare performance to equivalently-lit forward-rendering: - * (2pts) With no forward-rendering optimizations - * (+2pts) Coarse, per-object back-to-front sorting of geometry for early-z - * (Of course) must render many objects to test - * (+2pts) Z-prepass for early-z - -This extra feature list is not comprehensive. If you have a particular idea -that you would like to implement, please **contact us first** (preferably on -the mailing list). - -**Where possible, all features should be switchable using the GUI panel in -`ui.js`.** - +### Feature +Features: +

1.Blinn-Phong shading for point lights.

+

2.scissor test and debug view.

+

3.bloom shading using Gaussian blur.

+

4.Optimized g-buffer.

+Extra: +

5.Toon shading, the width of the outline is changed due to the distance to the viewer, more like comic.

+

6.Allow variability in additional material properties. add extra cube.since all the texture I find for the cow makes it look wired.

+

7.Optimized 2 pass Gaussian bloom.

+

8.AABB box for light.

+##the toon effect +

+Happy Helloween! +

### Performance & Analysis -**Before doing performance analysis,** you must disable debug mode by changing -`debugMode` to `false` in `framework.js`. Keep it enabled when developing - it -helps find WebGL errors *much* more easily. - -Optimize your JavaScript and/or GLSL code. Web Tracing Framework -and Chrome/Firefox's profiling tools (see Resources section) will -be useful for this. For each change -that improves performance, show the before and after render times. - -For each new *effect* feature (required or extra), please -provide the following analysis: - -* Concise overview write-up of the feature. -* Performance change due to adding the feature. - * If applicable, how do parameters (such as number of lights, etc.) - affect performance? Show data with simple graphs. -* If you did something to accelerate the feature, what did you do and why? -* How might this feature be optimized beyond your current implementation? - -For each *performance* feature (required or extra), please provide: - -* Concise overview write-up of the feature. -* Detailed performance improvement analysis of adding the feature - * What is the best case scenario for your performance improvement? What is - the worst? Explain briefly. - * Are there tradeoffs to this performance feature? Explain briefly. - * How do parameters (such as number of lights, tile size, etc.) affect - performance? Show data with graphs. - * Show debug views when possible. - * If the debug view correlates with performance, explain how. - -Note: Be aware that stats.js may give 0 millisecond frame timings in Chrome on -occasion - if this happens, you can use the FPS counter. - -### Starter Code Tour - -You'll be working mainly in `deferredRender.js` using raw WebGL. Three.js is -included in the project for various reasons. You won't use it for much, but its -matrix/vector types may come in handy. - -It's highly recommended that you use the browser debugger to inspect variables -to get familiar with the code. At any point, you can also -`console.log(some_var);` to show it in the console and inspect it. - -The setup in `deferredSetup` is already done for you, for many of the features. -If you want to add uniforms (textures or values), you'll change them here. -Therefore, it is recommended that you review the comments to understand the -process, BEFORE starting work in `deferredRender`. - -In `deferredRender`, start at the **START HERE!** comment. -Work through the appropriate **`TODO`s** as you go - most of them are very -small. Test incrementally (after implementing each part, instead of testing -all at once). - -Your first goal should be to get the debug views working. -Add code in `debug.frag.glsl` to examine your g-buffers before trying to -render them. (Set the debugView in the UI to show them.) - -For editing JavaScript, you can use a simple editor with syntax highlighting -such as Sublime, Vim, Emacs, etc., or the editor built into Chrome. - -* `js/`: JavaScript files for this project. - * `main.js`: Handles initialization of other parts of the program. - * `framework.js`: Loads the scene, camera, etc., and calls your setup/render - functions. Hopefully, you won't need to change anything here. - * `deferredSetup.js`: Deferred shading pipeline setup code. - * `createAndBind(Depth/Color)TargetTexture`: Creates empty textures for - binding to frame buffer objects as render targets. - * `deferredRender.js`: Your deferred shading pipeline execution code. - * `renderFullScreenQuad`: Renders a full-screen quad with the given shader - program. - * `ui.js`: Defines the UI using - [dat.GUI](https://workshop.chromeexperiments.com/examples/gui/). - * The global variable `cfg` can be accessed anywhere in the code to read - configuration values. - * `utils.js`: Utilities for JavaScript and WebGL. - * `abort`: Aborts the program and shows an error. - * `loadTexture`: Loads a texture from a URL into WebGL. - * `loadShaderProgram`: Loads shaders from URLs into a WebGL shader program. - * `loadModel`: Loads a model into WebGL buffers. - * `readyModelForDraw`: Configures the WebGL state to draw a model. - * `drawReadyModel`: Draws a model which has been readied. - * `getScissorForLight`: Computes an approximate scissor rectangle for a - light in world space. -* `glsl/`: GLSL code for each part of the pipeline: - * `clear.*.glsl`: Clears each of the `NUM_GBUFFERS` g-buffers. - * `copy.*.glsl`: Performs standard rendering without any fragment shading, - storing all of the resulting values into the `NUM_GBUFFERS` g-buffers. - * `quad.vert.glsl`: Minimal vertex shader for rendering a single quad. - * `deferred.frag.glsl`: Deferred shading pass (for lighting calculations). - Reads from each of the `NUM_GBUFFERS` g-buffers. - * `post1.frag.glsl`: First post-processing pass. -* `lib/`: JavaScript libraries. -* `models/`: OBJ models for testing. Sponza is the default. -* `index.html`: Main HTML page. -* `server.bat` (Windows) or `server.py` (OS X/Linux): - Runs a web server at `localhost:10565`. - -### The Deferred Shading Pipeline - -See the comments in `deferredSetup.js`/`deferredRender.js` for low-level guidance. - -In order to enable and disable effects using the GUI, upload a vec4 uniform -where each component is an enable/disable flag. In JavaScript, the state of the -UI is accessible anywhere as `cfg.enableEffect0`, etc. - -**Pass 1:** Renders the scene geometry and its properties to the g-buffers. -* `copy.vert.glsl`, `copy.frag.glsl` -* The framebuffer object `pass_copy.fbo` must be bound during this pass. -* Renders into `pass_copy.depthTex` and `pass_copy.gbufs[i]`, which need to be - attached to the framebuffer. - -**Pass 2:** Performs lighting and shading into the color buffer. -* `quad.vert.glsl`, `deferred/blinnphong-pointlight.frag.glsl` -* Takes the g-buffers `pass_copy.gbufs`/`depthTex` as texture inputs to the - fragment shader, on uniforms `u_gbufs` and `u_depth`. -* `pass_deferred.fbo` must be bound. -* Renders into `pass_deferred.colorTex`. - -**Pass 3:** Performs post-processing. -* `quad.vert.glsl`, `post/one.frag.glsl` -* Takes `pass_BlinnPhong_PointLight.colorTex` as a texture input `u_color`. -* Renders directly to the screen if there are no additional passes. - -More passes may be added for additional effects (e.g. combining bloom with -motion blur) or optimizations (e.g. two-pass Gaussian blur for bloom) - -#### Debugging - -If there is a WebGL error, it will be displayed on the developer console and -the renderer will be aborted. To find out where the error came from, look at -the backtrace of the error (you may need to click the triangle to expand the -message). The line right below `wrapper @ webgl-debug.js` will point to the -WebGL call that failed. - -#### Changing the number of g-buffers - -Note that the g-buffers are just `vec4`s - you can put any values you want into -them. However, if you want to change the total number of g-buffers (add more -for additional effects or remove some for performance), you will need to make -changes in a number of places: - -* `deferredSetup.js`/`deferredRender.js`: search for `NUM_GBUFFERS` -* `copy.frag.glsl` -* `deferred.frag.glsl` -* `clear.frag.glsl` - - -## Resources - -* [1] Bloom: - [GPU Gems, Ch. 21](http://http.developer.nvidia.com/GPUGems/gpugems_ch21.html) -* [2] Screen-Space Ambient Occlusion: - [Floored Article](http://floored.com/blog/2013/ssao-screen-space-ambient-occlusion.html) -* [3] Post-Process Motion Blur: - [GPU Gems 3, Ch. 27](http://http.developer.nvidia.com/GPUGems3/gpugems3_ch27.html) - -**Also see:** The articles linked in the course schedule. - -### Profiling and debugging tools - -Built into Firefox: -* Canvas inspector -* Shader Editor -* JavaScript debugger and profiler - -Built into Chrome: -* JavaScript debugger and profiler - -Plug-ins: -* (Chrome/Firefox) [Web Tracing Framework](http://google.github.io/tracing-framework/) -* (Chrome) [Shader Editor](https://chrome.google.com/webstore/detail/shader-editor/ggeaidddejpbakgafapihjbgdlbbbpob) - - -Firefox can also be useful - it has a canvas inspector, WebGL profiling and a -shader editor built in. - - -## README - -Replace the contents of this README.md in a clear manner with the following: - -* A brief description of the project and the specific features you implemented. -* At least one screenshot of your project running. -* A 30+ second video of your project running showing all features. - [Open Broadcaster Software](http://obsproject.com) is recommended. - (Even though your demo can be seen online, using multiple render targets - means it won't run on many computers. A video will work everywhere.) -* A performance analysis (described below). - -### Performance Analysis - -See above. - -### GitHub Pages - -Since this assignment is in WebGL, you can make your project easily viewable by -taking advantage of GitHub's project pages feature. - -Once you are done with the assignment, create a new branch: - -`git branch gh-pages` - -Push the branch to GitHub: - -`git push origin gh-pages` - -Now, you can go to `.github.io/` to see your -renderer online from anywhere. Add this link to your README. - -## Submit - -1. Open a GitHub pull request so that we can see that you have finished. - The title should be "Submission: YOUR NAME". - * **ADDITIONALLY:** - In the body of the pull request, include a link to your repository. -2. Send an email to the TA (gmail: kainino1+cis565@) with: - * **Subject**: in the form of `[CIS565] Project N: PENNKEY`. - * Direct link to your pull request on GitHub. - * Estimate the amount of time you spent on the project. - * If there were any outstanding problems, briefly explain. - * **List the extra features you did.** - * Feedback on the project itself, if any. +

1.The number of the light increase the memory usead is increase, and the FPS is decrease.

+

In the bloom effect, I choose 5*5 simples, int the toon I only calculate the left and top three samples, but their performace do not make much difference. However in the bloom effect, I devide Gaussian matrix into two passes, x and y pass. I think that's why it is a little faster. I think I should change the toon into x y pass to get a more accurate result.

+Increasing the number of the models, makes the program much slower. +

+

these are the g-buffers improvment I made. First only disable the buffer do not make much difference. +

note: M1: pack the specular parameter into posision.w

+

M2:apply normal map before

+

M3:if I do not use the specular parameter in g-buffer and take the color value apart and reduce the number of g-buffer to 2.

+

Since I have to use the specular component, so I use the 3 buffers in the end. But reducing the number of g-buffers accelerate the program dramatically.

+

+

+

The debug view of the original bounding box

+

+

The debug view of the current bounding box. I calculate is as a "box" not a plane so the length of the box maybe bigger

+

+ +When calculating the boundingbox, I was plan to buil a box with 6 point and apply transform an projection matrix on it and it is very slow so I did not use that method. -### Third-Party Code Policy -* Use of any third-party code must be approved by asking on our mailing list. -* 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 path 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, at minimum, - result in you receiving an F for the semester. diff --git a/glsl/clear.frag.glsl b/glsl/clear.frag.glsl index b4e4ff3..53d8f4c 100644 --- a/glsl/clear.frag.glsl +++ b/glsl/clear.frag.glsl @@ -3,7 +3,7 @@ precision highp float; precision highp int; -#define NUM_GBUFFERS 4 +#define NUM_GBUFFERS 3 void main() { for (int i = 0; i < NUM_GBUFFERS; i++) { diff --git a/glsl/copy.frag.glsl b/glsl/copy.frag.glsl index 0f5f8f7..622a914 100644 --- a/glsl/copy.frag.glsl +++ b/glsl/copy.frag.glsl @@ -10,6 +10,25 @@ varying vec3 v_position; varying vec3 v_normal; varying vec2 v_uv; +uniform vec3 u_spec; + +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. + + vec3 normal=applyNormalMap(v_normal.xyz, texture2D(u_normap, v_uv).xyz); + + gl_FragData[0] = vec4(v_position,u_spec.x); + + vec4 colordata= texture2D(u_colmap, v_uv); + float t=colordata.x*255.0+colordata.y*10000.0; + gl_FragData[1] = vec4(normal.xyz,t); + gl_FragData[2] = colordata; + } diff --git a/glsl/copy.vert.glsl b/glsl/copy.vert.glsl index ec14e69..340f1c3 100644 --- a/glsl/copy.vert.glsl +++ b/glsl/copy.vert.glsl @@ -9,13 +9,17 @@ attribute vec3 a_position; attribute vec3 a_normal; attribute vec2 a_uv; + varying vec3 v_position; varying vec3 v_normal; varying vec2 v_uv; void main() { gl_Position = u_cameraMat * vec4(a_position, 1.0); - v_position = a_position; + + // v_position = vec3(a_position.xy,temp_pos.z);// a_position; + v_position = a_position; v_normal = a_normal; v_uv = a_uv; + } diff --git a/glsl/deferred/ambient.frag.glsl b/glsl/deferred/ambient.frag.glsl index 1fd4647..a83fe9a 100644 --- a/glsl/deferred/ambient.frag.glsl +++ b/glsl/deferred/ambient.frag.glsl @@ -3,7 +3,7 @@ precision highp float; precision highp int; -#define NUM_GBUFFERS 4 +#define NUM_GBUFFERS 3 uniform sampler2D u_gbufs[NUM_GBUFFERS]; uniform sampler2D u_depth; @@ -11,17 +11,15 @@ uniform sampler2D u_depth; varying vec2 v_uv; 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); + + vec4 gb2 = texture2D(u_gbufs[2], v_uv);//colormap 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(gb2.xyz*0.2, 1.0); // ambient:0.2,diffuse:0.3,specular:0.6 - gl_FragColor = vec4(0.1, 0.1, 0.1, 1); // TODO: replace this -} + } diff --git a/glsl/deferred/blinnphong-pointlight.frag.glsl b/glsl/deferred/blinnphong-pointlight.frag.glsl index b24a54a..285752a 100644 --- a/glsl/deferred/blinnphong-pointlight.frag.glsl +++ b/glsl/deferred/blinnphong-pointlight.frag.glsl @@ -2,38 +2,77 @@ precision highp float; precision highp int; -#define NUM_GBUFFERS 4 +#define NUM_GBUFFERS 3 uniform vec3 u_lightCol; uniform vec3 u_lightPos; uniform float u_lightRad; +uniform vec3 u_cameraPos; uniform sampler2D u_gbufs[NUM_GBUFFERS]; uniform sampler2D u_depth; +uniform int u_toon; +//uniform int u_bloom; varying vec2 v_uv; +const vec3 offset = vec3( 0.0, 2.0, 4.0); +const float width=800.0; +const float height=600.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; +const vec3 offset_g = vec3( 0.0, 1.0, 2.0);//35,21,7,1 :sum:126 +const vec3 weight= vec3(0.48, 0.31, 0.17); //guess weight: 0.2778, 0.1667, 0.0556: to make it brighter it should be bigger than 1 + +float _clampf(float t) +{ +if(t>1.0)t=1.0; +if(t<0.0)t=0.0; +return t; } 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 nothing was rendered to this pixel, set alpha to 0 so that the - // postprocessing step can render the sky color. + if (depth == 1.0) { gl_FragColor = vec4(0, 0, 0, 0); return; } - gl_FragColor = vec4(0, 0, 1, 1); // TODO: perform lighting calculations -} + //vec3 std_normal=applyNormalMap(gb1.xyz, gb3.xyz); + vec3 std_normal=gb1.xyz; + + vec3 position=gb0.xyz; + //vec3 position=vec3(gb0.xy,depth); + vec3 lightray = normalize(u_lightPos-position); + + vec3 basec=gb2.xyz; + float dis=length(u_lightPos-position); + vec3 eyeray =normalize(u_cameraPos-position); + vec3 H=normalize(lightray+ eyeray); + float attenuation = max(0.0, u_lightRad - dis); + vec3 light; + float diffuse= _clampf(dot(lightray,std_normal)); + float specular= _clampf(pow(max(0.0, dot(lightray,H)), gb0.w)); + //https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Toon_Shading + if(u_toon>0) + {//ramp + float a=0.2; + float b=0.5; + float c=0.9; + float d=1.0; + + if(diffuse0.5)gl_FragColor=vec4(1.0,0.0,0.0,1.0); + //else gl_FragColor=vec4(0.0,1.0,0.0,1.0); +} \ No newline at end of file diff --git a/glsl/deferred/bloom_h.frag.glsl b/glsl/deferred/bloom_h.frag.glsl new file mode 100644 index 0000000..88667e5 --- /dev/null +++ b/glsl/deferred/bloom_h.frag.glsl @@ -0,0 +1,37 @@ +#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); + +const vec3 offset = vec3( 0.0, 1.0, 2.0);//35,21,7,1 :sum:126 +const vec3 weight= vec3(0.48, 0.31, 0.17); //guess weight: 0.2778, 0.1667, 0.0556: to make it brighter it should be bigger than 1 +const float width=800.0; +const float height=600.0; +const float sp=0.20; +void main() { + vec4 color = texture2D(u_color, v_uv);//(0,1) + + if (color.a == 0.0) { + gl_FragColor = SKY_COLOR; + return; + } + if(color.x>sp||color.y>sp||color.z>sp){ + vec4 FragmentColor = texture2D( u_color, vec2(v_uv) ) * weight.x; + + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(0.0,offset.y) /height )*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(0.0,offset.y) /height )*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(0.0,offset.z) /height )*weight.z; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(0.0,offset.z) /height )*weight.z; + gl_FragColor = FragmentColor; + } + else + gl_FragColor=vec4(color.xyz,1.0); + + + +} \ No newline at end of file diff --git a/glsl/deferred/bloom_w.frag.glsl b/glsl/deferred/bloom_w.frag.glsl new file mode 100644 index 0000000..e4433d0 --- /dev/null +++ b/glsl/deferred/bloom_w.frag.glsl @@ -0,0 +1,36 @@ +#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); + +const vec3 offset = vec3( 0.0, 1.0, 2.0);//35,21,7,1 :sum:126 +const vec3 weight= vec3(0.48, 0.31, 0.17); +const float width=800.0; +const float height=600.0; +const float sp=0.20; +void main() { + vec4 color = texture2D(u_color, v_uv); + if (color.a == 0.0) { + gl_FragColor = SKY_COLOR; + return; + } + if(color.x>sp||color.y>sp||color.z>sp){ + vec4 FragmentColor = texture2D( u_color, vec2(v_uv) ) * weight.x; + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(offset.y,0.0 )/width )*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(offset.y,0.0 )/width )*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(offset.z,0.0 )/width )*weight.z; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(offset.z,0.0 )/width )*weight.z; + + + gl_FragColor = FragmentColor; + } + else { + gl_FragColor=vec4(color.xyz,1.0); + } + +} diff --git a/glsl/deferred/debug.frag.glsl b/glsl/deferred/debug.frag.glsl index d05638c..0f9d4b9 100644 --- a/glsl/deferred/debug.frag.glsl +++ b/glsl/deferred/debug.frag.glsl @@ -2,7 +2,7 @@ precision highp float; precision highp int; -#define NUM_GBUFFERS 4 +#define NUM_GBUFFERS 5 uniform int u_debug; uniform sampler2D u_gbufs[NUM_GBUFFERS]; @@ -27,12 +27,18 @@ void main() { 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 - vec3 pos; - vec3 geomnor; - vec3 colmap; - vec3 normap; - vec3 nor; + vec3 pos = gb0.xyz; // World-space position + // + vec3 geomnor=gb1.xyz; // Normals of the geometry as defined, without normal mapping + vec3 colmap=gb2.xyz; // The color map - unlit "albedo" (surface color) + + vec3 normap=gb3.xyz; // The raw normal map (normals relative to the surface they're on) + + //vec4 temp= vec4(applyNormalMap(geomnor, normap),1.0); + // The true normals as we want to light them - with the normal map applied to the geometry normals (applyNormalMap ) + vec3 nor = applyNormalMap(geomnor, normap); + if (u_debug == 0) { gl_FragColor = vec4(vec3(depth), 1.0); } else if (u_debug == 1) { @@ -46,6 +52,6 @@ void main() { } else if (u_debug == 5) { gl_FragColor = vec4(abs(nor), 1.0); } else { - gl_FragColor = vec4(1, 0, 1, 1); + gl_FragColor = SKY_COLOR; } } diff --git a/glsl/deferred/singleBloom.frag.glsl b/glsl/deferred/singleBloom.frag.glsl new file mode 100644 index 0000000..8266c11 --- /dev/null +++ b/glsl/deferred/singleBloom.frag.glsl @@ -0,0 +1,39 @@ +#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); + +const vec3 offset = vec3( 0.0, 1.0, 2.0);//35,21,7,1 :sum:126 +const vec3 weight= vec3(0.48, 0.31, 0.17); +const float width=800.0; +const float height=600.0; +const float sp=0.20; +void main() { + vec4 color = texture2D(u_color, v_uv); + if (color.a == 0.0) { + gl_FragColor = SKY_COLOR; + return; + } + if(color.x>sp||color.y>sp||color.z>sp){ + vec4 FragmentColor = texture2D( u_color, vec2(v_uv)) * weight.x; + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(offset.y,0.0 )/width )*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(offset.y,0.0 )/width )*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(offset.z,0.0 )/width )*weight.z; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(offset.z,0.0 )/width )*weight.z; + + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(0.0, offset.y )/height)*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(0.0, offset.y )/height)*weight.y; + FragmentColor += texture2D( u_color, vec2(v_uv)+ vec2(0.0, offset.z )/height)*weight.z; + FragmentColor += texture2D( u_color, vec2(v_uv)- vec2(0.0, offset.z )/height)*weight.z; + gl_FragColor = FragmentColor; + } + else { + gl_FragColor=vec4(color.xyz,1.0); + } + +} diff --git a/glsl/deferred/toon.frag.glsl b/glsl/deferred/toon.frag.glsl new file mode 100644 index 0000000..36601a5 --- /dev/null +++ b/glsl/deferred/toon.frag.glsl @@ -0,0 +1,30 @@ +#version 100 +precision highp float; +precision highp int; + +#define NUM_GBUFFERS 4 + +uniform sampler2D u_depth; +uniform sampler2D u_color; +varying vec2 v_uv; + +const vec3 offset = vec3( 0.0, 2.0, 4.0); +const float width=800.0; +const float height=600.0; + +void main() { + + float depth = texture2D(u_depth, v_uv).x; + vec4 color=texture2D(u_color, vec2(v_uv)); + //https://www.shadertoy.com/view/4slSWf + float Fc= texture2D( u_depth, vec2(v_uv)+ vec2(0.0,offset.x) /height ).x; + float Fc1 = texture2D( u_depth, vec2(v_uv)+ vec2(0.0,offset.z) /height ).x; + float Fc2 = texture2D( u_depth, vec2(v_uv)+ vec2(offset.z,0.0) /width ).x; + + float e=max(abs(Fc-Fc1),abs(Fc-Fc2)); + + + if(e>0.05)gl_FragColor=vec4(0.1,0.1,0.1,1.0);//draw outline + else gl_FragColor = vec4(0.1,0.1,0.1,0.3); + //gl_FragColor=vec4(0.0,0.0,0.0,1.0); +} \ No newline at end of file diff --git a/glsl/red.frag.glsl b/glsl/red.frag.glsl index f8ef1ec..e41993b 100644 --- a/glsl/red.frag.glsl +++ b/glsl/red.frag.glsl @@ -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.1); } diff --git a/images.jpg b/images.jpg new file mode 100644 index 0000000..d451f92 Binary files /dev/null and b/images.jpg differ diff --git a/img/aabb.png b/img/aabb.png new file mode 100644 index 0000000..e002c3d Binary files /dev/null and b/img/aabb.png differ diff --git a/img/blood.png b/img/blood.png new file mode 100644 index 0000000..59e84a4 Binary files /dev/null and b/img/blood.png differ diff --git a/img/bloom.png b/img/bloom.png new file mode 100644 index 0000000..acfe7a5 Binary files /dev/null and b/img/bloom.png differ diff --git a/img/chart1.png b/img/chart1.png new file mode 100644 index 0000000..03a1284 Binary files /dev/null and b/img/chart1.png differ diff --git a/img/chart2.png b/img/chart2.png new file mode 100644 index 0000000..71e103f Binary files /dev/null and b/img/chart2.png differ diff --git a/img/chart3.png b/img/chart3.png new file mode 100644 index 0000000..a27e30c Binary files /dev/null and b/img/chart3.png differ diff --git a/img/chart4.png b/img/chart4.png new file mode 100644 index 0000000..10206e7 Binary files /dev/null and b/img/chart4.png differ diff --git a/img/creepy.png b/img/creepy.png new file mode 100644 index 0000000..ce38059 Binary files /dev/null and b/img/creepy.png differ diff --git a/img/debug.png b/img/debug.png new file mode 100644 index 0000000..638910b Binary files /dev/null and b/img/debug.png differ diff --git a/img/debug2.png b/img/debug2.png new file mode 100644 index 0000000..7c59ea0 Binary files /dev/null and b/img/debug2.png differ diff --git a/img/helloween.png b/img/helloween.png new file mode 100644 index 0000000..9b23b8c Binary files /dev/null and b/img/helloween.png differ diff --git a/img/noaabb.png b/img/noaabb.png new file mode 100644 index 0000000..de58ebf Binary files /dev/null and b/img/noaabb.png differ diff --git a/img/thumb.png b/img/thumb.png index 9ec8ed0..ef348b7 100644 Binary files a/img/thumb.png and b/img/thumb.png differ diff --git a/img/toon1.png b/img/toon1.png new file mode 100644 index 0000000..88929b4 Binary files /dev/null and b/img/toon1.png differ diff --git a/img/toon2.png b/img/toon2.png new file mode 100644 index 0000000..b7d3142 Binary files /dev/null and b/img/toon2.png differ diff --git a/img/video.png b/img/video.png index 9ec8ed0..4cb9143 100644 Binary files a/img/video.png and b/img/video.png differ diff --git a/index.html b/index.html index 4a0ec13..9f8639c 100644 --- a/index.html +++ b/index.html @@ -78,10 +78,19 @@ width: 100%; height: 100%; } + #msgbox { + font-family: sans-serif; + color: white; + height: 1.4em; + position: fixed; + bottom: 2em; + left: 0; + } +

DEBUG MODE! (Disable before measuring performance.) diff --git a/js/deferredRender.js b/js/deferredRender.js index 3d19a30..13b0010 100644 --- a/js/deferredRender.js +++ b/js/deferredRender.js @@ -10,7 +10,10 @@ !R.prog_Ambient || !R.prog_BlinnPhong_PointLight || !R.prog_Debug || - !R.progPost1)) { + !R.progPost1 || + !R.prog_bloom_w|| + !R.prog_toon + )) { console.log('waiting for programs to load...'); return; } @@ -20,33 +23,35 @@ // OPTIONAL TODO: Edit if you want to change how lights move var mn = R.light_min[1]; var mx = R.light_max[1]; + R.lights[i].pos[1] = (R.lights[i].pos[1] + R.light_dt - mn + mx) % mx + mn; + } // Execute deferred shading pipeline - // CHECKITOUT: START HERE! You can even uncomment this: //debugger; - - { // TODO: this block should be removed after testing renderFullScreenQuad - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - // TODO: Implement/test renderFullScreenQuad first - renderFullScreenQuad(R.progRed); - return; - } - R.pass_copy.render(state); if (cfg && cfg.debugView >= 0) { // Do a debug render instead of a regular render // Don't do any post-processing in debug mode R.pass_debug.render(state); - } else { + } + + else if(cfg.debugView<0 && cfg.TwoPassBloom) { + // R.light_pass.render(state); + R.pass_deferred.render(state); + R.pass_bloom_w.render(state); + R.pass_bloom_h.render(state); + } + + else { // * Deferred pass and postprocessing pass(es) - // TODO: uncomment these - //R.pass_deferred.render(state); - //R.pass_post1.render(state); + + R.pass_deferred.render(state); + R.pass_post1.render(state); // OPTIONAL TODO: call more postprocessing passes, if any } }; @@ -56,42 +61,36 @@ */ R.pass_copy.render = function(state) { // * Bind the framebuffer R.pass_copy.fbo - // TODO: ^ - + gl.bindFramebuffer(gl.FRAMEBUFFER,R.pass_copy.fbo); // * Clear screen using R.progClear - TODO: renderFullScreenQuad(R.progClear); + renderFullScreenQuad(R.progClear); // * Clear depth buffer to value 1.0 using gl.clearDepth and gl.clear - // TODO: ^ - // TODO: ^ + gl.clearDepth(1.0); + gl.clear(gl.DEPTH_BUFFER_BIT); // * "Use" the program R.progCopy.prog - // TODO: ^ - // TODO: Write glsl/copy.frag.glsl - + gl.useProgram(R.progCopy.prog); var m = state.cameraMat.elements; // * Upload the camera matrix m to the uniform R.progCopy.u_cameraMat // using gl.uniformMatrix4fv - // TODO: ^ - - // * Draw the scene + gl.uniformMatrix4fv(R.progCopy.u_cameraMat,false,m); + gl.uniform3f(R.progCopy.u_spec, cfg.specular,0.0,0.0); drawScene(state); }; var drawScene = function(state) { for (var i = 0; i < state.models.length; i++) { var m = state.models[i]; - // If you want to render one model many times, note: // readyModelForDraw only needs to be called once. readyModelForDraw(R.progCopy, m); - drawReadyModel(m); } }; R.pass_debug.render = function(state) { // * Unbind any framebuffer, so we can write to the screen - gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); // * Bind/setup the debug "lighting" pass // * Tell shader which debug view to use @@ -113,34 +112,69 @@ gl.clearColor(0.0, 0.0, 0.0, 0.0); gl.clearDepth(1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - // * _ADD_ together the result of each lighting pass - - // Enable blending and use gl.blendFunc to blend with: - // color = 1 * src_color + 1 * dst_color - // TODO: ^ - + gl.enable(gl.BLEND); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc(gl.ONE,gl.ONE); + // * Bind/setup the ambient pass, and render using fullscreen quad + bindTexturesForLightPass(R.prog_Ambient); renderFullScreenQuad(R.prog_Ambient); - - // * Bind/setup the Blinn-Phong pass, and render using fullscreen quad + bindTexturesForLightPass(R.prog_BlinnPhong_PointLight); - - // TODO: add a loop here, over the values in R.lights, which sets the - // uniforms R.prog_BlinnPhong_PointLight.u_lightPos/Col/Rad etc., - // then does renderFullScreenQuad(R.prog_BlinnPhong_PointLight). - - // TODO: In the lighting loop, use the scissor test optimization - // Enable gl.SCISSOR_TEST, render all lights, then disable it. - // - // getScissorForLight returns null if the scissor is off the screen. - // Otherwise, it returns an array [xmin, ymin, width, height]. - // - // var sc = getScissorForLight(state.viewMat, state.projMat, light); - + gl.enable(gl.SCISSOR_TEST); + //!!!!!note: 012!!!xyznot work!!!!I hate it + for (var i = 0; i < R.lights.length; i++) {//R.lights.length + if(cfg.AABBtest){ + var sc = getAABBForLight(state.viewMat, state.projMat, R.lights[i]); + } + else sc = getScissorForLight(state.viewMat, state.projMat, R.lights[i]); + + if(sc!=null){ + gl.scissor(sc[0], sc[1], sc[2], sc[3]); + if(!cfg.debugScissor){ + gl.uniform3f(R.prog_BlinnPhong_PointLight.u_lightPos, R.lights[i].pos[0],R.lights[i].pos[1],R.lights[i].pos[2]); + gl.uniform3f(R.prog_BlinnPhong_PointLight.u_lightCol, R.lights[i].col[0],R.lights[i].col[1],R.lights[i].col[2]); + gl.uniform1f(R.prog_BlinnPhong_PointLight.u_lightRad, R.lights[i].rad); + gl.uniform3f(R.prog_BlinnPhong_PointLight.u_cameraPos, state.cameraPos.x,state.cameraPos.y,state.cameraPos.z); + if(cfg.toon) + { + gl.uniform1i(R.prog_BlinnPhong_PointLight.u_toon, 1); + } + else + { + gl.uniform1i(R.prog_BlinnPhong_PointLight.u_toon, -1); + } + + renderFullScreenQuad(R.prog_BlinnPhong_PointLight); + } + else + { + //additive blend + gl.blendFunc(gl.SRC_ALPHA, gl.DST_ALPHA); + renderFullScreenQuad(R.progRed); + } + } + } // Disable blending so that it doesn't affect other code - gl.disable(gl.BLEND); + gl.disable(gl.SCISSOR_TEST); + // gl.disable(gl.BLEND); + if(cfg.toon) + { + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + + gl.useProgram(R.prog_toon.prog); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, R.pass_copy.depthTex); + gl.uniform1i(R.prog_toon.u_depth, 0); + + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex); + gl.uniform1i(R.prog_toon.u_color, 0); + + renderFullScreenQuad(R.prog_toon); + } + gl.disable(gl.BLEND); }; var bindTexturesForLightPass = function(prog) { @@ -157,60 +191,71 @@ gl.bindTexture(gl.TEXTURE_2D, R.pass_copy.depthTex); gl.uniform1i(prog.u_depth, R.NUM_GBUFFERS); }; - - /** - * 'post1' pass: Perform (first) pass of post-processing - */ + //bloom reference: http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ + + R.pass_bloom_w.render=function(state) + { + gl.bindFramebuffer(gl.FRAMEBUFFER, R.pass_bloom_w.fbo ); + gl.clearDepth(1.0); + gl.clear(gl.DEPTH_BUFFER_BIT); + gl.useProgram(R.prog_bloom_w.prog); + gl.activeTexture(gl.TEXTURE0); + + gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex); + // } + gl.uniform1i(R.prog_bloom_w.u_color, 0); + + renderFullScreenQuad(R.prog_bloom_w); + }; + R.pass_bloom_h.render=function(state) + { + gl.bindFramebuffer(gl.FRAMEBUFFER, null ); + gl.clearDepth(1.0); + gl.clear(gl.DEPTH_BUFFER_BIT); + + gl.useProgram(R.prog_bloom_h.prog); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex); + gl.uniform1i(R.prog_bloom_h.u_color, 0); + renderFullScreenQuad(R.prog_bloom_h); + + }; R.pass_post1.render = function(state) { // * Unbind any existing framebuffer (if there are no more passes) - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - + gl.bindFramebuffer(gl.FRAMEBUFFER, null); // * Clear the framebuffer depth to 1.0 gl.clearDepth(1.0); gl.clear(gl.DEPTH_BUFFER_BIT); - // * Bind the postprocessing shader program gl.useProgram(R.progPost1.prog); - // * Bind the deferred pass's color output as a texture input // Set gl.TEXTURE0 as the gl.activeTexture unit - // TODO: ^ + gl.activeTexture(gl.TEXTURE0); // Bind the TEXTURE_2D, R.pass_deferred.colorTex to the active texture unit - // TODO: ^ + gl.bindTexture(gl.TEXTURE_2D, R.pass_deferred.colorTex); + // Configure the R.progPost1.u_color uniform to point at texture unit 0 gl.uniform1i(R.progPost1.u_color, 0); - // * Render a fullscreen quad to perform shading on renderFullScreenQuad(R.progPost1); }; var renderFullScreenQuad = (function() { - // The variables in this function are private to the implementation of - // renderFullScreenQuad. They work like static local variables in C++. - - // Create an array of floats, where each set of 3 is a vertex position. - // You can render in normalized device coordinates (NDC) so that the - // vertex shader doesn't have to do any transformation; draw two - // triangles which cover the screen over x = -1..1 and y = -1..1. - // This array is set up to use gl.drawArrays with gl.TRIANGLE_STRIP. var positions = new Float32Array([ -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 0.0 + ]); var vbo = null; var init = function() { - // Create a new buffer with gl.createBuffer, and save it as vbo. - // TODO: ^ + vbo=gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER,vbo); + gl.bufferData(gl.ARRAY_BUFFER,positions,gl.STATIC_DRAW); - // Bind the VBO as the gl.ARRAY_BUFFER - // TODO: ^ - // Upload the positions array to the currently-bound array buffer - // using gl.bufferData in static draw mode. - // TODO: ^ }; return function(prog) { @@ -218,23 +263,19 @@ // If the vbo hasn't been initialized, initialize it. init(); } - // Bind the program to use to draw the quad - gl.useProgram(prog.prog); - + gl.useProgram(prog.prog); // Bind the VBO as the gl.ARRAY_BUFFER - // TODO: ^ - // Enable the bound buffer as the vertex attrib array for - // prog.a_position, using gl.enableVertexAttribArray - // TODO: ^ - // Use gl.vertexAttribPointer to tell WebGL the type/layout of the buffer - // TODO: ^ - // Use gl.drawArrays (or gl.drawElements) to draw your quad. - // TODO: ^ + gl.bindBuffer(gl.ARRAY_BUFFER,vbo); + gl.enableVertexAttribArray(prog.a_position); + // Use gl.vertexAttribPointer to tell WebGL the type/layout of the buffer + gl.vertexAttribPointer(prog.a_position, 3, gl.FLOAT, false, 0, 0); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // Unbind the array buffer. gl.bindBuffer(gl.ARRAY_BUFFER, null); }; })(); + })(); diff --git a/js/deferredSetup.js b/js/deferredSetup.js index ca6baec..67bc2d7 100644 --- a/js/deferredSetup.js +++ b/js/deferredSetup.js @@ -6,9 +6,15 @@ R.pass_debug = {}; R.pass_deferred = {}; R.pass_post1 = {}; + //********** + R.pass_bloom_w = {}; + R.pass_bloom_h = {}; + R.light_pass ={}; + R.pass_wall={}; + //********** R.lights = []; - R.NUM_GBUFFERS = 4; + R.NUM_GBUFFERS = 3; /** * Set up the deferred pipeline framebuffer objects and textures. @@ -18,11 +24,16 @@ loadAllShaderPrograms(); R.pass_copy.setup(); R.pass_deferred.setup(); + //******bloom.fbo******// + R.pass_bloom_w.setup(); + R.light_pass.setup(); + //************* + console.log('seted up.'); }; // TODO: Edit if you want to change the light initial positions - R.light_min = [-6, 0, -14]; - R.light_max = [6, 18, 14]; + R.light_min = [-14, 0, -6]; + R.light_max = [14, 18, 6]; R.light_dt = -0.03; R.LIGHT_RADIUS = 4.0; R.NUM_LIGHTS = 20; // TODO: test with MORE lights! @@ -34,14 +45,14 @@ for (var i = 0; i < 3; i++) { var mn = R.light_min[i]; var mx = R.light_max[i]; - r = Math.random() * (mx - mn) + mn; + r[i] = Math.random() * (mx - mn) + mn; } return r; }; for (var i = 0; i < R.NUM_LIGHTS; i++) { R.lights.push({ - pos: [posfn(), posfn(), posfn()], + pos: posfn(), col: [ 1 + Math.random(), 1 + Math.random(), @@ -57,6 +68,7 @@ R.pass_copy.setup = function() { // * Create the FBO R.pass_copy.fbo = gl.createFramebuffer(); + // * Create, bind, and store a depth target texture for the FBO R.pass_copy.depthTex = createAndBindDepthTargetTexture(R.pass_copy.fbo); @@ -75,23 +87,46 @@ // * Tell the WEBGL_draw_buffers extension which FBO attachments are // being used. (This extension allows for multiple render targets.) gl_draw_buffers.drawBuffersWEBGL(attachments); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); }; /** * Create/configure framebuffer between "deferred" and "post1" stages */ + R.pass_bloom_w.setup = function() { + + R.pass_bloom_w.fbo = gl.createFramebuffer(); + R.pass_bloom_w.colorTex = createAndBindColorTargetTexture( + R.pass_bloom_w.fbo, gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL); + abortIfFramebufferIncomplete(R.pass_bloom_w.fbo); + gl_draw_buffers.drawBuffersWEBGL([gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL]); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + }; + R.light_pass.setup = function() { + + R.light_pass.fbo = gl.createFramebuffer(); + R.light_pass.colorTex = createAndBindColorTargetTexture( + R.light_pass.fbo, gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL); + abortIfFramebufferIncomplete(R.light_pass.fbo); + gl_draw_buffers.drawBuffersWEBGL([gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL]); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + }; R.pass_deferred.setup = function() { // * Create the FBO R.pass_deferred.fbo = gl.createFramebuffer(); + // * Create, bind, and store a single color target texture for the FBO R.pass_deferred.colorTex = createAndBindColorTargetTexture( - R.pass_deferred.fbo, gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL); - + R.pass_deferred.fbo, gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL); + // * Check for framebuffer errors abortIfFramebufferIncomplete(R.pass_deferred.fbo); // * Tell the WEBGL_draw_buffers extension which FBO attachments are // being used. (This extension allows for multiple render targets.) gl_draw_buffers.drawBuffersWEBGL([gl_draw_buffers.COLOR_ATTACHMENT0_WEBGL]); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); }; /** @@ -107,10 +142,12 @@ p.u_cameraMat = gl.getUniformLocation(prog, 'u_cameraMat'); p.u_colmap = gl.getUniformLocation(prog, 'u_colmap'); p.u_normap = gl.getUniformLocation(prog, 'u_normap'); + p.a_position = gl.getAttribLocation(prog, 'a_position'); p.a_normal = gl.getAttribLocation(prog, 'a_normal'); p.a_uv = gl.getAttribLocation(prog, 'a_uv'); - + p.u_spec =gl.getUniformLocation(prog, 'u_spec'); + //gl.uniform3f(R.progCopy.a_spec, cfg.specular,0.0,0.0); // Save the object into this variable for access later R.progCopy = p; }); @@ -137,9 +174,27 @@ p.u_lightPos = gl.getUniformLocation(p.prog, 'u_lightPos'); p.u_lightCol = gl.getUniformLocation(p.prog, 'u_lightCol'); p.u_lightRad = gl.getUniformLocation(p.prog, 'u_lightRad'); + p.u_cameraPos = gl.getUniformLocation(p.prog, 'u_cameraPos'); + p.u_toon= gl.getUniformLocation(p.prog, 'u_toon'); + R.prog_BlinnPhong_PointLight = p; }); - + loadDeferredProgram('singleBloom', function(p) { + p.u_color = gl.getUniformLocation(p.prog, 'u_color'); + R.prog_singleBloom = p; + }); + loadDeferredProgram('bloom_w', function(p) { + p.u_color = gl.getUniformLocation(p.prog, 'u_color'); + R.prog_bloom_w = p; + }); + loadDeferredProgram('bloom_h', function(p) { + p.u_color = gl.getUniformLocation(p.prog, 'u_color'); + R.prog_bloom_h = p; + }); + loadDeferredProgram('toon', function(p) { + p.u_color = gl.getUniformLocation(p.prog, 'u_color'); + R.prog_toon = p; + }); loadDeferredProgram('debug', function(p) { p.u_debug = gl.getUniformLocation(p.prog, 'u_debug'); // Save the object into this variable for access later diff --git a/js/framework.js b/js/framework.js index a0653a5..0837180 100644 --- a/js/framework.js +++ b/js/framework.js @@ -17,6 +17,7 @@ var width, height; cameraMat: cameraMat, projMat: camera.projectionMatrix, viewMat: camera.matrixWorldInverse, + cameraPos: camera.position, models: models }); }; @@ -136,6 +137,19 @@ var width, height; models.push(m); }); }); + loadModel('models/cube.obj', function(o) { + scene.add(o); + uploadModel(o, function(m) { + // CHECKITOUT: load textures + loadTexture('models/sponza/color.jpg').then(function(tex) { + m.colmap = tex; + }); + loadTexture('models/sponza/normal.png').then(function(tex) { + m.normap = tex; + }); + models.push(m); + }); + }); // Render once to get three.js to copy all of the model buffers resize(); diff --git a/js/ui.js b/js/ui.js index 05c1852..a5c288d 100644 --- a/js/ui.js +++ b/js/ui.js @@ -7,7 +7,10 @@ var cfg; // TODO: Define config fields and defaults here this.debugView = -1; this.debugScissor = false; - this.enableEffect0 = false; + this.specular =50; + this.TwoPassBloom = false; + this.toon = false; + this.AABBtest = false; }; var init = function() { @@ -27,7 +30,12 @@ var cfg; gui.add(cfg, 'debugScissor'); var eff0 = gui.addFolder('EFFECT NAME HERE'); - eff0.add(cfg, 'enableEffect0'); + eff0.add(cfg, 'toon'); + eff0.add(cfg, 'specular').min(0).max(60).step(1); + eff0.add(cfg, 'TwoPassBloom'); + eff0.add(cfg, 'AABBtest'); + + // TODO: add more effects toggles and parameters here }; diff --git a/js/util.js b/js/util.js index 762fb4a..3b36b69 100644 --- a/js/util.js +++ b/js/util.js @@ -130,7 +130,186 @@ window.readyModelForDraw = function(prog, m) { window.drawReadyModel = function(m) { gl.drawElements(gl.TRIANGLES, m.elemCount, gl.UNSIGNED_INT, 0); }; +window.getAABBForLight = (function() { + // Pre-allocate for performance - avoids additional allocation + var a = new THREE.Vector4(0, 0, 0, 0); + var b = new THREE.Vector4(0, 0, 0, 0); + var c = new THREE.Vector4(0, 0, 0, 0); + var d = new THREE.Vector4(0, 0, 0, 0); + var e = new THREE.Vector4(0, 0, 0, 0); + var f = new THREE.Vector4(0, 0, 0, 0); + var g = new THREE.Vector4(0, 0, 0, 0); + var h = new THREE.Vector4(0, 0, 0, 0); + var center = new THREE.Vector4(0, 0, 0, 0); + var minx=-1.0; + var miny=1.0; + var minpt = new THREE.Vector2(0, 0); + var maxpt = new THREE.Vector2(0, 0); + + var ltx = new THREE.Vector2(0, 0); + var lty = new THREE.Vector2(0, 0); + var ret = [0, 0, 0, 0]; + + return function(view, proj, l) { + // front bottom-left corner of sphere's bounding cube + /* + a.fromArray(l.pos); + a.w = 1; + a.applyMatrix4(view); + a.x += l.rad; + a.y += l.rad; + //a.z += l.rad; + a.applyMatrix4(proj); + a.divideScalar(a.w); + + b.fromArray(l.pos); + b.w = 1; + b.applyMatrix4(view); + b.x -= l.rad; + b.y += l.rad; + // b.z += l.rad; + b.applyMatrix4(proj); + b.divideScalar(b.w); + + c.fromArray(l.pos); + c.w = 1; + c.applyMatrix4(view); + c.x += l.rad; + c.y -= l.rad; + // c.z += l.rad; + c.applyMatrix4(proj); + c.divideScalar(c.w); + + d.fromArray(l.pos); + d.w = 1; + d.applyMatrix4(view); + d.x -= l.rad; + d.y -= l.rad; + // d.z += l.rad; + d.applyMatrix4(proj); + d.divideScalar(d.w); + + e.fromArray(l.pos); + e.w = 1; + e.applyMatrix4(view); + e.x += l.rad; + e.y += l.rad; + // e.z -= l.rad; + e.applyMatrix4(proj); + e.divideScalar(e.w); + + f.fromArray(l.pos); + f.w = 1; + f.applyMatrix4(view); + f.x -= l.rad; + f.y += l.rad; + // f.z -= l.rad; + // f.applyMatrix4(proj); + f.divideScalar(f.w); + + g.fromArray(l.pos); + g.w = 1; + // g.applyMatrix4(view); + g.x += l.rad; + g.y -= l.rad; + g.z -= l.rad; + // g.applyMatrix4(proj); + g.divideScalar(g.w); + + h.fromArray(l.pos); + h.w = 1; + // h.applyMatrix4(view); + h.x -= l.rad; + h.y -= l.rad; + h.z -= l.rad; + // h.applyMatrix4(proj); + h.divideScalar(h.w); +////////////////////////////////min////////////// + var m1x=Math.min(Math.min(Math.min(a.x,b.x),c.x),d.x); + var m2x=Math.min(Math.min(e.x,f.x),g.x); + var m3x=Math.min(m1x,m2x); + + var m1y=Math.min(Math.min(Math.min(a.y,b.y),c.y),d.y); + var m2y=Math.min(Math.min(e.y,f.y),g.y); + var m3y=Math.min(m1y,m2y); + + var m1z=Math.min(Math.min(Math.min(a.z,b.z),c.z),d.z); + var m2z=Math.min(Math.min(e.z,f.z),g.z); + var m3z=Math.min(m1z,m2z); + + var mint=Math.min(m3x,m3y); +///////////////////////////////max/////////////// + var a1x=Math.max(Math.max(Math.max(a.x,b.x),c.x),d.x); + var a2x=Math.max(Math.max(e.x,f.x),g.x); + var a3x=Math.max(a1x,a2x); + + var a1y=Math.max(Math.max(Math.max(a.y,b.y),c.y),d.y); + var a2y=Math.max(Math.max(e.y,f.y),g.y); + var a3y=Math.max(a1y,a2y); + + var maxt=Math.max(a3x,a3y); + /////////////////////////////////////////////////// + //--+d,+++a(-1,1); + minpt.set(Math.max(-1, mint.x), Math.max(-1, mint.y)); + maxpt.set(Math.min( 1, maxt.x), Math.min( 1, maxt.y)); + + if (maxpt.x < -1 || 1 < minpt.x || + maxpt.y < -1 || 1 < minpt.y) { + return null; + } + + minpt.addScalar(1.0); minpt.multiplyScalar(0.5); + maxpt.addScalar(1.0); maxpt.multiplyScalar(0.5); + //0-2//// + + ret[0] = Math.round(minpt*width); + ret[1] = Math.round(maxpt*height); + ret[2] = Math.round(width * (maxpt.x - minpt.x)); + ret[3] = Math.round(height* (maxpt.x - minpt.x)); + + ret[0] = Math.round(width * minpt.x); + ret[1] = Math.round(height * minpt.y); + ret[2] = Math.round(width/2.0 ); + ret[3] = Math.round(height /2.0); + + return ret;*/ + a.fromArray(l.pos); + a.w = 1; + a.applyMatrix4(view); + a.x -= l.rad; + a.y -= l.rad; + a.z -= l.rad; + a.applyMatrix4(proj); + a.divideScalar(a.w); + + // front bottom-left corner of sphere's bounding cube + b.fromArray(l.pos); + b.w = 1; + b.applyMatrix4(view); + b.x += l.rad; + b.y += l.rad; + b.z += l.rad; + b.applyMatrix4(proj); + b.divideScalar(b.w); + + minpt.set(Math.max(-1, a.x), Math.max(-1, a.y)); + maxpt.set(Math.min( 1, b.x), Math.min( 1, b.y)); + + if (maxpt.x < -1 || 1 < minpt.x || + maxpt.y < -1 || 1 < minpt.y) { + return null; + } + minpt.addScalar(1.0); minpt.multiplyScalar(0.5); + maxpt.addScalar(1.0); maxpt.multiplyScalar(0.5); + + ret[0] = Math.round(width * minpt.x); + ret[1] = Math.round(height * minpt.y); + ret[2] = Math.round(width * (maxpt.x - minpt.x)); + ret[3] = Math.round(height * (maxpt.y - minpt.y)); + return ret; + }; +})(); window.getScissorForLight = (function() { // Pre-allocate for performance - avoids additional allocation var a = new THREE.Vector4(0, 0, 0, 0); diff --git a/models/cow.png b/models/cow.png new file mode 100644 index 0000000..c384f17 Binary files /dev/null and b/models/cow.png differ diff --git a/models/cown.png b/models/cown.png new file mode 100644 index 0000000..d0d45dc Binary files /dev/null and b/models/cown.png differ diff --git a/models/gcow.jpg b/models/gcow.jpg new file mode 100644 index 0000000..fd557fb Binary files /dev/null and b/models/gcow.jpg differ