Browse Source

Make CSS 3D renderer work with cubemaps, fix its edge flickering bug, and remove need for extra row of pixels in multires fallback images.

pull/54/head
Matthew Petroff 9 years ago
parent
commit
b268d29c42
4 changed files with 76 additions and 64 deletions
  1. +2
    -35
      src/css/pannellum.css
  2. +67
    -11
      src/js/libpannellum.js
  3. +6
    -6
      src/pannellum.htm
  4. +1
    -12
      utils/multires/generate.py

+ 2
- 35
src/css/pannellum.css View File

@@ -320,52 +320,19 @@ div.tooltip:hover:after {
overflow: hidden;
width: 100%;
height: 100%;
-webkit-perspective: 700px;
perspective: 700px;
}
.world {
display: none;
position: absolute;
left: 50%;
top: 50%;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transform: translate3d(0px, 0px, 700px) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
transform: translate3d(0px, 0px, 700px) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
}
.face {
position: absolute;
-webkit-transform-origin: 0 0 0;
transform-origin: 0 0 0;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
height: 1002px;
width: 1002px;
background-size: 100% 100%;
}
.fface {
-webkit-transform: translate3d(-501px, -501px, -500px) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
transform: translate3d(-501px, -501px, -500px) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
}
.bface {
-webkit-transform: translate3d(501px, -501px, 500px) rotateX(180deg) rotateY(0deg) rotateZ(180deg);
transform: translate3d(501px, -501px, 500px) rotateX(180deg) rotateY(0deg) rotateZ(180deg);
}
.uface {
-webkit-transform: translate3d(-501px, -500px, 501px) rotateX(270deg) rotateY(0deg) rotateZ(0deg);
transform: translate3d(-501px, -500px, 501px) rotateX(270deg) rotateY(0deg) rotateZ(0deg);
}
.dface {
-webkit-transform: translate3d(-501px, 500px, -501px) rotateX(90deg) rotateY(0deg) rotateZ(0deg);
transform: translate3d(-501px, 500px, -501px) rotateX(90deg) rotateY(0deg) rotateZ(0deg);
}
.lface {
-webkit-transform: translate3d(-500px, -501px, 501px) rotateX(180deg) rotateY(90deg) rotateZ(180deg);
transform: translate3d(-500px, -501px, 501px) rotateX(180deg) rotateY(90deg) rotateZ(180deg);
}
.rface {
-webkit-transform: translate3d(500px, -501px, -501px) rotateX(0deg) rotateY(270deg) rotateZ(0deg);
transform: translate3d(500px, -501px, -501px) rotateX(0deg) rotateY(270deg) rotateZ(0deg);
height: 1004px;
width: 1004px;
}

.dragfix, #preview {


+ 67
- 11
src/js/libpannellum.js View File

