Deferred renderer added to Light Layer

This commit is contained in:
Felipe Alfonso 2017-08-09 19:36:48 -04:00
parent 2955df2f4f
commit 679bbefff8
7 changed files with 337 additions and 13 deletions

View file

@ -1,4 +1,4 @@
var CHECKSUM = {
build: 'b28c18c0-7cff-11e7-b7e1-779245c06136'
build: '6ff2d290-7d5b-11e7-a786-3d8b38c88055'
};
module.exports = CHECKSUM;

View file

@ -1,9 +1,160 @@
var DeferredRenderer = function (renderer, src, interpolationPercentage, camera)
var DeferredRenderer = function (renderer, lightLayer, interpolationPercentage, camera)
{
var spriteList = lightLayer.sprites;
var length = spriteList.length;
var batch = renderer.spriteBatch;
var gl = renderer.gl;
if (this.renderMask !== this.renderFlags)
{
return;
}
if (renderer.currentRenderer !== null)
{
renderer.currentRenderer.flush();
}
batch.bind(lightLayer.gBufferShaderPass);
batch.indexBufferObject.bind();
lightLayer.updateLights(renderer, camera, this.lightPassShader);
gl.bindFramebuffer(gl.FRAMEBUFFER, lightLayer.gBufferFbo);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
for (var index = 0; index < length; ++index)
{
var spriteNormalPair = spriteList[index];
var gameObject = spriteNormalPair.spriteRef;
/* Inlined function of add sprite modified. */
{
var tempMatrix = batch.tempMatrix;
var frame = gameObject.frame;
var forceFlipY = (frame.texture.source[frame.sourceIndex].glTexture.isRenderTexture ? true : false);
var flipX = gameObject.flipX;
var flipY = gameObject.flipY ^ forceFlipY;
var vertexDataBuffer = batch.vertexDataBuffer;
var vertexBufferObjectF32 = vertexDataBuffer.floatView;
var vertexBufferObjectU32 = vertexDataBuffer.uintView;
var vertexOffset = 0;
var uvs = frame.uvs;
var width = frame.width * (flipX ? -1 : 1);
var height = frame.height * (flipY ? -1 : 1);
var translateX = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var translateY = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;
var tempMatrixMatrix = tempMatrix.matrix;
var x = -gameObject.displayOriginX + frame.x + ((frame.width) * (flipX ? 1 : 0.0));
var y = -gameObject.displayOriginY + frame.y + ((frame.height) * (flipY ? 1 : 0.0));
var xw = x + width;
var yh = y + height;
var cameraMatrix = camera.matrix.matrix;
var mva, mvb, mvc, mvd, mve, mvf, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3;
var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf;
var alphaTL = gameObject._alphaTL;
var alphaTR = gameObject._alphaTR;
var alphaBL = gameObject._alphaBL;
var alphaBR = gameObject._alphaBR;
var tintTL = gameObject._tintTL;
var tintTR = gameObject._tintTR;
var tintBL = gameObject._tintBL;
var tintBR = gameObject._tintBR;
tempMatrix.applyITRS(translateX, translateY, rotation, scaleX, scaleY);
sra = tempMatrixMatrix[0];
srb = tempMatrixMatrix[1];
src = tempMatrixMatrix[2];
srd = tempMatrixMatrix[3];
sre = tempMatrixMatrix[4];
srf = tempMatrixMatrix[5];
cma = cameraMatrix[0];
cmb = cameraMatrix[1];
cmc = cameraMatrix[2];
cmd = cameraMatrix[3];
cme = cameraMatrix[4];
cmf = cameraMatrix[5];
mva = sra * cma + srb * cmc;
mvb = sra * cmb + srb * cmd;
mvc = src * cma + srd * cmc;
mvd = src * cmb + srd * cmd;
mve = sre * cma + srf * cmc + cme;
mvf = sre * cmb + srf * cmd + cmf;
tx0 = x * mva + y * mvc + mve;
ty0 = x * mvb + y * mvd + mvf;
tx1 = x * mva + yh * mvc + mve;
ty1 = x * mvb + yh * mvd + mvf;
tx2 = xw * mva + yh * mvc + mve;
ty2 = xw * mvb + yh * mvd + mvf;
tx3 = xw * mva + y * mvc + mve;
ty3 = xw * mvb + y * mvd + mvf;
if (renderer.currentTexture[0] !== frame.texture.source[frame.sourceIndex].glTexture ||
renderer.currentTexture[1] !== spriteNormalPair.normalTextureRef.source[spriteNormalPair.spriteRef.frame.sourceIndex].glTexture)
{
batch.flush(lightLayer.gBufferShaderPass, lightLayer.renderTarget);
renderer.setTexture(frame.texture.source[frame.sourceIndex].glTexture, 0);
renderer.setTexture(spriteNormalPair.normalTextureRef.source[spriteNormalPair.spriteRef.frame.sourceIndex].glTexture, 1);
}
batch.drawIndexed = true;
batch.drawingMesh = false;
vertexOffset = vertexDataBuffer.allocate(24);
batch.elementCount += 6;
// Top Left
vertexBufferObjectF32[vertexOffset++] = tx0;
vertexBufferObjectF32[vertexOffset++] = ty0;
vertexBufferObjectF32[vertexOffset++] = uvs.x0;
vertexBufferObjectF32[vertexOffset++] = uvs.y0;
vertexBufferObjectU32[vertexOffset++] = tintTL;
vertexBufferObjectF32[vertexOffset++] = alphaTL;
// Bottom Left
vertexBufferObjectF32[vertexOffset++] = tx1;
vertexBufferObjectF32[vertexOffset++] = ty1;
vertexBufferObjectF32[vertexOffset++] = uvs.x1;
vertexBufferObjectF32[vertexOffset++] = uvs.y1;
vertexBufferObjectU32[vertexOffset++] = tintBL;
vertexBufferObjectF32[vertexOffset++] = alphaBL;
// Bottom Right
vertexBufferObjectF32[vertexOffset++] = tx2;
vertexBufferObjectF32[vertexOffset++] = ty2;
vertexBufferObjectF32[vertexOffset++] = uvs.x2;
vertexBufferObjectF32[vertexOffset++] = uvs.y2;
vertexBufferObjectU32[vertexOffset++] = tintBR;
vertexBufferObjectF32[vertexOffset++] = alphaBR;
// Top Right
vertexBufferObjectF32[vertexOffset++] = tx3;
vertexBufferObjectF32[vertexOffset++] = ty3;
vertexBufferObjectF32[vertexOffset++] = uvs.x3;
vertexBufferObjectF32[vertexOffset++] = uvs.y3;
vertexBufferObjectU32[vertexOffset++] = tintTR;
vertexBufferObjectF32[vertexOffset++] = alphaTR;
}
}
batch.flush(lightLayer.gBufferShaderPass, lightLayer.renderTarget);
renderer.setTexture({texture: lightLayer.gBufferColorTex}, 0);
renderer.setTexture({texture: lightLayer.gBufferNormalTex}, 1);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.useProgram(lightLayer.lightPassShader.program);
gl.bindBuffer(gl.ARRAY_BUFFER, lightLayer.lightPassVBO);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
batch.bind();
};
module.exports = DeferredRenderer;

