From c979ff362ed8d39f05286bd22ddbb75cc8e47a9a Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Sun, 4 Mar 2018 11:23:07 -0500 Subject: [PATCH 1/2] Add background color support for multires panoramas. --- doc/json-config-parameters.md | 11 ++++++----- src/js/libpannellum.js | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/doc/json-config-parameters.md b/doc/json-config-parameters.md index 7630a3d..93fc31c 100644 --- a/doc/json-config-parameters.md +++ b/doc/json-config-parameters.md @@ -303,6 +303,12 @@ WebGL renderer. Specifies the key numbers that are captured in key events. Defaults to the standard keys that are used by the viewer. +### `backgroundColor` ([number, number, number]) + +Specifies an array containing RGB values [0, 1] that sets the background color +shown past the edges of a partial panorama. Defaults to `[0, 0, 0]` (black). +Does not work for `cubemap` panoramas. + ## `equirectangular` specific options @@ -336,11 +342,6 @@ and the equirectangular image is not cropped symmetrically. If set to `true`, any embedded Photo Sphere XMP data will be ignored; else, said data will override any existing settings. Defaults to `false`. -### `backgroundColor` ([number, number, number]) - -Specifies an array containing RGB values [0, 1] that sets the background color -shown past the edges of a partial panorama. Defaults to `[0, 0, 0]` (black). - ## `cubemap` specific options diff --git a/src/js/libpannellum.js b/src/js/libpannellum.js index 5dc09d0..1ea12af 100644 --- a/src/js/libpannellum.js +++ b/src/js/libpannellum.js @@ -321,6 +321,11 @@ function Renderer(container) { program.drawInProgress = false; + // Set background clear color + var color = params.backgroundColor ? params.backgroundColor : [0, 0, 0]; + gl.clearColor(color[0], color[1], color[2], 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + // Look up texture coordinates location program.texCoordLocation = gl.getAttribLocation(program, 'a_texCoord'); gl.enableVertexAttribArray(program.texCoordLocation); @@ -354,7 +359,6 @@ function Renderer(container) { // Set background color if (imageType == 'equirectangular') { program.backgroundColor = gl.getUniformLocation(program, 'u_backgroundColor'); - var color = params.backgroundColor ? params.backgroundColor : [0, 0, 0]; gl.uniform4fv(program.backgroundColor, color.concat([1])); } @@ -707,8 +711,9 @@ function Renderer(container) { function multiresDraw() { if (!program.drawInProgress) { program.drawInProgress = true; + gl.clear(gl.COLOR_BUFFER_BIT); for ( var i = 0; i < program.currentNodes.length; i++ ) { - if (program.currentNodes[i].textureLoaded) { + if (program.currentNodes[i].textureLoaded > 1) { //var color = program.currentNodes[i].color; //gl.uniform4f(program.colorUniform, color[0], color[1], color[2], 1.0); @@ -1035,9 +1040,12 @@ function Renderer(container) { this.image = new Image(); this.image.crossOrigin = crossOrigin ? crossOrigin : 'anonymous'; var loadFn = (function() { - if (self.image.width > 0 && self.image.height > 0) // ignore missing tile to supporting partial image + if (self.image.width > 0 && self.image.height > 0) { // ignore missing tile to supporting partial image processLoadedTexture(self.image, self.texture); - self.callback(self.texture); + self.callback(self.texture, true); + } else { + self.callback(self.texture, false); + } releaseTextureImageLoader(self); }); this.image.addEventListener('load', loadFn); @@ -1086,9 +1094,9 @@ function Renderer(container) { function processNextTile(node) { if (!node.textureLoad) { node.textureLoad = true; - loadTexture(encodeURI(node.path + '.' + image.extension), function(texture) { + loadTexture(encodeURI(node.path + '.' + image.extension), function(texture, loaded) { node.texture = texture; - node.textureLoaded = true; + node.textureLoaded = loaded ? 2 : 1; }, globalParams.crossOrigin); } } From edc587cd894c41c9f0692cd1e37c89a17f21564f Mon Sep 17 00:00:00 2001 From: David von Oheimb Date: Sun, 11 Mar 2018 03:33:51 +0100 Subject: [PATCH 2/2] avoid showing out-of-range areas of partial (cylindrical) panoramas (#567) * prevent display of out-of-range areas of partial (cylindrical) panoramas by adaping min/may yaw and max horizontal fov, this no background (empty space) shown * improvements as requested: made view restrictions optional, etc. * extend documentation to describe new avoidShowingBackground option --- doc/json-config-parameters.md | 8 ++++++++ src/js/pannellum.js | 47 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/doc/json-config-parameters.md b/doc/json-config-parameters.md index 93fc31c..2820619 100644 --- a/doc/json-config-parameters.md +++ b/doc/json-config-parameters.md @@ -309,6 +309,14 @@ Specifies an array containing RGB values [0, 1] that sets the background color shown past the edges of a partial panorama. Defaults to `[0, 0, 0]` (black). Does not work for `cubemap` panoramas. +### `avoidShowingBackground` (boolean) + +If set to `true`, prevent displaying out-of-range areas of a partial panorama +by constraining the yaw and the field-of-view. Even at the corners and edges +of the canvas only areas actually belonging to the image +(i.e., within [`minYaw`, `maxYaw`] and [`minPitch`, `maxPitch`]) are shown, +thus setting the `backgroundColor` option is not needed if this option is set. +Defaults to `false`. ## `equirectangular` specific options diff --git a/src/js/pannellum.js b/src/js/pannellum.js index 3aa74a9..adc22e5 100644 --- a/src/js/pannellum.js +++ b/src/js/pannellum.js @@ -99,6 +99,7 @@ var defaultConfig = { orientationOnByDefault: false, hotSpotDebug: false, backgroundColor: [0, 0, 0], + avoidShowingBackground: false, animationTimingFunction: timingFunction, draggable: true, disableKeyboardCtrl: false, @@ -500,6 +501,7 @@ function onImageLoad() { } renderInit(); + setHfov(config.hfov); // possibly adapt hfov after configuration and canvas is complete; prevents empty space on top or bottom by zomming out too much setTimeout(function(){isTimedOut = true;}, 500); } @@ -1400,23 +1402,41 @@ function render() { // Keep a tmp value of yaw for autoRotate comparison later tmpyaw = config.yaw; + // Optionally avoid showing background (empty space) on left or right by adapting min/max yaw + var hoffcut = 0, + voffcut = 0; + if (config.avoidShowingBackground) { + var canvas = renderer.getCanvas(), + hfov2 = config.hfov / 2, + vfov2 = Math.atan2(Math.tan(hfov2 / 180 * Math.PI), (canvas.width / canvas.height)) * 180 / Math.PI, + transposed = config.vaov > config.haov; + if (transposed) { + voffcut = vfov2 * (1 - Math.min(Math.cos((config.pitch - hfov2) / 180 * Math.PI), + Math.cos((config.pitch + hfov2) / 180 * Math.PI))); + } else { + hoffcut = hfov2 * (1 - Math.min(Math.cos((config.pitch - vfov2) / 180 * Math.PI), + Math.cos((config.pitch + vfov2) / 180 * Math.PI))); + } + } + // Ensure the yaw is within min and max allowed var yawRange = config.maxYaw - config.minYaw, minYaw = -180, maxYaw = 180; if (yawRange < 360) { - minYaw = config.minYaw + config.hfov / 2; - maxYaw = config.maxYaw - config.hfov / 2; + minYaw = config.minYaw + config.hfov / 2 + hoffcut; + maxYaw = config.maxYaw - config.hfov / 2 - hoffcut; if (yawRange < config.hfov) { // Lock yaw to average of min and max yaw when both can be seen at once minYaw = maxYaw = (minYaw + maxYaw) / 2; } + config.yaw = Math.max(minYaw, Math.min(maxYaw, config.yaw)); } - config.yaw = Math.max(minYaw, Math.min(maxYaw, config.yaw)); // Check if we autoRotate in a limited by min and max yaw // If so reverse direction - if (config.autoRotate !== false && tmpyaw != config.yaw) { + if (config.autoRotate !== false && tmpyaw != config.yaw && + prevTime !== undefined) { // this condition prevents changing the direction initially config.autoRotate *= -1; } @@ -2117,13 +2137,24 @@ function constrainHfov(hfov) { // Don't change view if bounds don't make sense console.log('HFOV bounds do not make sense (minHfov > maxHfov).') return config.hfov; - } if (hfov < minHfov) { - return minHfov; + } + var newHfov = config.hfov; + if (hfov < minHfov) { + newHfov = minHfov; } else if (hfov > config.maxHfov) { - return config.maxHfov; + newHfov = config.maxHfov; } else { - return hfov; + newHfov = hfov; + } + // Optionally avoid showing background (empty space) on top or bottom by adapting newHfov + if (config.avoidShowingBackground && renderer) { + var canvas = renderer.getCanvas(); + newHfov = Math.min(newHfov, + Math.atan(Math.tan((config.maxPitch - config.minPitch) / 360 * Math.PI) / + canvas.height * canvas.width) + * 360 / Math.PI); } + return newHfov; } /**