From 559ec47aabe6f139dff4d2f850744182245715e1 Mon Sep 17 00:00:00 2001 From: Olli Etuaho Date: Thu, 26 Jun 2014 11:12:51 +0300 Subject: [PATCH 1/7] Revert "Use VAO to save on vertex specifying commands when drawing" This is to make refactoring the geometry node easier. VAO usage will be restored in the end. This reverts commit 22f9555d09d93f6dd38852908df2ee66737ba4f6. --- src/core/display/chunks/chunkFactory.js | 6 +- src/core/display/chunks/geometryChunk.js | 107 ++++++++--------------- src/core/display/display.js | 10 +-- 3 files changed, 38 insertions(+), 85 deletions(-) diff --git a/src/core/display/chunks/chunkFactory.js b/src/core/display/chunks/chunkFactory.js index b7fb4823..0de23eca 100644 --- a/src/core/display/chunks/chunkFactory.js +++ b/src/core/display/chunks/chunkFactory.js @@ -112,10 +112,6 @@ SceneJS_ChunkFactory.prototype.putChunk = function (chunk) { if (--chunk.useCount <= 0) { // Release shared core if use count now zero - if (chunk.recycle) { - chunk.recycle(); - } - this._chunks[chunk.id] = null; var freeChunks = SceneJS_ChunkFactory._freeChunks[chunk.type]; @@ -125,7 +121,7 @@ SceneJS_ChunkFactory.prototype.putChunk = function (chunk) { }; /** - * Re-cache shader variable locations for each active chunk and reset VAOs if any + * Re-cache shader variable locations for each active chunk */ SceneJS_ChunkFactory.prototype.webglRestored = function () { diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index b77fa9ea..28a23887 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -24,9 +24,6 @@ SceneJS_ChunkFactory.createChunkType({ this._aUV2Draw = draw.getAttribute("SCENEJS_aUVCoord2"); this._aColorDraw = draw.getAttribute("SCENEJS_aVertexColor"); - this.VAO = null; - this.VAOHasInterleavedBuf = false; - var pick = this.program.pick; this._aVertexPick = pick.getAttribute("SCENEJS_aVertex"); @@ -36,89 +33,57 @@ SceneJS_ChunkFactory.createChunkType({ this._aColorPick = pick.getAttribute("SCENEJS_aVertexColor"); }, - recycle:function () { - if (this.VAO) { - // Guarantee that the old VAO is deleted immediately when recycling the object. - var VAOExt = this.program.gl.getExtension("OES_vertex_array_object"); - VAOExt.deleteVertexArrayOES(this.VAO); - } - }, - draw:function (ctx) { var gl = this.program.gl; if (ctx.geoChunkId != this.id) { // HACK until we have distinct state chunks for VBOs and draw call - var ctxBufsActive = ctx.vertexBuf || ctx.normalBuf || ctx.uvBuf || ctx.uvBuf2 || ctx.colorBuf; - if (this.VAO && (ctxBufsActive || - this.core.interleavedBuf && this.core.interleavedBuf.dirty && this.VAOHasInterleavedBuf)) { - // Need to recreate VAO to refer to separate buffers, or can't use VAO due to buffers - // specified outside. - ctx.VAO.deleteVertexArrayOES(this.VAO); - this.VAO = null; - } - if (this.VAO) { - ctx.VAO.bindVertexArrayOES(this.VAO); + + if (this.core.interleavedBuf && !this.core.interleavedBuf.dirty) { + this.core.interleavedBuf.bind(); + if (this._aVertexDraw && !ctx.vertexBuf) { + this._aVertexDraw.bindInterleavedFloatArrayBuffer(3, this.core.interleavedStride, this.core.interleavedPositionOffset); + } + if (this._aNormalDraw && !ctx.normalBuf) { + this._aNormalDraw.bindInterleavedFloatArrayBuffer(3, this.core.interleavedStride, this.core.interleavedNormalOffset); + } + if (this._aUVDraw && !ctx.uvBuf) { + this._aUVDraw.bindInterleavedFloatArrayBuffer(2, this.core.interleavedStride, this.core.interleavedUVOffset); + } + if (this._aUV2Draw && !ctx.uv2Buf) { + this._aUV2Draw.bindInterleavedFloatArrayBuffer(2, this.core.interleavedStride, this.core.interleavedUV2Offset); + } + if (this._aColorDraw && !ctx.colorBuf) { + this._aColorDraw.bindInterleavedFloatArrayBuffer(4, this.core.interleavedStride, this.core.interleavedColorOffset); + } } else { - var useInterleavedBuf = (this.core.interleavedBuf && !this.core.interleavedBuf.dirty); - if (ctx.VAO && !ctxBufsActive) { - this.VAO = ctx.VAO.createVertexArrayOES(); - ctx.VAO.bindVertexArrayOES(this.VAO); - this.VAOHasInterleavedBuf = useInterleavedBuf; + if (this._aVertexDraw && !ctx.vertexBuf) { + this._aVertexDraw.bindFloatArrayBuffer(this.core.vertexBuf); } - if (useInterleavedBuf) { - this.core.interleavedBuf.bind(); - if (this._aVertexDraw && !ctx.vertexBuf) { - this._aVertexDraw.bindInterleavedFloatArrayBuffer(3, this.core.interleavedStride, this.core.interleavedPositionOffset); - } - if (this._aNormalDraw && !ctx.normalBuf) { - this._aNormalDraw.bindInterleavedFloatArrayBuffer(3, this.core.interleavedStride, this.core.interleavedNormalOffset); - } - if (this._aUVDraw && !ctx.uvBuf) { - this._aUVDraw.bindInterleavedFloatArrayBuffer(2, this.core.interleavedStride, this.core.interleavedUVOffset); - } - if (this._aUV2Draw && !ctx.uv2Buf) { - this._aUV2Draw.bindInterleavedFloatArrayBuffer(2, this.core.interleavedStride, this.core.interleavedUV2Offset); - } - if (this._aColorDraw && !ctx.colorBuf) { - this._aColorDraw.bindInterleavedFloatArrayBuffer(4, this.core.interleavedStride, this.core.interleavedColorOffset); - } - } else { - if (this._aVertexDraw && !ctx.vertexBuf) { - this._aVertexDraw.bindFloatArrayBuffer(this.core.vertexBuf); - } - - if (this._aNormalDraw && !ctx.normalBuf) { - this._aNormalDraw.bindFloatArrayBuffer(this.core.normalBuf); - } - - if (this._aUVDraw && !ctx.uvBuf) { - this._aUVDraw.bindFloatArrayBuffer(this.core.uvBuf); - } - - if (this._aUV2Draw && !ctx.uvBuf2) { - this._aUV2Draw.bindFloatArrayBuffer(this.core.uvBuf2); - } - - if (this._aColorDraw && !ctx.colorBuf) { - this._aColorDraw.bindFloatArrayBuffer(this.core.colorBuf); - } + if (this._aNormalDraw && !ctx.normalBuf) { + this._aNormalDraw.bindFloatArrayBuffer(this.core.normalBuf); } - this.core.indexBuf.bind(); + if (this._aUVDraw && !ctx.uvBuf) { + this._aUVDraw.bindFloatArrayBuffer(this.core.uvBuf); + } + + if (this._aUV2Draw && !ctx.uvBuf2) { + this._aUV2Draw.bindFloatArrayBuffer(this.core.uvBuf2); + } + + if (this._aColorDraw && !ctx.colorBuf) { + this._aColorDraw.bindFloatArrayBuffer(this.core.colorBuf); + } } - } - gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, gl.UNSIGNED_SHORT, 0); + this.core.indexBuf.bind(); - if (this.VAO) { - // We don't want following nodes that don't use their own VAOs to muck up - // this node's VAO, so we need to unbind it. - ctx.VAO.bindVertexArrayOES(null); - } else { ctx.geoChunkId = this.id; } + + gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, gl.UNSIGNED_SHORT, 0); }, pick:function (ctx) { diff --git a/src/core/display/display.js b/src/core/display/display.js index f561ffd3..6cec9009 100644 --- a/src/core/display/display.js +++ b/src/core/display/display.js @@ -273,8 +273,7 @@ var SceneJS_Display = function (cfg) { */ this._frameCtx = { pickNames:[], // Pick names of objects hit during pick render - canvas:this._canvas, // The canvas - VAO:null // Vertex array object extension + canvas:this._canvas // The canvas }; /* The frame context has this facade which is given to scene node "rendered" listeners @@ -927,13 +926,6 @@ SceneJS_Display.prototype._doDrawList = function (pick, rayPick) { frameCtx.transparencyPass = false; - // The extension needs to be re-queried in case the context was lost and - // has been recreated. - var VAO = gl.getExtension("OES_vertex_array_object"); - if (VAO) { - frameCtx.VAO = VAO; - } - gl.viewport(0, 0, this._canvas.canvas.width, this._canvas.canvas.height); if (this.transparent) { gl.clearColor(0,0,0,0); From f16f4422160d4405c52d03de92d83a23ad993a71 Mon Sep 17 00:00:00 2001 From: Olli Etuaho Date: Wed, 25 Jun 2014 16:57:06 +0300 Subject: [PATCH 2/7] Use draw chunk for drawElements instead of geometry chunk --- src/core/display/chunks/drawChunk.js | 2 +- src/core/display/chunks/geometryChunk.js | 22 ---------------------- src/core/display/chunks/programChunk.js | 4 ---- src/core/display/display.js | 9 +++++++-- 4 files changed, 8 insertions(+), 29 deletions(-) diff --git a/src/core/display/chunks/drawChunk.js b/src/core/display/chunks/drawChunk.js index b3e260d1..a10598ee 100644 --- a/src/core/display/chunks/drawChunk.js +++ b/src/core/display/chunks/drawChunk.js @@ -22,4 +22,4 @@ SceneJS_ChunkFactory.createChunkType({ gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, gl.UNSIGNED_SHORT, 0); } -}); \ No newline at end of file +}); diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index 28a23887..96609dab 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -5,15 +5,6 @@ SceneJS_ChunkFactory.createChunkType({ type:"geometry", - /** - * As we apply a list of state chunks in a {@link SceneJS_Display}, we track the ID of each chunk - * in order to avoid redundantly re-applying the same chunk. - * - * We don't want that for draw chunks however, because they contain GL drawElements calls, - * which we need to do for each object. - */ - unique:true, - build:function () { var draw = this.program.draw; @@ -37,8 +28,6 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; - if (ctx.geoChunkId != this.id) { // HACK until we have distinct state chunks for VBOs and draw call - if (this.core.interleavedBuf && !this.core.interleavedBuf.dirty) { this.core.interleavedBuf.bind(); if (this._aVertexDraw && !ctx.vertexBuf) { @@ -80,18 +69,12 @@ SceneJS_ChunkFactory.createChunkType({ this.core.indexBuf.bind(); - ctx.geoChunkId = this.id; - } - - gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, gl.UNSIGNED_SHORT, 0); }, pick:function (ctx) { var gl = this.program.gl; - if (ctx.geoChunkId != this.id) { // HACK until we have distinct state chunks for VBOs and draw call - if (this._aVertexPick && !ctx.vertexBuf) { this._aVertexPick.bindFloatArrayBuffer(this.core.vertexBuf); } @@ -109,10 +92,5 @@ SceneJS_ChunkFactory.createChunkType({ } this.core.indexBuf.bind(); - - ctx.geoChunkId = this.id; - } - - gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, gl.UNSIGNED_SHORT, 0); } }); diff --git a/src/core/display/chunks/programChunk.js b/src/core/display/chunks/programChunk.js index f57ea717..8137a6bb 100644 --- a/src/core/display/chunks/programChunk.js +++ b/src/core/display/chunks/programChunk.js @@ -22,8 +22,6 @@ SceneJS_ChunkFactory.createChunkType({ frameCtx.colorBuf = false; frameCtx.textureUnit = 0; - frameCtx.geoChunkId = null; // HACK until we have distinct state chunks for VBOs and draw call - var gl = this.program.gl; for (var i = 0; i < 10; i++) { @@ -51,8 +49,6 @@ SceneJS_ChunkFactory.createChunkType({ frameCtx.colorBuf = false; frameCtx.textureUnit = 0; - frameCtx.geoChunkId = null; // HACK until we have distinct state chunks for VBOs and draw call - for (var i = 0; i < 10; i++) { gl.disableVertexAttribArray(i); } diff --git a/src/core/display/display.js b/src/core/display/display.js index 6cec9009..a5bdd6f7 100644 --- a/src/core/display/display.js +++ b/src/core/display/display.js @@ -430,7 +430,8 @@ SceneJS_Display.prototype.buildObject = function (objectId) { this._setChunk(object, 17, "clips", this.clips); this._setChunk(object, 18, "morphGeometry", this.morphGeometry); this._setChunk(object, 19, "listeners", this.renderListeners); // Must be after the above chunks - this._setChunk(object, 20, "geometry", this.geometry); // Must be last + this._setChunk(object, 20, "geometry", this.geometry); + this._setChunk(object, 21, "draw", this.geometry); // Must be last }; SceneJS_Display.prototype._setChunk = function (object, order, chunkType, core, unique) { @@ -468,6 +469,10 @@ SceneJS_Display.prototype._setChunk = function (object, order, chunkType, core, chunkId = 'p' + object.program.id; } + // This is needed so that chunkFactory can distinguish between draw and geometry + // chunks with the same core. + chunkId = order + '__' + chunkId; + var oldChunk = object.chunks[order]; if (oldChunk) { @@ -718,7 +723,7 @@ SceneJS_Display.prototype._buildDrawList = function () { // As we apply the state chunk lists we track the ID of most types of chunk in order // to cull redundant re-applications of runs of the same chunk - except for those chunks with a - // 'unique' flag. We don't want to cull runs of geometry chunks because they contain the GL + // 'unique' flag. We don't want to cull runs of draw chunks because they contain the GL // drawElements calls which render the objects. // Chunk IDs are only considered unique within the same program. Therefore, whenever we do a From ab1075e8a04f11759b6f9bea3bc2eab451c2f4e8 Mon Sep 17 00:00:00 2001 From: Olli Etuaho Date: Wed, 25 Jun 2014 18:00:29 +0300 Subject: [PATCH 3/7] Merge geometry and morphGeometry into one chunk This is done in the simplest possible way in this commit, further changes will refine the code. --- build.js | 3 +- src/core/display/chunks/chunk.js | 4 +- src/core/display/chunks/chunkFactory.js | 7 +- src/core/display/chunks/geometryChunk.js | 180 ++++++++++++++++-- src/core/display/chunks/morphGeometryChunk.js | 166 ---------------- src/core/display/display.js | 17 +- 6 files changed, 180 insertions(+), 197 deletions(-) delete mode 100644 src/core/display/chunks/morphGeometryChunk.js diff --git a/build.js b/build.js index 9e797981..57fcc65d 100755 --- a/build.js +++ b/build.js @@ -193,7 +193,6 @@ "src/core/display/chunks/listenersChunk.js", "src/core/display/chunks/lookAtChunk.js", "src/core/display/chunks/materialChunk.js", - "src/core/display/chunks/morphGeometryChunk.js", "src/core/display/chunks/nameChunk.js", "src/core/display/chunks/programChunk.js", "src/core/display/chunks/rendererChunk.js", @@ -318,4 +317,4 @@ }); }); -})(); \ No newline at end of file +})(); diff --git a/src/core/display/chunks/chunk.js b/src/core/display/chunks/chunk.js index 35b16bba..a0568573 100644 --- a/src/core/display/chunks/chunk.js +++ b/src/core/display/chunks/chunk.js @@ -17,12 +17,14 @@ var SceneJS_Chunk = function() {}; * @param {String} id Chunk ID * @param {SceneJS_Program} program Program to render the chunk * @param {SceneJS_Core} core The state core rendered by this chunk + * @param {SceneJS_Core} core2 Another state core rendered by this chunk, only used for geometry */ -SceneJS_Chunk.prototype.init = function(id, program, core) { +SceneJS_Chunk.prototype.init = function(id, program, core, core2) { this.id = id; this.program = program; this.core = core; + this.core2 = core2; if (this.build) { this.build(); diff --git a/src/core/display/chunks/chunkFactory.js b/src/core/display/chunks/chunkFactory.js index 0de23eca..46ca2da4 100644 --- a/src/core/display/chunks/chunkFactory.js +++ b/src/core/display/chunks/chunkFactory.js @@ -62,7 +62,7 @@ SceneJS_ChunkFactory.createChunkType = function(params) { /** * */ -SceneJS_ChunkFactory.prototype.getChunk = function(chunkId, type, program, core) { +SceneJS_ChunkFactory.prototype.getChunk = function(chunkId, type, program, core, core2) { var chunkClass = SceneJS_ChunkFactory.chunkTypes[type]; // Check type supported @@ -85,11 +85,12 @@ SceneJS_ChunkFactory.prototype.getChunk = function(chunkId, type, program, core) if (chunk) { // Reinitialise the recycled chunk - chunk.init(chunkId, program, core); + chunk.init(chunkId, program, core, core2); } else { // Instantiate a fresh chunk - chunk = new chunkClass(chunkId, program, core); // Create new chunk + chunk = new chunkClass(chunkId, program, core, core2); // Create new chunk + } chunk.useCount = 1; diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index 96609dab..bd9d1a95 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -15,6 +15,13 @@ SceneJS_ChunkFactory.createChunkType({ this._aUV2Draw = draw.getAttribute("SCENEJS_aUVCoord2"); this._aColorDraw = draw.getAttribute("SCENEJS_aVertexColor"); + this._aMorphVertexDraw = draw.getAttribute("SCENEJS_aMorphVertex"); + this._aMorphNormalDraw = draw.getAttribute("SCENEJS_aMorphNormal"); + this._aMorphUVDraw = draw.getAttribute("SCENEJS_aMorphUVCoord"); + this._aMorphUV2Draw = draw.getAttribute("SCENEJS_aMorphUVCoord2"); + this._aMorphColorDraw = draw.getAttribute("SCENEJS_aMorphColor"); + this._uMorphFactorDraw = draw.getUniformLocation("SCENEJS_uMorphFactor"); + var pick = this.program.pick; this._aVertexPick = pick.getAttribute("SCENEJS_aVertex"); @@ -22,75 +29,212 @@ SceneJS_ChunkFactory.createChunkType({ this._aUVPick = pick.getAttribute("SCENEJS_aUVCoord"); this._aUV2Pick = pick.getAttribute("SCENEJS_aUVCoord2"); this._aColorPick = pick.getAttribute("SCENEJS_aVertexColor"); + + this._aMorphVertexPick = pick.getAttribute("SCENEJS_aMorphVertex"); + this._aMorphNormalPick = pick.getAttribute("SCENEJS_aMorphNormal"); + this._aMorphUVPick = pick.getAttribute("SCENEJS_aMorphUVCoord"); + this._aMorphUV2Pick = pick.getAttribute("SCENEJS_aMorphUVCoord2"); + this._aMorphColorPick = pick.getAttribute("SCENEJS_aMorphColor"); + this._uMorphFactorPick = pick.getUniformLocation("SCENEJS_uMorphFactor"); + }, + + morphDraw:function (ctx) { + + var targets = this.core.targets; + + if (!targets || targets.length == 0) { + ctx.vertexBuf = false; + ctx.normalBuf = false; + ctx.uvBuf = false; + ctx.uvBuf2 = false; + ctx.colorBuf = false; + return; + } + + var gl = this.program.gl; + + var target1 = this.core.targets[this.core.key1]; // Keys will update + var target2 = this.core.targets[this.core.key2]; + + if (this._aMorphVertexDraw) { + this._aVertexDraw.bindFloatArrayBuffer(target1.vertexBuf); + this._aMorphVertexDraw.bindFloatArrayBuffer(target2.vertexBuf); + ctx.vertexBuf = true; + } else { + ctx.vertexBuf = false; + } + + if (this._aMorphNormalDraw) { + this._aNormalDraw.bindFloatArrayBuffer(target1.normalBuf); + this._aMorphNormalDraw.bindFloatArrayBuffer(target2.normalBuf); + ctx.normalBuf = true; + } else { + ctx.normalBuf = false; + } + + if (this._aMorphUVDraw) { + this._aUVDraw.bindFloatArrayBuffer(target1.uvBuf); + this._aMorphUVDraw.bindFloatArrayBuffer(target2.uvBuf); + ctx.uvBuf = true; + } else { + ctx.uvBuf = false; + } + + if (this._aMorphUV2Draw) { + this._aUV2Draw.bindFloatArrayBuffer(target1.uvBuf2); + this._aMorphUV2Draw.bindFloatArrayBuffer(target2.uvBuf2); + ctx.uvBuf2 = true; + } else { + ctx.uvBuf2 = false; + } + + if (this._aMorphColorDraw) { + this._aColorDraw.bindFloatArrayBuffer(target1.colorBuf); + this._aMorphColorDraw.bindFloatArrayBuffer(target2.colorBuf); + ctx.colorBuf = true; + } else { + ctx.colorBuf = false; + } + + if (this._uMorphFactorDraw) { + gl.uniform1f(this._uMorphFactorDraw, this.core.factor); // Bind LERP factor + } }, draw:function (ctx) { + this.morphDraw(ctx); + var gl = this.program.gl; - if (this.core.interleavedBuf && !this.core.interleavedBuf.dirty) { - this.core.interleavedBuf.bind(); + if (this.core2.interleavedBuf && !this.core2.interleavedBuf.dirty) { + this.core2.interleavedBuf.bind(); if (this._aVertexDraw && !ctx.vertexBuf) { - this._aVertexDraw.bindInterleavedFloatArrayBuffer(3, this.core.interleavedStride, this.core.interleavedPositionOffset); + this._aVertexDraw.bindInterleavedFloatArrayBuffer(3, this.core2.interleavedStride, this.core2.interleavedPositionOffset); } if (this._aNormalDraw && !ctx.normalBuf) { - this._aNormalDraw.bindInterleavedFloatArrayBuffer(3, this.core.interleavedStride, this.core.interleavedNormalOffset); + this._aNormalDraw.bindInterleavedFloatArrayBuffer(3, this.core2.interleavedStride, this.core2.interleavedNormalOffset); } if (this._aUVDraw && !ctx.uvBuf) { - this._aUVDraw.bindInterleavedFloatArrayBuffer(2, this.core.interleavedStride, this.core.interleavedUVOffset); + this._aUVDraw.bindInterleavedFloatArrayBuffer(2, this.core2.interleavedStride, this.core2.interleavedUVOffset); } if (this._aUV2Draw && !ctx.uv2Buf) { - this._aUV2Draw.bindInterleavedFloatArrayBuffer(2, this.core.interleavedStride, this.core.interleavedUV2Offset); + this._aUV2Draw.bindInterleavedFloatArrayBuffer(2, this.core2.interleavedStride, this.core2.interleavedUV2Offset); } if (this._aColorDraw && !ctx.colorBuf) { - this._aColorDraw.bindInterleavedFloatArrayBuffer(4, this.core.interleavedStride, this.core.interleavedColorOffset); + this._aColorDraw.bindInterleavedFloatArrayBuffer(4, this.core2.interleavedStride, this.core2.interleavedColorOffset); } } else { if (this._aVertexDraw && !ctx.vertexBuf) { - this._aVertexDraw.bindFloatArrayBuffer(this.core.vertexBuf); + this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf); } if (this._aNormalDraw && !ctx.normalBuf) { - this._aNormalDraw.bindFloatArrayBuffer(this.core.normalBuf); + this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf); } if (this._aUVDraw && !ctx.uvBuf) { - this._aUVDraw.bindFloatArrayBuffer(this.core.uvBuf); + this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf); } if (this._aUV2Draw && !ctx.uvBuf2) { - this._aUV2Draw.bindFloatArrayBuffer(this.core.uvBuf2); + this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2); } if (this._aColorDraw && !ctx.colorBuf) { - this._aColorDraw.bindFloatArrayBuffer(this.core.colorBuf); + this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); } } - this.core.indexBuf.bind(); + this.core2.indexBuf.bind(); }, + morphPick:function (ctx) { + + var targets = this.core.targets; + + if (!targets || targets.length == 0) { + ctx.vertexBuf = false; + ctx.normalBuf = false; + ctx.uvBuf = false; + ctx.uvBuf2 = false; + ctx.colorBuf = false; + return; + } + + var gl = this.program.gl; + + var target1 = targets[this.core.key1]; // Keys will update + var target2 = targets[this.core.key2]; + + if (this._aMorphVertexPick) { + this._aVertexPick.bindFloatArrayBuffer(target1.vertexBuf); + this._aMorphVertexPick.bindFloatArrayBuffer(target2.vertexBuf); + ctx.vertexBuf = true; + } else { + ctx.vertexBuf = false; + } + + if (this._aMorphNormalPick) { + this._aNormalPick.bindFloatArrayBuffer(target1.normalBuf); + this._aMorphNormalPick.bindFloatArrayBuffer(target2.normalBuf); + ctx.normalBuf = true; + } else { + ctx.normalBuf = false; + } + + if (this._aMorphUVPick) { + this._aUVPick.bindFloatArrayBuffer(target1.uvBuf); + this._aMorphUVPick.bindFloatArrayBuffer(target2.uvBuf); + ctx.uvBuf = true; + } else { + ctx.uvBuf = false; + } + + if (this._aMorphUV2Pick) { + this._aUV2Pick.bindFloatArrayBuffer(target1.uvBuf2); + this._aMorphUV2Pick.bindFloatArrayBuffer(target2.uvBuf2); + ctx.uvBuf2 = true; + } else { + ctx.uvBuf2 = false; + } + + if (this._aMorphColorPick) { + this._aColorPick.bindFloatArrayBuffer(target1.colorBuf); + this._aMorphColorPick.bindFloatArrayBuffer(target2.colorBuf); + ctx.colorBuf = true; + } else { + ctx.colorBuf = false; + } + + if (this._uMorphFactorPick) { + gl.uniform1f(this._uMorphFactorPick, this.core.factor); // Bind LERP factor + } + }, + pick:function (ctx) { + this.morphPick(ctx); + var gl = this.program.gl; if (this._aVertexPick && !ctx.vertexBuf) { - this._aVertexPick.bindFloatArrayBuffer(this.core.vertexBuf); + this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf); } if (this._aNormalPick && !ctx.normalBuf) { - this._aNormalPick.bindFloatArrayBuffer(this.core.normalBuf); + this._aNormalPick.bindFloatArrayBuffer(this.core2.normalBuf); } if (this._aUVPick && !ctx.uvBuf) { - this._aUVPick.bindFloatArrayBuffer(this.core.uvBuf); + this._aUVPick.bindFloatArrayBuffer(this.core2.uvBuf); } if (this._aUV2Pick && !ctx.uvBuf2) { - this._aUV2Pick.bindFloatArrayBuffer(this.core.uvBuf2); + this._aUV2Pick.bindFloatArrayBuffer(this.core2.uvBuf2); } - this.core.indexBuf.bind(); + this.core2.indexBuf.bind(); } }); diff --git a/src/core/display/chunks/morphGeometryChunk.js b/src/core/display/chunks/morphGeometryChunk.js deleted file mode 100644 index 115196b3..00000000 --- a/src/core/display/chunks/morphGeometryChunk.js +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Create display state chunk type for draw render of material transform - */ -SceneJS_ChunkFactory.createChunkType({ - - type:"morphGeometry", - - build:function () { - - var draw = this.program.draw; - - this._aVertexDraw = draw.getAttribute("SCENEJS_aVertex"); - this._aNormalDraw = draw.getAttribute("SCENEJS_aNormal"); - this._aUVDraw = draw.getAttribute("SCENEJS_aUVCoord"); - this._aUV2Draw = draw.getAttribute("SCENEJS_aUVCoord2"); - this._aColorDraw = draw.getAttribute("SCENEJS_aVertexColor"); - - this._aMorphVertexDraw = draw.getAttribute("SCENEJS_aMorphVertex"); - this._aMorphNormalDraw = draw.getAttribute("SCENEJS_aMorphNormal"); - this._aMorphUVDraw = draw.getAttribute("SCENEJS_aMorphUVCoord"); - this._aMorphUV2Draw = draw.getAttribute("SCENEJS_aMorphUVCoord2"); - this._aMorphColorDraw = draw.getAttribute("SCENEJS_aMorphColor"); - this._uMorphFactorDraw = draw.getUniformLocation("SCENEJS_uMorphFactor"); - - var pick = this.program.pick; - - this._aVertexPick = pick.getAttribute("SCENEJS_aVertex"); - this._aNormalPick = pick.getAttribute("SCENEJS_aNormal"); - this._aUVPick = pick.getAttribute("SCENEJS_aUVCoord"); - this._aUV2Pick = pick.getAttribute("SCENEJS_aUVCoord2"); - this._aColorPick = pick.getAttribute("SCENEJS_aVertexColor"); - - this._aMorphVertexPick = pick.getAttribute("SCENEJS_aMorphVertex"); - this._aMorphNormalPick = pick.getAttribute("SCENEJS_aMorphNormal"); - this._aMorphUVPick = pick.getAttribute("SCENEJS_aMorphUVCoord"); - this._aMorphUV2Pick = pick.getAttribute("SCENEJS_aMorphUVCoord2"); - this._aMorphColorPick = pick.getAttribute("SCENEJS_aMorphColor"); - this._uMorphFactorPick = pick.getUniformLocation("SCENEJS_uMorphFactor"); - }, - - draw:function (ctx) { - - var targets = this.core.targets; - - if (!targets || targets.length == 0) { - ctx.vertexBuf = false; - ctx.normalBuf = false; - ctx.uvBuf = false; - ctx.uvBuf2 = false; - ctx.colorBuf = false; - return; - } - - var gl = this.program.gl; - - var target1 = this.core.targets[this.core.key1]; // Keys will update - var target2 = this.core.targets[this.core.key2]; - - if (this._aMorphVertexDraw) { - this._aVertexDraw.bindFloatArrayBuffer(target1.vertexBuf); - this._aMorphVertexDraw.bindFloatArrayBuffer(target2.vertexBuf); - ctx.vertexBuf = true; - } else { - ctx.vertexBuf = false; - } - - if (this._aMorphNormalDraw) { - this._aNormalDraw.bindFloatArrayBuffer(target1.normalBuf); - this._aMorphNormalDraw.bindFloatArrayBuffer(target2.normalBuf); - ctx.normalBuf = true; - } else { - ctx.normalBuf = false; - } - - if (this._aMorphUVDraw) { - this._aUVDraw.bindFloatArrayBuffer(target1.uvBuf); - this._aMorphUVDraw.bindFloatArrayBuffer(target2.uvBuf); - ctx.uvBuf = true; - } else { - ctx.uvBuf = false; - } - - if (this._aMorphUV2Draw) { - this._aUV2Draw.bindFloatArrayBuffer(target1.uvBuf2); - this._aMorphUV2Draw.bindFloatArrayBuffer(target2.uvBuf2); - ctx.uvBuf2 = true; - } else { - ctx.uvBuf2 = false; - } - - if (this._aMorphColorDraw) { - this._aColorDraw.bindFloatArrayBuffer(target1.colorBuf); - this._aMorphColorDraw.bindFloatArrayBuffer(target2.colorBuf); - ctx.colorBuf = true; - } else { - ctx.colorBuf = false; - } - - if (this._uMorphFactorDraw) { - gl.uniform1f(this._uMorphFactorDraw, this.core.factor); // Bind LERP factor - } - }, - - pick:function (ctx) { - - var targets = this.core.targets; - - if (!targets || targets.length == 0) { - ctx.vertexBuf = false; - ctx.normalBuf = false; - ctx.uvBuf = false; - ctx.uvBuf2 = false; - ctx.colorBuf = false; - return; - } - - var gl = this.program.gl; - - var target1 = targets[this.core.key1]; // Keys will update - var target2 = targets[this.core.key2]; - - if (this._aMorphVertexPick) { - this._aVertexPick.bindFloatArrayBuffer(target1.vertexBuf); - this._aMorphVertexPick.bindFloatArrayBuffer(target2.vertexBuf); - ctx.vertexBuf = true; - } else { - ctx.vertexBuf = false; - } - - if (this._aMorphNormalPick) { - this._aNormalPick.bindFloatArrayBuffer(target1.normalBuf); - this._aMorphNormalPick.bindFloatArrayBuffer(target2.normalBuf); - ctx.normalBuf = true; - } else { - ctx.normalBuf = false; - } - - if (this._aMorphUVPick) { - this._aUVPick.bindFloatArrayBuffer(target1.uvBuf); - this._aMorphUVPick.bindFloatArrayBuffer(target2.uvBuf); - ctx.uvBuf = true; - } else { - ctx.uvBuf = false; - } - - if (this._aMorphUV2Pick) { - this._aUV2Pick.bindFloatArrayBuffer(target1.uvBuf2); - this._aMorphUV2Pick.bindFloatArrayBuffer(target2.uvBuf2); - ctx.uvBuf2 = true; - } else { - ctx.uvBuf2 = false; - } - - if (this._aMorphColorPick) { - this._aColorPick.bindFloatArrayBuffer(target1.colorBuf); - this._aMorphColorPick.bindFloatArrayBuffer(target2.colorBuf); - ctx.colorBuf = true; - } else { - ctx.colorBuf = false; - } - - if (this._uMorphFactorPick) { - gl.uniform1f(this._uMorphFactorPick, this.core.factor); // Bind LERP factor - } - } -}); diff --git a/src/core/display/display.js b/src/core/display/display.js index a5bdd6f7..16d46d7b 100644 --- a/src/core/display/display.js +++ b/src/core/display/display.js @@ -428,13 +428,12 @@ SceneJS_Display.prototype.buildObject = function (objectId) { this._setChunk(object, 15, "cubemap", this.cubemap); this._setChunk(object, 16, "framebuf", this.framebuf); this._setChunk(object, 17, "clips", this.clips); - this._setChunk(object, 18, "morphGeometry", this.morphGeometry); + this._setChunk(object, 18, "geometry", this.morphGeometry, this.geometry); this._setChunk(object, 19, "listeners", this.renderListeners); // Must be after the above chunks - this._setChunk(object, 20, "geometry", this.geometry); - this._setChunk(object, 21, "draw", this.geometry); // Must be last + this._setChunk(object, 20, "draw", this.geometry); // Must be last }; -SceneJS_Display.prototype._setChunk = function (object, order, chunkType, core, unique) { +SceneJS_Display.prototype._setChunk = function (object, order, chunkType, core, core2) { var chunkId; var chunkClass = this._chunkFactory.chunkTypes[chunkType]; @@ -462,6 +461,10 @@ SceneJS_Display.prototype._setChunk = function (object, order, chunkType, core, ? '_' + core.stateId : 'p' + object.program.id + '_' + core.stateId; + if (core2) { + chunkId += '__' + core2.stateId; + } + } else { // No core supplied, probably a program. @@ -484,7 +487,7 @@ SceneJS_Display.prototype._setChunk = function (object, order, chunkType, core, this._chunkFactory.putChunk(oldChunk); // Release previous chunk to pool } - object.chunks[order] = this._chunkFactory.getChunk(chunkId, chunkType, object.program, core); // Attach new chunk + object.chunks[order] = this._chunkFactory.getChunk(chunkId, chunkType, object.program, core, core2); // Attach new chunk // Ambient light is global across everything in display, and // can never be disabled, so grab it now because we want to @@ -636,7 +639,7 @@ SceneJS_Display.prototype._buildDrawList = function () { this._lastStateId = this._lastStateId || []; this._lastPickStateId = this._lastPickStateId || []; - for (var i = 0; i < 22; i++) { + for (var i = 0; i < 21; i++) { this._lastStateId[i] = null; this._lastPickStateId[i] = null; } @@ -750,7 +753,7 @@ SceneJS_Display.prototype._buildDrawList = function () { if (this._xpBufLen > 0) { - for (var i = 0; i < 23; i++) { // TODO: magic number! + for (var i = 0; i < this._lastStateId.length; i++) { this._lastStateId[i] = null; } From 27963677652cbf19ecfd5bbd9ddf6ba919c2af0a Mon Sep 17 00:00:00 2001 From: Olli Etuaho Date: Wed, 25 Jun 2014 18:30:05 +0300 Subject: [PATCH 4/7] Simplify morph geometry handling --- src/core/display/chunks/geometryChunk.js | 138 +++++++++-------------- src/core/display/chunks/programChunk.js | 16 --- src/core/display/display.js | 5 - 3 files changed, 54 insertions(+), 105 deletions(-) diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index bd9d1a95..f54cbe9a 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -38,20 +38,7 @@ SceneJS_ChunkFactory.createChunkType({ this._uMorphFactorPick = pick.getUniformLocation("SCENEJS_uMorphFactor"); }, - morphDraw:function (ctx) { - - var targets = this.core.targets; - - if (!targets || targets.length == 0) { - ctx.vertexBuf = false; - ctx.normalBuf = false; - ctx.uvBuf = false; - ctx.uvBuf2 = false; - ctx.colorBuf = false; - return; - } - - var gl = this.program.gl; + morphDraw:function () { var target1 = this.core.targets[this.core.key1]; // Keys will update var target2 = this.core.targets[this.core.key2]; @@ -59,182 +46,165 @@ SceneJS_ChunkFactory.createChunkType({ if (this._aMorphVertexDraw) { this._aVertexDraw.bindFloatArrayBuffer(target1.vertexBuf); this._aMorphVertexDraw.bindFloatArrayBuffer(target2.vertexBuf); - ctx.vertexBuf = true; - } else { - ctx.vertexBuf = false; + } else if (this._aVertexDraw) { + this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf); } if (this._aMorphNormalDraw) { this._aNormalDraw.bindFloatArrayBuffer(target1.normalBuf); this._aMorphNormalDraw.bindFloatArrayBuffer(target2.normalBuf); - ctx.normalBuf = true; - } else { - ctx.normalBuf = false; + } else if (this._aNormalDraw) { + this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf); } if (this._aMorphUVDraw) { this._aUVDraw.bindFloatArrayBuffer(target1.uvBuf); this._aMorphUVDraw.bindFloatArrayBuffer(target2.uvBuf); - ctx.uvBuf = true; - } else { - ctx.uvBuf = false; + } else if (this._aUVDraw) { + this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf); } if (this._aMorphUV2Draw) { this._aUV2Draw.bindFloatArrayBuffer(target1.uvBuf2); this._aMorphUV2Draw.bindFloatArrayBuffer(target2.uvBuf2); - ctx.uvBuf2 = true; - } else { - ctx.uvBuf2 = false; + } else if (this._aUV2Draw) { + this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2); } if (this._aMorphColorDraw) { this._aColorDraw.bindFloatArrayBuffer(target1.colorBuf); this._aMorphColorDraw.bindFloatArrayBuffer(target2.colorBuf); - ctx.colorBuf = true; - } else { - ctx.colorBuf = false; + } else if (this._aColorDraw) { + this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); } if (this._uMorphFactorDraw) { - gl.uniform1f(this._uMorphFactorDraw, this.core.factor); // Bind LERP factor + this.program.gl.uniform1f(this._uMorphFactorDraw, this.core.factor); // Bind LERP factor } + }, draw:function (ctx) { - this.morphDraw(ctx); - - var gl = this.program.gl; + if (this.core.targets && this.core.targets.length) { + this.morphDraw(); + } else { if (this.core2.interleavedBuf && !this.core2.interleavedBuf.dirty) { this.core2.interleavedBuf.bind(); - if (this._aVertexDraw && !ctx.vertexBuf) { + if (this._aVertexDraw) { this._aVertexDraw.bindInterleavedFloatArrayBuffer(3, this.core2.interleavedStride, this.core2.interleavedPositionOffset); } - if (this._aNormalDraw && !ctx.normalBuf) { + if (this._aNormalDraw) { this._aNormalDraw.bindInterleavedFloatArrayBuffer(3, this.core2.interleavedStride, this.core2.interleavedNormalOffset); } - if (this._aUVDraw && !ctx.uvBuf) { + if (this._aUVDraw) { this._aUVDraw.bindInterleavedFloatArrayBuffer(2, this.core2.interleavedStride, this.core2.interleavedUVOffset); } - if (this._aUV2Draw && !ctx.uv2Buf) { + if (this._aUV2Draw) { this._aUV2Draw.bindInterleavedFloatArrayBuffer(2, this.core2.interleavedStride, this.core2.interleavedUV2Offset); } - if (this._aColorDraw && !ctx.colorBuf) { + if (this._aColorDraw) { this._aColorDraw.bindInterleavedFloatArrayBuffer(4, this.core2.interleavedStride, this.core2.interleavedColorOffset); } } else { - if (this._aVertexDraw && !ctx.vertexBuf) { + if (this._aVertexDraw) { this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf); } - if (this._aNormalDraw && !ctx.normalBuf) { + if (this._aNormalDraw) { this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf); } - if (this._aUVDraw && !ctx.uvBuf) { + if (this._aUVDraw) { this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf); } - if (this._aUV2Draw && !ctx.uvBuf2) { + if (this._aUV2Draw) { this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2); } - if (this._aColorDraw && !ctx.colorBuf) { + if (this._aColorDraw) { this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); } } - this.core2.indexBuf.bind(); - - }, - - morphPick:function (ctx) { + } - var targets = this.core.targets; + this.core2.indexBuf.bind(); - if (!targets || targets.length == 0) { - ctx.vertexBuf = false; - ctx.normalBuf = false; - ctx.uvBuf = false; - ctx.uvBuf2 = false; - ctx.colorBuf = false; - return; - } + }, - var gl = this.program.gl; + morphPick:function () { - var target1 = targets[this.core.key1]; // Keys will update - var target2 = targets[this.core.key2]; + var target1 = this.core.targets[this.core.key1]; // Keys will update + var target2 = this.core.targets[this.core.key2]; if (this._aMorphVertexPick) { this._aVertexPick.bindFloatArrayBuffer(target1.vertexBuf); this._aMorphVertexPick.bindFloatArrayBuffer(target2.vertexBuf); - ctx.vertexBuf = true; - } else { - ctx.vertexBuf = false; + } else if (this._aVertexPick) { + this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf); } if (this._aMorphNormalPick) { this._aNormalPick.bindFloatArrayBuffer(target1.normalBuf); this._aMorphNormalPick.bindFloatArrayBuffer(target2.normalBuf); - ctx.normalBuf = true; - } else { - ctx.normalBuf = false; + } else if (this._aNormalPick) { + this._aNormalPick.bindFloatArrayBuffer(this.core2.normalBuf); } if (this._aMorphUVPick) { this._aUVPick.bindFloatArrayBuffer(target1.uvBuf); this._aMorphUVPick.bindFloatArrayBuffer(target2.uvBuf); - ctx.uvBuf = true; - } else { - ctx.uvBuf = false; + } else if (this._aUVPick) { + this._aUVPick.bindFloatArrayBuffer(this.core2.uvBuf); } if (this._aMorphUV2Pick) { this._aUV2Pick.bindFloatArrayBuffer(target1.uvBuf2); this._aMorphUV2Pick.bindFloatArrayBuffer(target2.uvBuf2); - ctx.uvBuf2 = true; - } else { - ctx.uvBuf2 = false; + } else if (this._aUV2Pick) { + this._aUV2Pick.bindFloatArrayBuffer(this.core2.uvBuf2); } if (this._aMorphColorPick) { this._aColorPick.bindFloatArrayBuffer(target1.colorBuf); this._aMorphColorPick.bindFloatArrayBuffer(target2.colorBuf); - ctx.colorBuf = true; - } else { - ctx.colorBuf = false; + } else if (this._aColorPick) { + this._aColorPick.bindFloatArrayBuffer(this.core2.colorBuf); } if (this._uMorphFactorPick) { - gl.uniform1f(this._uMorphFactorPick, this.core.factor); // Bind LERP factor + this.program.gl.uniform1f(this._uMorphFactorPick, this.core.factor); // Bind LERP factor } + }, pick:function (ctx) { - this.morphPick(ctx); - - var gl = this.program.gl; + if (this.core.targets && this.core.targets.length) { + this.morphPick(); + } else { - if (this._aVertexPick && !ctx.vertexBuf) { + if (this._aVertexPick) { this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf); } - if (this._aNormalPick && !ctx.normalBuf) { + if (this._aNormalPick) { this._aNormalPick.bindFloatArrayBuffer(this.core2.normalBuf); } - if (this._aUVPick && !ctx.uvBuf) { + if (this._aUVPick) { this._aUVPick.bindFloatArrayBuffer(this.core2.uvBuf); } - if (this._aUV2Pick && !ctx.uvBuf2) { + if (this._aUV2Pick) { this._aUV2Pick.bindFloatArrayBuffer(this.core2.uvBuf2); } - this.core2.indexBuf.bind(); + } + + this.core2.indexBuf.bind(); } }); diff --git a/src/core/display/chunks/programChunk.js b/src/core/display/chunks/programChunk.js index 8137a6bb..f1799749 100644 --- a/src/core/display/chunks/programChunk.js +++ b/src/core/display/chunks/programChunk.js @@ -12,14 +12,6 @@ SceneJS_ChunkFactory.createChunkType({ drawProgram.bind(); - /* - * HACK until we have distinct chunk for each VBO (maybe) - */ - frameCtx.vertexBuf = false; - frameCtx.normalBuf = false; - frameCtx.uvBuf = false; - frameCtx.uvBuf2 = false; - frameCtx.colorBuf = false; frameCtx.textureUnit = 0; var gl = this.program.gl; @@ -39,14 +31,6 @@ SceneJS_ChunkFactory.createChunkType({ gl.uniform1i(this._rayPickMode, frameCtx.rayPick); - /* - * HACK until we have distinct chunk for each VBO (maybe) - */ - frameCtx.vertexBuf = false; - frameCtx.normalBuf = false; - frameCtx.uvBuf = false; - frameCtx.uvBuf2 = false; - frameCtx.colorBuf = false; frameCtx.textureUnit = 0; for (var i = 0; i < 10; i++) { diff --git a/src/core/display/display.js b/src/core/display/display.js index 16d46d7b..1770e9fc 100644 --- a/src/core/display/display.js +++ b/src/core/display/display.js @@ -920,11 +920,6 @@ SceneJS_Display.prototype._doDrawList = function (pick, rayPick) { frameCtx.blendEnabled = false; - frameCtx.vertexBuf = false; - frameCtx.normalBuf = false; - frameCtx.uvBuf = false; - frameCtx.uvBuf2 = false; - frameCtx.colorBuf = false; frameCtx.backfaces = true; frameCtx.frontface = "ccw"; frameCtx.pick = !!pick; From 72f42537dcdc23302bec00bc2a86cfeff06f445f Mon Sep 17 00:00:00 2001 From: Olli Etuaho Date: Wed, 25 Jun 2014 19:33:51 +0300 Subject: [PATCH 5/7] Do not try to set morph attributes to values not morphed by the shader Setting color when picking is skipped completely. --- src/core/display/chunks/geometryChunk.js | 39 +++--------------------- 1 file changed, 5 insertions(+), 34 deletions(-) diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index f54cbe9a..8689d1a1 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -17,9 +17,6 @@ SceneJS_ChunkFactory.createChunkType({ this._aMorphVertexDraw = draw.getAttribute("SCENEJS_aMorphVertex"); this._aMorphNormalDraw = draw.getAttribute("SCENEJS_aMorphNormal"); - this._aMorphUVDraw = draw.getAttribute("SCENEJS_aMorphUVCoord"); - this._aMorphUV2Draw = draw.getAttribute("SCENEJS_aMorphUVCoord2"); - this._aMorphColorDraw = draw.getAttribute("SCENEJS_aMorphColor"); this._uMorphFactorDraw = draw.getUniformLocation("SCENEJS_uMorphFactor"); var pick = this.program.pick; @@ -28,13 +25,9 @@ SceneJS_ChunkFactory.createChunkType({ this._aNormalPick = pick.getAttribute("SCENEJS_aNormal"); this._aUVPick = pick.getAttribute("SCENEJS_aUVCoord"); this._aUV2Pick = pick.getAttribute("SCENEJS_aUVCoord2"); - this._aColorPick = pick.getAttribute("SCENEJS_aVertexColor"); this._aMorphVertexPick = pick.getAttribute("SCENEJS_aMorphVertex"); this._aMorphNormalPick = pick.getAttribute("SCENEJS_aMorphNormal"); - this._aMorphUVPick = pick.getAttribute("SCENEJS_aMorphUVCoord"); - this._aMorphUV2Pick = pick.getAttribute("SCENEJS_aMorphUVCoord2"); - this._aMorphColorPick = pick.getAttribute("SCENEJS_aMorphColor"); this._uMorphFactorPick = pick.getUniformLocation("SCENEJS_uMorphFactor"); }, @@ -57,24 +50,15 @@ SceneJS_ChunkFactory.createChunkType({ this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf); } - if (this._aMorphUVDraw) { - this._aUVDraw.bindFloatArrayBuffer(target1.uvBuf); - this._aMorphUVDraw.bindFloatArrayBuffer(target2.uvBuf); - } else if (this._aUVDraw) { + if (this._aUVDraw) { this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf); } - if (this._aMorphUV2Draw) { - this._aUV2Draw.bindFloatArrayBuffer(target1.uvBuf2); - this._aMorphUV2Draw.bindFloatArrayBuffer(target2.uvBuf2); - } else if (this._aUV2Draw) { + if (this._aUV2Draw) { this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2); } - if (this._aMorphColorDraw) { - this._aColorDraw.bindFloatArrayBuffer(target1.colorBuf); - this._aMorphColorDraw.bindFloatArrayBuffer(target2.colorBuf); - } else if (this._aColorDraw) { + if (this._aColorDraw) { this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); } @@ -154,27 +138,14 @@ SceneJS_ChunkFactory.createChunkType({ this._aNormalPick.bindFloatArrayBuffer(this.core2.normalBuf); } - if (this._aMorphUVPick) { - this._aUVPick.bindFloatArrayBuffer(target1.uvBuf); - this._aMorphUVPick.bindFloatArrayBuffer(target2.uvBuf); - } else if (this._aUVPick) { + if (this._aUVPick) { this._aUVPick.bindFloatArrayBuffer(this.core2.uvBuf); } - if (this._aMorphUV2Pick) { - this._aUV2Pick.bindFloatArrayBuffer(target1.uvBuf2); - this._aMorphUV2Pick.bindFloatArrayBuffer(target2.uvBuf2); - } else if (this._aUV2Pick) { + if (this._aUV2Pick) { this._aUV2Pick.bindFloatArrayBuffer(this.core2.uvBuf2); } - if (this._aMorphColorPick) { - this._aColorPick.bindFloatArrayBuffer(target1.colorBuf); - this._aMorphColorPick.bindFloatArrayBuffer(target2.colorBuf); - } else if (this._aColorPick) { - this._aColorPick.bindFloatArrayBuffer(this.core2.colorBuf); - } - if (this._uMorphFactorPick) { this.program.gl.uniform1f(this._uMorphFactorPick, this.core.factor); // Bind LERP factor } From b52cd7cd26af6cd7a6378843e1057c00ca304ed2 Mon Sep 17 00:00:00 2001 From: Olli Etuaho Date: Wed, 25 Jun 2014 20:10:23 +0300 Subject: [PATCH 6/7] Use VAO on the refactored geometry+morphGeometry chunk The VAO reference is stored on the geometry chunk, which now handles both morph geometry and regular geometry. If the interleaved buffer is dirtied and the VAO references it, it is reconstructed based on the regular buffers. It is also reconstructed when the morph geometry keys change, and reset if the chunk is rebuilt. Performance improvement is similar to the earlier VAO patch, but it also applies to morph geometry. There's also the benefit that we don't need to switch back to the default VAO after every draw call. --- src/core/display/chunks/chunkFactory.js | 6 +++- src/core/display/chunks/geometryChunk.js | 46 +++++++++++++++++++++--- src/core/display/chunks/programChunk.js | 4 +++ src/core/display/display.js | 14 +++++++- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/core/display/chunks/chunkFactory.js b/src/core/display/chunks/chunkFactory.js index 46ca2da4..e7b8fc40 100644 --- a/src/core/display/chunks/chunkFactory.js +++ b/src/core/display/chunks/chunkFactory.js @@ -113,6 +113,10 @@ SceneJS_ChunkFactory.prototype.putChunk = function (chunk) { if (--chunk.useCount <= 0) { // Release shared core if use count now zero + if (chunk.recycle) { + chunk.recycle(); + } + this._chunks[chunk.id] = null; var freeChunks = SceneJS_ChunkFactory._freeChunks[chunk.type]; @@ -122,7 +126,7 @@ SceneJS_ChunkFactory.prototype.putChunk = function (chunk) { }; /** - * Re-cache shader variable locations for each active chunk + * Re-cache shader variable locations for each active chunk and reset VAOs if any */ SceneJS_ChunkFactory.prototype.webglRestored = function () { diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index 8689d1a1..3b8a6717 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -29,9 +29,25 @@ SceneJS_ChunkFactory.createChunkType({ this._aMorphVertexPick = pick.getAttribute("SCENEJS_aMorphVertex"); this._aMorphNormalPick = pick.getAttribute("SCENEJS_aMorphNormal"); this._uMorphFactorPick = pick.getUniformLocation("SCENEJS_uMorphFactor"); + + this.VAO = null; + this.VAOMorphKey1 = 0; + this.VAOMorphKey2 = 0; + this.VAOHasInterleavedBuf = false; + }, + + recycle:function () { + if (this.VAO) { + // Guarantee that the old VAO is deleted immediately when recycling the object. + var VAOExt = this.program.gl.getExtension("OES_vertex_array_object"); + VAOExt.deleteVertexArrayOES(this.VAO); + this.VAO = null; + } }, morphDraw:function () { + this.VAOMorphKey1 = this.core.key1; + this.VAOMorphKey2 = this.core.key2; var target1 = this.core.targets[this.core.key1]; // Keys will update var target2 = this.core.targets[this.core.key2]; @@ -62,6 +78,11 @@ SceneJS_ChunkFactory.createChunkType({ this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); } + this.setDrawMorphFactor(); + }, + + setDrawMorphFactor:function () { + if (this._uMorphFactorDraw) { this.program.gl.uniform1f(this._uMorphFactorDraw, this.core.factor); // Bind LERP factor } @@ -69,12 +90,29 @@ SceneJS_ChunkFactory.createChunkType({ }, draw:function (ctx) { + var doMorph = this.core.targets && this.core.targets.length; + var cleanInterleavedBuf = this.core2.interleavedBuf && !this.core2.interleavedBuf.dirty; + + if (this.VAO) { + ctx.VAO.bindVertexArrayOES(this.VAO); + if (doMorph) { + if (this.VAOMorphKey1 == this.core.key1 && this.VAOMorphKey2 == this.core.key2) { + this.setDrawMorphFactor(); + return; + } + } else if (cleanInterleavedBuf || !this.VAOHasInterleavedBuf) { + return; + } + } else if (ctx.VAO) { + this.VAO = ctx.VAO.createVertexArrayOES(); + ctx.VAO.bindVertexArrayOES(this.VAO); + } - if (this.core.targets && this.core.targets.length) { + if (doMorph) { this.morphDraw(); } else { - - if (this.core2.interleavedBuf && !this.core2.interleavedBuf.dirty) { + if (cleanInterleavedBuf) { + this.VAOHasInterleavedBuf = true; this.core2.interleavedBuf.bind(); if (this._aVertexDraw) { this._aVertexDraw.bindInterleavedFloatArrayBuffer(3, this.core2.interleavedStride, this.core2.interleavedPositionOffset); @@ -92,6 +130,7 @@ SceneJS_ChunkFactory.createChunkType({ this._aColorDraw.bindInterleavedFloatArrayBuffer(4, this.core2.interleavedStride, this.core2.interleavedColorOffset); } } else { + this.VAOHasInterleavedBuf = false; if (this._aVertexDraw) { this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf); } @@ -112,7 +151,6 @@ SceneJS_ChunkFactory.createChunkType({ this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); } } - } this.core2.indexBuf.bind(); diff --git a/src/core/display/chunks/programChunk.js b/src/core/display/chunks/programChunk.js index f1799749..ec2284da 100644 --- a/src/core/display/chunks/programChunk.js +++ b/src/core/display/chunks/programChunk.js @@ -16,6 +16,10 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; + if (frameCtx.VAO) { + frameCtx.VAO.bindVertexArrayOES(null); + } + for (var i = 0; i < 10; i++) { gl.disableVertexAttribArray(i); } diff --git a/src/core/display/display.js b/src/core/display/display.js index 1770e9fc..5767e936 100644 --- a/src/core/display/display.js +++ b/src/core/display/display.js @@ -273,7 +273,8 @@ var SceneJS_Display = function (cfg) { */ this._frameCtx = { pickNames:[], // Pick names of objects hit during pick render - canvas:this._canvas // The canvas + canvas:this._canvas, // The canvas + VAO:null // Vertex array object extension }; /* The frame context has this facade which is given to scene node "rendered" listeners @@ -929,6 +930,13 @@ SceneJS_Display.prototype._doDrawList = function (pick, rayPick) { frameCtx.transparencyPass = false; + // The extension needs to be re-queried in case the context was lost and + // has been recreated. + var VAO = gl.getExtension("OES_vertex_array_object"); + if (VAO) { + frameCtx.VAO = VAO; + } + gl.viewport(0, 0, this._canvas.canvas.width, this._canvas.canvas.height); if (this.transparent) { gl.clearColor(0,0,0,0); @@ -988,6 +996,10 @@ SceneJS_Display.prototype._doDrawList = function (pick, rayPick) { if (frameCtx.renderer) { // Forget last call-time renderer properties // frameCtx.renderer.props.restoreProps(gl); } + + if (frameCtx.VAO) { + frameCtx.VAO.bindVertexArrayOES(null); + } }; SceneJS_Display.prototype.destroy = function () { From 963d61d5ff487c8e4d607033d5b37aa9d02b7594 Mon Sep 17 00:00:00 2001 From: Olli Etuaho Date: Thu, 26 Jun 2014 16:35:36 +0300 Subject: [PATCH 7/7] Only disable vertex attrib arrays when not using VAOs This saves on disableVertexAttribArray calls. They are always disabled at the end of doDrawList since picking still enables arrays on the default VAO. --- src/core/display/chunks/geometryChunk.js | 3 +++ src/core/display/chunks/programChunk.js | 10 ++++------ src/core/display/display.js | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index 3b8a6717..ce34e339 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -104,8 +104,11 @@ SceneJS_ChunkFactory.createChunkType({ return; } } else if (ctx.VAO) { + // Start creating a new VAO by switching to the default VAO, which doesn't have attribs enabled. + ctx.VAO.bindVertexArrayOES(null); this.VAO = ctx.VAO.createVertexArrayOES(); ctx.VAO.bindVertexArrayOES(this.VAO); + var gl = this.program.gl; } if (doMorph) { diff --git a/src/core/display/chunks/programChunk.js b/src/core/display/chunks/programChunk.js index ec2284da..359ddec3 100644 --- a/src/core/display/chunks/programChunk.js +++ b/src/core/display/chunks/programChunk.js @@ -16,12 +16,10 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; - if (frameCtx.VAO) { - frameCtx.VAO.bindVertexArrayOES(null); - } - - for (var i = 0; i < 10; i++) { - gl.disableVertexAttribArray(i); + if (!frameCtx.VAO) { + for (var i = 0; i < 10; i++) { + gl.disableVertexAttribArray(i); + } } }, diff --git a/src/core/display/display.js b/src/core/display/display.js index 5767e936..a8744fbc 100644 --- a/src/core/display/display.js +++ b/src/core/display/display.js @@ -999,6 +999,9 @@ SceneJS_Display.prototype._doDrawList = function (pick, rayPick) { if (frameCtx.VAO) { frameCtx.VAO.bindVertexArrayOES(null); + for (var i = 0; i < 10; i++) { + gl.disableVertexAttribArray(i); + } } };