View file

@ -16,7 +16,7 @@ var ForwardRenderer = function (renderer, lightLayer, interpolationPercentage, c
batch.bind(lightLayer.passShader);
batch.indexBufferObject.bind();
lightLayer.updateLights(renderer, camera);
lightLayer.updateLights(renderer, camera, this.passShader);
for (var index = 0; index < length; ++index)
{

View file

@ -34,11 +34,11 @@ var LightLayer = new Class({
GameObject.call(this, scene, 'LightLayer');
var resourceManager = scene.game.renderer.resourceManager;
var deferred = WebGLSupportedExtensions.has('WEBGL_draw_buffers');
this.renderer = scene.game.renderer;
this.passShader = null;
this.gl = null;
this.deferred = WebGLSupportedExtensions.has('WEBGL_draw_buffers');
this.ambientLightColorR = 0.0;
this.ambientLightColorG = 0.0;
this.ambientLightColorB = 0.0;
@ -49,7 +49,7 @@ var LightLayer = new Class({
this.lightsLocations = [];
this._z = 0;
if (resourceManager !== undefined && !this.deferred)
if (resourceManager !== undefined && !deferred)
{
this.gl = scene.game.renderer.gl;
this.passShader = resourceManager.createShader('Phong2DShaderForward', {vert: TexturedAndNormalizedTintedShader.vert, frag: `
@ -112,6 +112,154 @@ var LightLayer = new Class({
};
}
}
else
{
Const.MAX_LIGHTS = 100;
var gl = this.gl = scene.game.renderer.gl;
this.ext = scene.game.renderer.getExtension('WEBGL_draw_buffers');
this.gBufferShaderPass = resourceManager.createShader('GBufferShader', {vert: TexturedAndNormalizedTintedShader.vert, frag: `
#extension GL_EXT_draw_buffers : require
precision mediump float;
uniform vec2 uResolution;
uniform sampler2D uMainTexture;
uniform sampler2D uNormTexture;
varying vec2 v_tex_coord;
varying vec3 v_color;
varying float v_alpha;
void main()
{
vec4 spriteColor = texture2D(uMainTexture, v_tex_coord) * vec4(v_color, v_alpha);
vec3 spriteNormal = texture2D(uNormTexture, v_tex_coord).rgb;
gl_FragData[0] = spriteColor;
gl_FragData[1] = vec4(spriteNormal, spriteColor.a);
}
`});
this.lightPassShader = resourceManager.createShader('Phong2DShaderDeferred', {
vert: `
precision mediump float;
attribute vec2 vertexPosition;
void main()
{
gl_Position = vec4(vertexPosition, 0.0, 1.0);
}
`,
frag: `
precision mediump float;
struct Light
{
vec3 position;
vec3 color;
float attenuation;
};
uniform vec2 uResolution;
uniform sampler2D uGbufferColor;
uniform sampler2D uGbufferNormal;
uniform vec3 uAmbientLightColor;
uniform Light uLights[` + Const.MAX_LIGHTS + `];
void main()
{
vec2 uv = vec2(gl_FragCoord.xy / uResolution);
vec3 finalColor = vec3(0.0, 0.0, 0.0);
vec4 gbColor = texture2D(uGbufferColor, uv);
vec3 gbNormal = texture2D(uGbufferNormal, uv).rgb;
vec3 normal = normalize(vec3(gbNormal * 2.0 - 1.0));
for (int index = 0; index < ` + Const.MAX_LIGHTS + `; ++index)
{
Light light = uLights[index];
float lightY = uResolution.y - light.position.y;
vec3 lightDir = vec3((vec2(light.position.x, lightY) / uResolution) - uv, light.position.z);
vec3 lightNormal = normalize(lightDir);
float distToSurf = length(lightDir);
float diffuseFactor = max(dot(normal, lightNormal), 0.0);
float attenuation = 1.0 / (1.0 + light.attenuation * (distToSurf * distToSurf));
vec3 diffuse = light.color * gbColor.rgb * diffuseFactor;
finalColor += attenuation * diffuse;
}
gl_FragColor = vec4(uAmbientLightColor + finalColor, gbColor.a);
}
`});
this.lightPassVBO = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.lightPassVBO);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, 7, -1, -1, 7, -1]), gl.STATIC_DRAW);
this.uMainTextureLoc = this.gBufferShaderPass.getUniformLocation('uMainTexture');
this.uNormTextureLoc = this.gBufferShaderPass.getUniformLocation('uNormTexture');
this.gBufferShaderPass.setConstantInt1(this.uMainTextureLoc, 0);
this.gBufferShaderPass.setConstantInt1(this.uNormTextureLoc, 1);
this.ambientLightColorLoc = this.lightPassShader.getUniformLocation('uAmbientLightColor');
this.uResolutionLoc = this.lightPassShader.getUniformLocation('uResolution');
this.uGbufferColorLoc = this.lightPassShader.getUniformLocation('uGbufferColor');
this.uGbufferNormalLoc = this.lightPassShader.getUniformLocation('uGbufferNormal');
this.lightPassShader.setConstantInt1(this.uGbufferColorLoc, 0);
this.lightPassShader.setConstantInt1(this.uGbufferNormalLoc, 1);
this.gBufferShaderPass.bindAttribLocation(0, 'v_tex_coord');
this.gBufferShaderPass.bindAttribLocation(1, 'v_color');
this.gBufferShaderPass.bindAttribLocation(2, 'v_alpha');
this.lightPassShader.bindAttribLocation(0, 'vertexPosition');
for (var index = 0; index < Const.MAX_LIGHTS; ++index)
{
this.lightsLocations[index] = {
position: this.lightPassShader.getUniformLocation('uLights[' + index + '].position'),
color: this.lightPassShader.getUniformLocation('uLights[' + index + '].color'),
attenuation: this.lightPassShader.getUniformLocation('uLights[' + index + '].attenuation')
};
}
/* Setup render targets */
this.gBufferFbo = gl.createFramebuffer();
this.gBufferColorTex = gl.createTexture();
this.gBufferNormalTex = gl.createTexture();
gl.bindFramebuffer(gl.FRAMEBUFFER, this.gBufferFbo);
gl.bindTexture(gl.TEXTURE_2D, this.gBufferColorTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, scene.game.renderer.width, scene.game.renderer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
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.bindTexture(gl.TEXTURE_2D, this.gBufferNormalTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, scene.game.renderer.width, scene.game.renderer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
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.framebufferTexture2D(gl.FRAMEBUFFER, this.ext.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_2D, this.gBufferColorTex, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, this.ext.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, this.gBufferNormalTex, 0);
this.ext.drawBuffersWEBGL([this.ext.COLOR_ATTACHMENT0_WEBGL, this.ext.COLOR_ATTACHMENT1_WEBGL]);
var complete = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (complete !== gl.FRAMEBUFFER_COMPLETE)
{
var errors = {
36054: 'Incomplete Attachment',
36055: 'Missing Attachment',
36057: 'Incomplete Dimensions',
36061: 'Framebuffer Unsupported'
};
throw new Error('Framebuffer incomplete. Framebuffer status: ' + errors[complete]);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
this.setOrigin(0, 0);
},
@ -138,6 +286,16 @@ var LightLayer = new Class({
return Const.MAX_LIGHTS;
},
getLightCount: function ()
{
return this.lights.length;
},
isDeferred: function ()
{
return WebGLSupportedExtensions.has('WEBGL_draw_buffers');
},
/* This will probably be removed later */
addSprite: function (sprite, normalTexture)
{
@ -202,7 +360,7 @@ var LightLayer = new Class({
}
},
updateLights: function(renderer, camera)
updateLights: function(renderer, camera, shader)
{
if (this.gl !== null)
{
@ -210,11 +368,10 @@ var LightLayer = new Class({
var lights = this.lights;
var length = lights.length;
var gl = this.gl;
var passShader = this.passShader;
var point = {x: 0, y: 0};
passShader.setConstantFloat2(this.uResolutionLoc, renderer.width, renderer.height);
passShader.setConstantFloat3(this.ambientLightColorLoc, this.ambientLightColorR, this.ambientLightColorG, this.ambientLightColorB);
shader.setConstantFloat2(this.uResolutionLoc, renderer.width, renderer.height);
shader.setConstantFloat3(this.ambientLightColorLoc, this.ambientLightColorR, this.ambientLightColorG, this.ambientLightColorB);
TempMatrix.applyITRS(camera.x, camera.y, camera.rotation, camera.zoom, camera.zoom);
@ -222,9 +379,9 @@ var LightLayer = new Class({
{
var light = lights[index];
TempMatrix.transformPoint(light.x, light.y, point);
passShader.setConstantFloat3(locations[index].position, point.x - (camera.scrollX * light.scrollFactorX), point.y - (camera.scrollY * light.scrollFactorY), light.z);
passShader.setConstantFloat3(locations[index].color, light.r, light.g, light.b);
passShader.setConstantFloat1(locations[index].attenuation, light.attenuation);
shader.setConstantFloat3(locations[index].position, point.x - (camera.scrollX * light.scrollFactorX), point.y - (camera.scrollY * light.scrollFactorY), light.z);
shader.setConstantFloat3(locations[index].color, light.r, light.g, light.b);
shader.setConstantFloat1(locations[index].attenuation, light.attenuation);
}
}
}

View file

@ -56,6 +56,7 @@ var WebGLRenderer = new Class({
this.blendModes = [];
this.gl = null;
this.extensions = null;
this.extensionList = {};
this.rendererArray = [];
this.blitterBatch = null;
this.aaQuadBatch = null;
@ -170,6 +171,15 @@ var WebGLRenderer = new Class({
return this;
},
getExtension: function (name)
{
if (!(name in this.extensionList))
{
this.extensionList[name] = this.gl.getExtension(name);
}
return this.extensionList[name];
},
createTexture: function (source, width, height)
{
width = source ? source.width : width;

View file

@ -7,7 +7,7 @@ var WebGLSupportedExtensions = (function () {
has: function (name)
{
return false; //extensionList.indexOf(name) >= 0;
return extensionList.indexOf(name) >= 0;
}
};

View file

@ -13,6 +13,12 @@ var Shader = new Class({
this.name = name;
},
bindAttribLocation: function (index, name)
{
this.gl.bindAttribLocation(this.program, index, name);
},
getUniformLocation: function (name)
{
return this.gl.getUniformLocation(this.program, name);