Skip to content

Commit

Permalink
Merge pull request #156 from gopro/multiresolution-improvement
Browse files Browse the repository at this point in the history
Multiresolution stabilization
  • Loading branch information
benjamin committed Oct 30, 2017
2 parents a718297 + 9669d2b commit 8f8fc39
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 48 deletions.
5 changes: 5 additions & 0 deletions externs/lib/three.ext.js
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,11 @@ THREE.Raycaster.prototype.intersectObjects = function(arg1) {};
*/
THREE.Scene = function() {};

/**
* @param {THREE.Object3D} arg1
*/
THREE.Scene.prototype.getObjectByName = function(arg1) {};

/**
* @constructor
* @param {(Element|HTMLElement)=} arg1
Expand Down
81 changes: 60 additions & 21 deletions src/3d/Tile.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ FORGE.Tile = function(parent, renderer, x, y, level, face, creator)
this._opacity = 0;

/**
* Texture load pending flag
* @name FORGE.Tile#_texturePending
* Texture set flag
* @name FORGE.Tile#_textureIsSet
* @type {boolean}
* @private
*/
this._texturePending = false;
this._textureIsSet = false;

/**
* Event dispatcher for destroy.
Expand Down Expand Up @@ -214,6 +214,11 @@ FORGE.Tile.FACE_NEXT = {
FORGE.Tile.createName = function(face, level, x, y)
{
face = typeof face === "number" ? FORGE.Tile.FACES[face] : face.toLowerCase();
if (level === FORGE.Tile.PREVIEW)
{
return face.substring(0, 1).toUpperCase() + "-preview";
}

return face.substring(0, 1).toUpperCase() + "-" + level + "-" + y + "-" + x;
};

Expand Down Expand Up @@ -250,7 +255,7 @@ FORGE.Tile.prototype._boot = function()
this._checkParent();
}

this.renderOrder = this._level === FORGE.Tile.PREVIEW ? 0 : this._level + 1;
this.renderOrder = this._level === FORGE.Tile.PREVIEW ? 0 : 2 * (this._level + 1);
this.onBeforeRender = this._onBeforeRender.bind(this);
this.onAfterRender = this._onAfterRender.bind(this);

Expand Down Expand Up @@ -291,7 +296,7 @@ FORGE.Tile.prototype._onBeforeRender = function()
// Add to renderer render list
this._renderer.addToRenderList(this);

if (this._texturePending === true)
if (this._textureIsSet === true)
{
this._setOpacity(1);
}
Expand All @@ -312,16 +317,33 @@ FORGE.Tile.prototype._onBeforeRender = function()
FORGE.Tile.prototype._onAfterRender = function()
{
// Update last display timestamp
this._displayTS = Date.now();
this.refreshDisplayTS();

// Check if tile should be divided
if (this._renderer.level > this._level)
if (this._level !== FORGE.Tile.PREVIEW)
{
this._subdivide();
}
// Check if tile should be divided
if (this._renderer.level > this._level)
{
this._subdivide();

// Restoration process for required tiles previously removed from the scene
// Check if children are intersecting the frustum and add them back to the
// scene (with refreshed display timer)
for (var i=0, ii=this._children.length; i<ii; i++)
{
var child = this._children[i];

// Get all neighbour tiles references
this._checkNeighbours();
if (!this._renderer.isObjectInScene(child) && this._renderer.isObjectInFrustum(child))
{
this._renderer.scene.add(child);
child.refreshDisplayTS();
}
}
}

// Get all neighbour tiles references
this._checkNeighbours();
}

this._queryTexture();
};
Expand All @@ -334,7 +356,7 @@ FORGE.Tile.prototype._onAfterRender = function()
FORGE.Tile.prototype._queryTexture = function()
{
// Update texture mapping
if (this.material !== null && this.material.map === null && this._texturePending === false)
if (this.material !== null && this.material.map === null && this._textureIsSet === false)
{
// Check if predelay since creation has been respected (except for preview)
if ((this._level !== FORGE.Tile.PREVIEW || this._level !== this._renderer.level) &&
Expand All @@ -357,7 +379,7 @@ FORGE.Tile.prototype._queryTexture = function()

if (texture !== null && texture instanceof THREE.Texture)
{
this._texturePending = true;
this._textureIsSet = true;

texture.generateMipmaps = false;
texture.minFilter = THREE.LinearFilter;
Expand Down Expand Up @@ -387,7 +409,6 @@ FORGE.Tile.prototype._addDebugLayer = function()
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 512;
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";

var x = canvas.width / 2;
var y = canvas.height / 2 - 25;
Expand All @@ -412,7 +433,14 @@ FORGE.Tile.prototype._addDebugLayer = function()

ctx.textAlign = "left";
ctx.font = "10px Courier";
ctx.fillText("Level " + this._level, 10, canvas.height - 10);
if (this._level === FORGE.Tile.PREVIEW)
{
ctx.fillText("Preview", 10, canvas.height - 10);
}
else
{
ctx.fillText("Level " + this._level, 10, canvas.height - 10);
}

ctx.textAlign = "right";
ctx.fillText(this._renderer.pixelsAtCurrentLevelHumanReadable, canvas.width - 10, canvas.height - 10);
Expand All @@ -429,6 +457,8 @@ FORGE.Tile.prototype._addDebugLayer = function()
var mesh = new THREE.Mesh(this.geometry.clone(), material);
mesh.name = this.name + "-debug-canvas";
this.add(mesh);

mesh.renderOrder = this.renderOrder + 1;
};

/**
Expand Down Expand Up @@ -540,7 +570,7 @@ FORGE.Tile.prototype._getRotation = function()
*/
FORGE.Tile.prototype._subdivide = function()
{
if (this._children.length === 4)
if (this._children.length > 0)
{
return;
}
Expand Down Expand Up @@ -818,6 +848,15 @@ FORGE.Tile.prototype.getParentName = function()
return FORGE.Tile.createName(this._face, this._level - 1, coords.x, coords.y);
};