@@ -53,7 +53,7 @@ function Renderer(container, image, imageType, video) {
// If there is no WebGL, fall back to CSS 3D transform renderer.
// While browser specific tests are usually frowned upon, the
// fallback viewer only really works with WebKit/Blink
if (!gl && this.imageType == 'multires' && this.image.fallbackPath && 'WebkitAppearance' in document.documentElement.style) {
if (!gl && ((this.imageType == 'multires' && this.image.fallbackPath) || this.imageType == 'cubemap') && 'WebkitAppearance' in document.documentElement.style) {
// Initialize renderer
container.className = 'viewport';
this.world = container.querySelector('.world');
@@ -61,9 +61,52 @@ function Renderer(container, image, imageType, video) {
// Add images
var path = this.image.basePath + this.image.fallbackPath;
var sides = ['f', 'b', 'u', 'd', 'l', 'r'];
var sides = ['f', 'r', 'b', 'l', 'u', 'd'];
for (s = 0; s < 6; s++) {
this.world.querySelector('.' + sides[s] + 'face').style.backgroundImage = 'url("' + path.replace('%s',sides[s]) + '.' + this.image.extension + '")';
var faceImg = new Image();
var world = this.world;
faceImg.crossOrigin = 'anonymous';
faceImg.side = s;
faceImg.onload = function() {
// Draw image on canvas
var faceCanvas = world.querySelector('.' + sides[this.side] + 'face');
var faceContext = faceCanvas.getContext('2d');
faceCanvas.width = this.width + 2;
faceCanvas.height = this.height + 2;
faceContext.drawImage(this, 1, 1);
var imgData = faceContext.getImageData(0, 0, faceCanvas.width, faceCanvas.height);
var data = imgData.data;
// Duplicate edge pixels
var i;
var j;
for (i = 1; i < faceCanvas.width - 1; i++) {
for (j = 0; j < 4; j++) {
data[i * 4 + j] = data[(i + faceCanvas.width) * 4 + j];
data[(i + faceCanvas.width * (faceCanvas.height - 1)) * 4 + j] = data[(i + faceCanvas.width * (faceCanvas.height - 2)) * 4 + j];
}
}
for (i = 1; i < faceCanvas.height - 1; i++) {
for (j = 0; j < 4; j++) {
data[(i * faceCanvas.width) * 4 + j] = data[(i * faceCanvas.width + 1) * 4 + j];
data[((i + 1) * faceCanvas.width - 1) * 4 + j] = data[((i + 1) * faceCanvas.width - 2) * 4 + j];
}
}
for (j = 0; j < 4; j++) {
data[j] = data[(faceCanvas.width + 1) * 4 + j];
data[(faceCanvas.width - 1) * 4 + j] = data[(faceCanvas.width * 2 - 2) * 4 + j];
data[(faceCanvas.width * (faceCanvas.height - 1)) * 4 + j] = data[(faceCanvas.width * (faceCanvas.height - 2) + 1) * 4 + j];
data[(faceCanvas.width * faceCanvas.height - 1) * 4 + j] = data[(faceCanvas.width * (faceCanvas.height - 1) - 2) * 4 + j];
}
// Draw image width duplicated edge pixels on canvas
faceContext.putImageData(imgData, 0, 0);
};
if (this.imageType == 'multires') {
faceImg.src = path.replace('%s',sides[s]) + '.' + this.image.extension;
} else {
faceImg.src = this.image[s].src;
}
}
return;
@@ -238,17 +281,30 @@ function Renderer(container, image, imageType, video) {
};

this.render = function(pitch, yaw, hfov) {
var focal;
var focal, i;
// If no WebGL
if (!gl && this.imageType == 'multires') {
if (!gl && (this.imageType == 'multires' || this.imageType == 'cubemap')) {
// Determine face transforms
var transforms = {
f: 'translate3d(-502px, -502px, -500px)',
b: 'translate3d(502px, -502px, 500px) rotateX(180deg) rotateZ(180deg)',
u: 'translate3d(-502px, -500px, 502px) rotateX(270deg)',
d: 'translate3d(-502px, 500px, -502px) rotateX(90deg)',
l: 'translate3d(-500px, -502px, 502px) rotateX(180deg) rotateY(90deg) rotateZ(180deg)',
r: 'translate3d(500px, -502px, -502px) rotateY(270deg)'
};
focal = 1 / Math.tan(hfov / 2);
var zoom = focal * this.canvas.width / 2 + 'px';
var transform = 'translate3d(0px, 0px, ' + zoom + ') rotateX(' + pitch + 'rad) rotateY(' + yaw + 'rad) rotateZ(0rad)';
this.world.style.webkitTransform = transform;
this.world.style.transform = transform;
this.container.style.webkitPerspective = zoom;
this.container.style.perspective = zoom;
var transform = 'perspective(' + zoom + ') translateZ(' + zoom + ') rotateX(' + pitch + 'rad) rotateY(' + yaw + 'rad) ';
// Apply face transforms
var faces = Object.keys(transforms);
for (i = 0; i < 6; i++) {
var face = this.world.querySelector('.' + faces[i] + 'face').style;
face.webkitTransform = transform + transforms[faces[i]];
face.transform = transform + transforms[faces[i]];
}
return;
}
@@ -307,7 +363,7 @@ function Renderer(container, image, imageType, video) {
}
program.currentNodes.sort(this.multiresNodeRenderSort);
// Only process one tile per frame to improve responsiveness
for ( var i = 0; i < program.currentNodes.length; i++ ) {
for (i = 0; i < program.currentNodes.length; i++) {
if (!program.currentNodes[i].texture) {
setTimeout(this.processNextTile(program.currentNodes[i]), 0);
break;


+ 6
- 6
src/pannellum.htm View File

@@ -12,12 +12,12 @@
<div id="container">
<canvas id="canvas"></canvas>
<div class="world">
<div class="face fface"></div>
<div class="face bface"></div>
<div class="face uface"></div>
<div class="face dface"></div>
<div class="face lface"></div>
<div class="face rface"></div>
<canvas class="face fface"></canvas>
<canvas class="face bface"></canvas>
<canvas class="face uface"></canvas>
<canvas class="face dface"></canvas>
<canvas class="face lface"></canvas>
<canvas class="face rface"></canvas>
</div>
</div>
<div class="dragfix"></div>


+ 1
- 12
utils/multires/generate.py View File

@@ -123,18 +123,7 @@ for f in range(0, 6):
os.makedirs(os.path.join(args.output, 'fallback'))
face = Image.open(os.path.join(args.output, faces[f]))
face = face.resize([1024, 1024], Image.ANTIALIAS)
# Create 1px border by duplicating border pixels
out = Image.new(face.mode, (1026, 1026))
out.paste(face, (0, 1))
out.paste(face, (2, 1))
out.paste(face, (1, 0))
out.paste(face, (1, 2))
out.putpixel((0, 0), out.getpixel((1, 0)))
out.putpixel((1025, 0), out.getpixel((1025, 1)))
out.putpixel((1025, 1025), out.getpixel((1024, 1025)))
out.putpixel((0, 1025), out.getpixel((0, 1024)))
out.paste(face, (1, 1))
out.save(os.path.join(args.output, 'fallback', faceLetters[f] + extension))
face.save(os.path.join(args.output, 'fallback', faceLetters[f] + extension))

# Clean up temporary files
os.remove(os.path.join(args.output, 'cubic.pto'))


Loading…
Cancel
Save