diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index b512c09..22e6580 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +.idea \ No newline at end of file diff --git a/INSTRUCTION.md b/INSTRUCTION.md old mode 100644 new mode 100755 index 8f4404e..f7d0000 --- a/INSTRUCTION.md +++ b/INSTRUCTION.md @@ -1,4 +1,4 @@ -WebGL Clustered Deferred and Forward+ Shading - Instructions +WebGL Clustered and Forward+ Shading - Instructions ========================================================== **This is due Thursday 10/26** @@ -27,19 +27,19 @@ In this project, you are given code for: - Loading glTF models - Camera control - Simple forward renderer -- Partial implementation and setup for Clustered Deferred and Forward+ shading +- Partial implementation and setup for Clustered and Forward+ shading - Many helpful helpers ## Required Tasks **Before doing performance analysis**, you must disable debug mode by changing `DEBUG` to false in `src/init.js`. Keep it enabled when developing - it helps find WebGL errors *much* more easily. -**Clustered Forward+** +**Forward+** - Build a data structure to keep track of how many lights are in each cluster and what their indices are - Render the scene using only the lights that overlap a given cluster -**Clustered Deferred** - - Reuse clustering logic from Clustered Forward+ +**Clustered** + - Reuse clustering logic from Forward+ - Store vertex attributes in g-buffer - Read g-buffer in a shader to produce final output @@ -63,7 +63,7 @@ In this project, you are given code for: ## Performance & Analysis -Compare your implementations of Clustered Forward+ and Clustered Deferred shading and analyze their differences. +Compare your implementations of Forward+ and Clustered shading and analyze their differences. - Is one of them faster? - Is one of them better at certain types of workloads? - What are the benefits and tradeoffs of using one over the other? @@ -95,7 +95,7 @@ For each performance feature (required or extra), please provide: Initialization happens in `src/init.js`. You don't need to worry about this; it is mostly initializing the gl context, debug modes, extensions, etc. -`src/main.js` is configuration for the renderers. It sets up the gui for switching renderers and initializes the scene and render loop. The only important thing here are the arguments for `ClusteredForwardPlusRenderer` and `ClusteredDeferredRenderer`. These constructors take the number of x, y, and z slices to split the frustum into. +`src/main.js` is configuration for the renderers. It sets up the gui for switching renderers and initializes the scene and render loop. The only important thing here are the arguments for `ForwardPlusRenderer` and `ClusteredRenderer`. These constructors take the number of x, y, and z slices to split the frustum into. `src/scene.js` handles loading a .gltf scene and initializes the lights. Here, you can modify the number of lights, their positions, and how they move around. Also, take a look at the `draw` function. This handles binding the vertex attributes, which are hardcoded to `a_position`, `a_normal`, and `a_uv`, as well as the color and normal maps to targets `gl.TEXTURE0` and `gl.TEXTURE1`. @@ -115,17 +115,17 @@ Now go look inside `src/shaders/forward.frag.glsl.js`. Here, there is a simple l **Getting Started** Here's a few tips to get you started. -1. Complete `updateClusters` in `src/renderers/clustered.js`. This should update the cluster `TextureBuffer` with a mapping from cluster index to light count and light list (indices). +1. Complete `updateClusters` in `src/renderers/base.js`. This should update the cluster `TextureBuffer` with a mapping from cluster index to light count and light list (indices). -2. Update `src/shaders/clusteredForward.frag.glsl.js` to +2. Update `src/shaders/forwardPlus.frag.glsl.js` to - Determine the cluster for a fragment - Read in the lights in that cluster from the populated data - Do shading for just those lights - - You may find it necessary to bind additional uniforms in `src/renderers/clusteredForwardPlus.js` + - You may find it necessary to bind additional uniforms in `src/renderers/forwardPlus.js` 3. Update `src/shaders/deferredToTexture.frag.glsl` to write desired data to the g-buffer 4. Update `src/deferred.frag.glsl` to read values from the g-buffer and perform simple forward rendering. (Right now it just outputs the screen xy coordinate) -5. Update it to use clustered shading. You should be able to reuse lots of stuff from Clustered Forward+ for this. You will also likely need to update shader inputs in `src/renderers/clusteredDeferred.js` +5. Update it to use clustered shading. You should be able to reuse lots of stuff from Forward+ for this. You will also likely need to update shader inputs in `src/renderers/clustered.js` ## README diff --git a/README.md b/README.md old mode 100644 new mode 100755 index a903608..ec3c73b --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -WebGL Clustered Deferred and Forward+ Shading +WebGL Clustered and Forward+ Shading ====================== **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 5** diff --git a/package.json b/package.json old mode 100644 new mode 100755 index a4429c1..8b772fd --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "build": "webpack --env.production" }, "dependencies": { - "dat-gui": "^0.5.0", + "dat.gui": "^0.7.3", "gl-matrix": "^2.4.0", "spectorjs": "^0.9.0", "stats-js": "^1.0.0-alpha1", diff --git a/src/init.js b/src/init.js old mode 100644 new mode 100755 index 1b09377..885240b --- a/src/init.js +++ b/src/init.js @@ -1,7 +1,7 @@ // TODO: Change this to enable / disable debug mode export const DEBUG = true && process.env.NODE_ENV === 'development'; -import DAT from 'dat-gui'; +import DAT from 'dat.gui'; import WebGLDebug from 'webgl-debug'; import Stats from 'stats-js'; import { PerspectiveCamera } from 'three'; diff --git a/src/main.js b/src/main.js old mode 100644 new mode 100755 index 1cbbf9a..0438a6d --- a/src/main.js +++ b/src/main.js @@ -1,15 +1,15 @@ import { makeRenderLoop, camera, cameraControls, gui, gl } from './init'; import ForwardRenderer from './renderers/forward'; -import ClusteredForwardPlusRenderer from './renderers/clusteredForwardPlus'; -import ClusteredDeferredRenderer from './renderers/clusteredDeferred'; +import ForwardPlusRenderer from './renderers/forwardPlus'; +import ClusteredRenderer from './renderers/clustered'; import Scene from './scene'; const FORWARD = 'Forward'; -const CLUSTERED_FORWARD_PLUS = 'Clustered Forward+'; -const CLUSTERED_DEFFERED = 'Clustered Deferred'; +const FORWARD_PLUS = 'Forward+'; +const CLUSTERED = 'Clustered'; const params = { - renderer: CLUSTERED_FORWARD_PLUS, + renderer: FORWARD_PLUS, _renderer: null, }; @@ -20,16 +20,16 @@ function setRenderer(renderer) { case FORWARD: params._renderer = new ForwardRenderer(); break; - case CLUSTERED_FORWARD_PLUS: - params._renderer = new ClusteredForwardPlusRenderer(15, 15, 15); + case FORWARD_PLUS: + params._renderer = new ForwardPlusRenderer(15, 15, 15); break; - case CLUSTERED_DEFFERED: - params._renderer = new ClusteredDeferredRenderer(15, 15, 15); + case CLUSTERED: + params._renderer = new ClusteredRenderer(15, 15, 15); break; } } -gui.add(params, 'renderer', [FORWARD, CLUSTERED_FORWARD_PLUS, CLUSTERED_DEFFERED]).onChange(setRenderer); +gui.add(params, 'renderer', [FORWARD, FORWARD_PLUS, CLUSTERED]).onChange(setRenderer); const scene = new Scene(); scene.loadGLTF('models/sponza/sponza.gltf'); diff --git a/src/renderers/base.js b/src/renderers/base.js new file mode 100755 index 0000000..8a975b9 --- /dev/null +++ b/src/renderers/base.js @@ -0,0 +1,30 @@ +import TextureBuffer from './textureBuffer'; + +export const MAX_LIGHTS_PER_CLUSTER = 100; + +export default class BaseRenderer { + constructor(xSlices, ySlices, zSlices) { + // Create a texture to store cluster data. Each cluster stores the number of lights followed by the light indices + this._clusterTexture = new TextureBuffer(xSlices * ySlices * zSlices, MAX_LIGHTS_PER_CLUSTER + 1); + this._xSlices = xSlices; + this._ySlices = ySlices; + this._zSlices = zSlices; + } + + updateClusters(camera, viewMatrix, scene) { + // TODO: Update the cluster texture with the count and indices of the lights in each cluster + // This will take some time. The math is nontrivial... + + for (let z = 0; z < this._zSlices; ++z) { + for (let y = 0; y < this._ySlices; ++y) { + for (let x = 0; x < this._xSlices; ++x) { + let i = x + y * this._xSlices + z * this._xSlices * this._ySlices; + // Reset the light count to 0 for every cluster + this._clusterTexture.buffer[this._clusterTexture.bufferIndex(i, 0)] = 0; + } + } + } + + this._clusterTexture.update(); + } +} \ No newline at end of file diff --git a/src/renderers/clustered.js b/src/renderers/clustered.js old mode 100644 new mode 100755 index 9521fbd..46b8278 --- a/src/renderers/clustered.js +++ b/src/renderers/clustered.js @@ -1,32 +1,168 @@ -import { mat4, vec4, vec3 } from 'gl-matrix'; +import { gl, WEBGL_draw_buffers, canvas } from '../init'; +import { mat4, vec4 } from 'gl-matrix'; +import { loadShaderProgram, renderFullscreenQuad } from '../utils'; import { NUM_LIGHTS } from '../scene'; +import toTextureVert from '../shaders/deferredToTexture.vert.glsl'; +import toTextureFrag from '../shaders/deferredToTexture.frag.glsl'; +import QuadVertSource from '../shaders/quad.vert.glsl'; +import fsSource from '../shaders/deferred.frag.glsl.js'; import TextureBuffer from './textureBuffer'; +import BaseRenderer from './base'; -export const MAX_LIGHTS_PER_CLUSTER = 100; +export const NUM_GBUFFERS = 4; -export default class ClusteredRenderer { +export default class ClusteredRenderer extends BaseRenderer { constructor(xSlices, ySlices, zSlices) { - // Create a texture to store cluster data. Each cluster stores the number of lights followed by the light indices - this._clusterTexture = new TextureBuffer(xSlices * ySlices * zSlices, MAX_LIGHTS_PER_CLUSTER + 1); - this._xSlices = xSlices; - this._ySlices = ySlices; - this._zSlices = zSlices; + super(xSlices, ySlices, zSlices); + + this.setupDrawBuffers(canvas.width, canvas.height); + + // Create a texture to store light data + this._lightTexture = new TextureBuffer(NUM_LIGHTS, 8); + + this._progCopy = loadShaderProgram(toTextureVert, toTextureFrag, { + uniforms: ['u_viewProjectionMatrix', 'u_colmap', 'u_normap'], + attribs: ['a_position', 'a_normal', 'a_uv'], + }); + + this._progShade = loadShaderProgram(QuadVertSource, fsSource({ + numLights: NUM_LIGHTS, + numGBuffers: NUM_GBUFFERS, + }), { + uniforms: ['u_gbuffers[0]', 'u_gbuffers[1]', 'u_gbuffers[2]', 'u_gbuffers[3]'], + attribs: ['a_uv'], + }); + + this._projectionMatrix = mat4.create(); + this._viewMatrix = mat4.create(); + this._viewProjectionMatrix = mat4.create(); + } + + setupDrawBuffers(width, height) { + this._width = width; + this._height = height; + + this._fbo = gl.createFramebuffer(); + + //Create, bind, and store a depth target texture for the FBO + this._depthTex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this._depthTex); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null); + gl.bindTexture(gl.TEXTURE_2D, null); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this._fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this._depthTex, 0); + + // Create, bind, and store "color" target textures for the FBO + this._gbuffers = new Array(NUM_GBUFFERS); + let attachments = new Array(NUM_GBUFFERS); + for (let i = 0; i < NUM_GBUFFERS; i++) { + attachments[i] = WEBGL_draw_buffers[`COLOR_ATTACHMENT${i}_WEBGL`]; + this._gbuffers[i] = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this._gbuffers[i]); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, null); + gl.bindTexture(gl.TEXTURE_2D, null); + + gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[i], gl.TEXTURE_2D, this._gbuffers[i], 0); + } + + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { + throw "Framebuffer incomplete"; + } + + // Tell the WEBGL_draw_buffers extension which FBO attachments are + // being used. (This extension allows for multiple render targets.) + WEBGL_draw_buffers.drawBuffersWEBGL(attachments); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + } + + resize(width, height) { + this._width = width; + this._height = height; + + gl.bindTexture(gl.TEXTURE_2D, this._depthTex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null); + for (let i = 0; i < NUM_GBUFFERS; i++) { + gl.bindTexture(gl.TEXTURE_2D, this._gbuffers[i]); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, null); + } + gl.bindTexture(gl.TEXTURE_2D, null); } - updateClusters(camera, viewMatrix, scene) { - // TODO: Update the cluster texture with the count and indices of the lights in each cluster - // This will take some time. The math is nontrivial... - - for (let z = 0; z < this._zSlices; ++z) { - for (let y = 0; y < this._ySlices; ++y) { - for (let x = 0; x < this._xSlices; ++x) { - let i = x + y * this._xSlices + z * this._xSlices * this._ySlices; - // Reset the light count to 0 for every cluster - this._clusterTexture.buffer[this._clusterTexture.bufferIndex(i, 0)] = 0; - } - } + render(camera, scene) { + if (canvas.width != this._width || canvas.height != this._height) { + this.resize(canvas.width, canvas.height); + } + + // Update the camera matrices + camera.updateMatrixWorld(); + mat4.invert(this._viewMatrix, camera.matrixWorld.elements); + mat4.copy(this._projectionMatrix, camera.projectionMatrix.elements); + mat4.multiply(this._viewProjectionMatrix, this._projectionMatrix, this._viewMatrix); + + // Render to the whole screen + gl.viewport(0, 0, canvas.width, canvas.height); + + // Bind the framebuffer + gl.bindFramebuffer(gl.FRAMEBUFFER, this._fbo); + + // Clear the frame + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Use the shader program to copy to the draw buffers + gl.useProgram(this._progCopy.glShaderProgram); + + // Upload the camera matrix + gl.uniformMatrix4fv(this._progCopy.u_viewProjectionMatrix, false, this._viewProjectionMatrix); + + // Draw the scene. This function takes the shader program so that the model's textures can be bound to the right inputs + scene.draw(this._progCopy); + + // Update the buffer used to populate the texture packed with light data + for (let i = 0; i < NUM_LIGHTS; ++i) { + this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 0] = scene.lights[i].position[0]; + this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 1] = scene.lights[i].position[1]; + this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 2] = scene.lights[i].position[2]; + this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 3] = scene.lights[i].radius; + + this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 1) + 0] = scene.lights[i].color[0]; + this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 1) + 1] = scene.lights[i].color[1]; + this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 1) + 2] = scene.lights[i].color[2]; + } + // Update the light texture + this._lightTexture.update(); + + // Update the clusters for the frame + this.updateClusters(camera, this._viewMatrix, scene); + + // Bind the default null framebuffer which is the screen + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + // Clear the frame + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Use this shader program + gl.useProgram(this._progShade.glShaderProgram); + + // TODO: Bind any other shader inputs + + // Bind g-buffers + const firstGBufferBinding = 0; // You may have to change this if you use other texture slots + for (let i = 0; i < NUM_GBUFFERS; i++) { + gl.activeTexture(gl[`TEXTURE${i + firstGBufferBinding}`]); + gl.bindTexture(gl.TEXTURE_2D, this._gbuffers[i]); + gl.uniform1i(this._progShade[`u_gbuffers[${i}]`], i + firstGBufferBinding); } - this._clusterTexture.update(); + renderFullscreenQuad(this._progShade); } -} \ No newline at end of file +}; diff --git a/src/renderers/clusteredDeferred.js b/src/renderers/clusteredDeferred.js deleted file mode 100644 index 5e28e84..0000000 --- a/src/renderers/clusteredDeferred.js +++ /dev/null @@ -1,168 +0,0 @@ -import { gl, WEBGL_draw_buffers, canvas } from '../init'; -import { mat4, vec4 } from 'gl-matrix'; -import { loadShaderProgram, renderFullscreenQuad } from '../utils'; -import { NUM_LIGHTS } from '../scene'; -import toTextureVert from '../shaders/deferredToTexture.vert.glsl'; -import toTextureFrag from '../shaders/deferredToTexture.frag.glsl'; -import QuadVertSource from '../shaders/quad.vert.glsl'; -import fsSource from '../shaders/deferred.frag.glsl.js'; -import TextureBuffer from './textureBuffer'; -import ClusteredRenderer from './clustered'; - -export const NUM_GBUFFERS = 4; - -export default class ClusteredDeferredRenderer extends ClusteredRenderer { - constructor(xSlices, ySlices, zSlices) { - super(xSlices, ySlices, zSlices); - - this.setupDrawBuffers(canvas.width, canvas.height); - - // Create a texture to store light data - this._lightTexture = new TextureBuffer(NUM_LIGHTS, 8); - - this._progCopy = loadShaderProgram(toTextureVert, toTextureFrag, { - uniforms: ['u_viewProjectionMatrix', 'u_colmap', 'u_normap'], - attribs: ['a_position', 'a_normal', 'a_uv'], - }); - - this._progShade = loadShaderProgram(QuadVertSource, fsSource({ - numLights: NUM_LIGHTS, - numGBuffers: NUM_GBUFFERS, - }), { - uniforms: ['u_gbuffers[0]', 'u_gbuffers[1]', 'u_gbuffers[2]', 'u_gbuffers[3]'], - attribs: ['a_uv'], - }); - - this._projectionMatrix = mat4.create(); - this._viewMatrix = mat4.create(); - this._viewProjectionMatrix = mat4.create(); - } - - setupDrawBuffers(width, height) { - this._width = width; - this._height = height; - - this._fbo = gl.createFramebuffer(); - - //Create, bind, and store a depth target texture for the FBO - this._depthTex = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this._depthTex); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null); - gl.bindTexture(gl.TEXTURE_2D, null); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this._fbo); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this._depthTex, 0); - - // Create, bind, and store "color" target textures for the FBO - this._gbuffers = new Array(NUM_GBUFFERS); - let attachments = new Array(NUM_GBUFFERS); - for (let i = 0; i < NUM_GBUFFERS; i++) { - attachments[i] = WEBGL_draw_buffers[`COLOR_ATTACHMENT${i}_WEBGL`]; - this._gbuffers[i] = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this._gbuffers[i]); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, null); - gl.bindTexture(gl.TEXTURE_2D, null); - - gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[i], gl.TEXTURE_2D, this._gbuffers[i], 0); - } - - if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { - throw "Framebuffer incomplete"; - } - - // Tell the WEBGL_draw_buffers extension which FBO attachments are - // being used. (This extension allows for multiple render targets.) - WEBGL_draw_buffers.drawBuffersWEBGL(attachments); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - } - - resize(width, height) { - this._width = width; - this._height = height; - - gl.bindTexture(gl.TEXTURE_2D, this._depthTex); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null); - for (let i = 0; i < NUM_GBUFFERS; i++) { - gl.bindTexture(gl.TEXTURE_2D, this._gbuffers[i]); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, null); - } - gl.bindTexture(gl.TEXTURE_2D, null); - } - - render(camera, scene) { - if (canvas.width != this._width || canvas.height != this._height) { - this.resize(canvas.width, canvas.height); - } - - // Update the camera matrices - camera.updateMatrixWorld(); - mat4.invert(this._viewMatrix, camera.matrixWorld.elements); - mat4.copy(this._projectionMatrix, camera.projectionMatrix.elements); - mat4.multiply(this._viewProjectionMatrix, this._projectionMatrix, this._viewMatrix); - - // Render to the whole screen - gl.viewport(0, 0, canvas.width, canvas.height); - - // Bind the framebuffer - gl.bindFramebuffer(gl.FRAMEBUFFER, this._fbo); - - // Clear the frame - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - // Use the shader program to copy to the draw buffers - gl.useProgram(this._progCopy.glShaderProgram); - - // Upload the camera matrix - gl.uniformMatrix4fv(this._progCopy.u_viewProjectionMatrix, false, this._viewProjectionMatrix); - - // Draw the scene. This function takes the shader program so that the model's textures can be bound to the right inputs - scene.draw(this._progCopy); - - // Update the buffer used to populate the texture packed with light data - for (let i = 0; i < NUM_LIGHTS; ++i) { - this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 0] = scene.lights[i].position[0]; - this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 1] = scene.lights[i].position[1]; - this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 2] = scene.lights[i].position[2]; - this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 0) + 3] = scene.lights[i].radius; - - this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 1) + 0] = scene.lights[i].color[0]; - this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 1) + 1] = scene.lights[i].color[1]; - this._lightTexture.buffer[this._lightTexture.bufferIndex(i, 1) + 2] = scene.lights[i].color[2]; - } - // Update the light texture - this._lightTexture.update(); - - // Update the clusters for the frame - this.updateClusters(camera, this._viewMatrix, scene); - - // Bind the default null framebuffer which is the screen - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - // Clear the frame - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - // Use this shader program - gl.useProgram(this._progShade.glShaderProgram); - - // TODO: Bind any other shader inputs - - // Bind g-buffers - const firstGBufferBinding = 0; // You may have to change this if you use other texture slots - for (let i = 0; i < NUM_GBUFFERS; i++) { - gl.activeTexture(gl[`TEXTURE${i + firstGBufferBinding}`]); - gl.bindTexture(gl.TEXTURE_2D, this._gbuffers[i]); - gl.uniform1i(this._progShade[`u_gbuffers[${i}]`], i + firstGBufferBinding); - } - - renderFullscreenQuad(this._progShade); - } -}; diff --git a/src/renderers/clusteredForwardPlus.js b/src/renderers/forwardPlus.js old mode 100644 new mode 100755 similarity index 93% rename from src/renderers/clusteredForwardPlus.js rename to src/renderers/forwardPlus.js index 9e8afbe..a02649c --- a/src/renderers/clusteredForwardPlus.js +++ b/src/renderers/forwardPlus.js @@ -2,12 +2,12 @@ import { gl } from '../init'; import { mat4, vec4, vec3 } from 'gl-matrix'; import { loadShaderProgram } from '../utils'; import { NUM_LIGHTS } from '../scene'; -import vsSource from '../shaders/clusteredForward.vert.glsl'; -import fsSource from '../shaders/clusteredForward.frag.glsl.js'; +import vsSource from '../shaders/forwardPlus.vert.glsl'; +import fsSource from '../shaders/forwardPlus.frag.glsl.js'; import TextureBuffer from './textureBuffer'; -import ClusteredRenderer from './clustered'; +import BaseRenderer from './base'; -export default class ClusteredForwardPlusRenderer extends ClusteredRenderer { +export default class ForwardPlusRenderer extends BaseRenderer { constructor(xSlices, ySlices, zSlices) { super(xSlices, ySlices, zSlices); diff --git a/src/shaders/clusteredForward.frag.glsl.js b/src/shaders/forwardPlus.frag.glsl.js similarity index 100% rename from src/shaders/clusteredForward.frag.glsl.js rename to src/shaders/forwardPlus.frag.glsl.js diff --git a/src/shaders/clusteredForward.vert.glsl b/src/shaders/forwardPlus.vert.glsl similarity index 100% rename from src/shaders/clusteredForward.vert.glsl rename to src/shaders/forwardPlus.vert.glsl