/**
* Refresh display timestamp with current date
* @method FORGE.Tile#refreshDisplayTS
*/
FORGE.Tile.prototype.refreshDisplayTS = function()
{
this._displayTS = Date.now();
};

/**
* Destroy sequence
* @method FORGE.Tile#destroy
Expand Down Expand Up @@ -1012,15 +1051,15 @@ Object.defineProperty(FORGE.Tile.prototype, "neighbours",
});

/**
* Is the texture still pending
* @name FORGE.Tile#texturePending
* Is the texture set
* @name FORGE.Tile#textureIsSet
* @type {boolean}
*/
Object.defineProperty(FORGE.Tile.prototype, "texturePending",
Object.defineProperty(FORGE.Tile.prototype, "textureIsSet",
{
/** @this {FORGE.Tile} */
get: function()
{
return this._texturePending;
return this._textureIsSet;
}
});
2 changes: 1 addition & 1 deletion src/camera/Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,7 @@ FORGE.Camera.prototype.lookAt = function(yaw, pitch, roll, fov, durationMS, canc
{
if (typeof durationMS !== "number" || durationMS === 0)
{
var changed = this._setAll(yaw, pitch, roll, fov, FORGE.Math.DEGREES);
var changed = this._setAll(yaw, pitch, roll, fov, FORGE.Math.DEGREES);

if (changed === true)
{
Expand Down
60 changes: 42 additions & 18 deletions src/render/background/BackgroundPyramidRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,16 +357,50 @@ FORGE.BackgroundPyramidRenderer.prototype._clearTiles = function()

this._scene.children.forEach(function(tile)
{
// Tile with level greater than renderer level -> always removed
var tileLevelHigher = tile.level > this._level;

// Tile with level different than renderer level
var tileLevelEqualsCurrent = tile.level === this._level;

// Tile with level different than renderer level
var tileLevelPreview = tile.level === FORGE.Tile.PREVIEW;

// Tile with level different than renderer level
var tileLevelZero = tile.level === 0;

// Only clear tiles from level different from current and higher than preview and zero
var tileLevelClearable = !tileLevelEqualsCurrent && !tileLevelPreview && !tileLevelZero;

// Tile has a texture set in its material map
// Never clear a tile without a texture set to keep parents of the current displayed tile
// available (with their texture) when the user quickly zooms out
var tileHasATexture = tile.textureIsSet === true;

// Tile is part of the neighbour list
var isANeighbourTile = this._renderNeighborList.indexOf(tile) !== -1;

// Tile has never been displayed and time to live delay has been exceeded
var timeSinceCreate = now - tile.createTS;
var timeSinceDisplay = now - tile.displayTS;
var tileNeverDisplayedAndTTLExceeded = tile.displayTS === null
&& timeSinceCreate > FORGE.BackgroundPyramidRenderer.MAX_ALLOWED_TIME_SINCE_CREATION_MS;

if (tile.level > this._level ||
(tile.level !== this._level &&
tile.level > 0 &&
tile.texturePending === true &&
this._renderNeighborList.indexOf(tile) === -1 &&
((tile.displayTS === null && timeSinceCreate > FORGE.BackgroundPyramidRenderer.MAX_ALLOWED_TIME_SINCE_CREATION_MS) ||
(tile.displayTS !== null && timeSinceDisplay > FORGE.BackgroundPyramidRenderer.MAX_ALLOWED_TIME_SINCE_DISPLAY_MS))))
// Tile has been displayed a too long time ago
var timeSinceDisplay = now - tile.displayTS;
var tileNotDisplayedRecentlyEnough = tile.displayTS !== null
&& timeSinceDisplay > FORGE.BackgroundPyramidRenderer.MAX_ALLOWED_TIME_SINCE_DISPLAY_MS;

// Tile is out of delay and could be cleared
// This flag will force clearing tiles with lower levels not displayed for a while
// Tiles at lower level (parents) rendered but hidden by current level tiles should not
// be cleared to keep them available immediatly when zooming out
var tileOutOfDelay = tileNeverDisplayedAndTTLExceeded || tileNotDisplayedRecentlyEnough;

// Always clear all tiles from higher levels (performance and aliasing issues)
// OR
// Clear tiles from lower levels (except preview or zero) AND out of delay
// AND with a texture set AND out of the neighbour list
if (tileLevelHigher || (tileLevelClearable && tileOutOfDelay && tileHasATexture && !isANeighbourTile))
{
clearList.push(tile);
}
Expand Down Expand Up @@ -487,16 +521,6 @@ FORGE.BackgroundPyramidRenderer.prototype.tileSize = function(level)
return new FORGE.Size(this._size / this.nbTilesPerAxis(level, "x"), this._size / this.nbTilesPerAxis(level, "y"));
};

/**
* Remove tile from the scene
* @method FORGE.BackgroundPyramidRenderer#removeFromScene
* @param {FORGE.Tile} tile
*/
FORGE.BackgroundPyramidRenderer.prototype.removeFromScene = function(tile)
{
this._scene.remove(tile);
};

/**
* Select current level for the pyramid
* @method FORGE.BackgroundPyramidRenderer#selectLevel
Expand Down
55 changes: 47 additions & 8 deletions src/render/background/BackgroundRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ FORGE.BackgroundRenderer = function(viewer, target, options, type)
*/
this._camera = null;

/**
* @name FORGE.BackgroundRenderer#_frustum
* @type {THREE.Frustum}
* @private
*/
this._frustum = null;

/**
* Media format (cubemap, equi...)
* @type {string}
Expand Down Expand Up @@ -93,6 +100,8 @@ FORGE.BackgroundRenderer.prototype._boot = function()

this._renderTarget = new THREE.WebGLRenderTarget(width, height, rtParams);
}

this._frustum = new THREE.Frustum();
};

/**
Expand Down Expand Up @@ -184,14 +193,29 @@ FORGE.BackgroundRenderer.prototype.render = function(camera)

this._updateTexture();

if (camera !== null)
{
this._viewer.renderer.webGLRenderer.render ( this._scene, camera, this._renderTarget, true );
}
else
{
this._viewer.renderer.webGLRenderer.render ( this._scene, this._camera, this._renderTarget, true );
}
var renderCamera = (camera !== null) ? camera : this._camera;
this._frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices( renderCamera.projectionMatrix, renderCamera.matrixWorldInverse ) );
this._viewer.renderer.webGLRenderer.render ( this._scene, renderCamera, this._renderTarget, true );
};

/**
* Check if some 3D object is interesecting the rendering frustum.
* @method FORGE.BackgroundRenderer#isObjectInFrustum
* @param {THREE.Object3D} object - 3D object
*/
FORGE.BackgroundRenderer.prototype.isObjectInFrustum = function(object)
{
return this._frustum.intersectsObject(object);
};

/**
* Check if some 3D object is in the scene
* @method FORGE.BackgroundRenderer#isObjectInScene
* @param {THREE.Object3D} object - 3D object
*/
FORGE.BackgroundRenderer.prototype.isObjectInScene = function(object)
{
return this._scene.getObjectByName(object.name) !== undefined;
};

/**
Expand Down Expand Up @@ -233,6 +257,7 @@ FORGE.BackgroundRenderer.prototype.update = function()
FORGE.BackgroundRenderer.prototype.destroy = function()
{
this._camera = null;
this._frustum = null;

if (this._renderTarget !== null)
{
Expand Down Expand Up @@ -331,3 +356,17 @@ Object.defineProperty(FORGE.BackgroundRenderer.prototype, "scene",
return this._scene;
}
});

/**
* Get camera frustum.
* @name FORGE.BackgroundRenderer#frustum
* @type {THREE.Frustum}
*/
Object.defineProperty(FORGE.BackgroundRenderer.prototype, "frustum",
{
/** @this {FORGE.BackgroundRenderer} */
get: function()
{
return this._frustum;
}
});

0 comments on commit 8f8fc39

Please sign in to comment.