equi working, just left/right mix

pull/28/head
GeorgLegato 2023-04-08 02:53:43 +02:00
parent 4da87f9b07
commit 135220cc09
1 changed files with 275 additions and 89 deletions

View File

@ -1,3 +1,6 @@
let exports = {}
//import { PNG } from "./pngjs";
const openpanorama = {
frame: null
};
@ -366,105 +369,242 @@ document.addEventListener("DOMContentLoaded", () => {
});
function convertto_equi() {
/* routine based on disseminate/cube2equi github.com, default Github license */
function convertto_cubemap() {
const PNG = require( 'pngjs' ).PNG;
program
.version( '0.1.0' )
.option( '-i, --input <file>', 'Input cubemap image' )
.option( '-o, --output [file]', 'Output cubemap image' )
.option( '-w, --width <n>', 'Output cubemap size', parseInt )
.option( '-h, --height <n>', 'Output cubemap height', parseInt )
.parse( process.argv );
const W = program.width || 2048;
const H = program.height || 1024;
const out = program.output || 'out.png';
panorama_get_image_from_gallery()
.then((dataURL) => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const img = new Image();
img.src = dataURL
img.addEventListener('load', () => {
const { width, height } = img;
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0);
const sourceTexture = ctx.getImageData(0, 0, width, height);
const outputWidth = sourceTexture.width
const outputHeight = sourceTexture.height /1.5
let equiTexture = new ImageData(outputWidth, outputHeight);
let u, v; // Normalised texture coordinates, from 0 to 1, starting at lower left corner
let phi, theta; // Polar coordinates
const cubeFaceWidth = sourceTexture.width / 4; // 4 horizontal faces
const cubeFaceHeight = sourceTexture.height / 3; // 3 vertical faces
onePx = document.createElement("canvas").getContext("2d").createImageData(1, 1);
for (let j = 0; j < equiTexture.height; j++) {
// Rows start from the bottom
v = 1 - (j / equiTexture.height);
theta = v * Math.PI;
for (let i = 0; i < equiTexture.width; i++) {
// Columns start from the left
u = (i / equiTexture.width);
phi = u * 2 * Math.PI;
let x, y, z; // Unit vector
x = Math.sin(phi) * Math.sin(theta) * -1;
y = Math.cos(theta);
z = Math.cos(phi) * Math.sin(theta) * -1;
let xa, ya, za;
let a;
a = Math.max(Math.abs(x), Math.abs(y), Math.abs(z));
// Vector Parallel to the unit vector that lies on one of the cube faces
xa = x / a;
ya = y / a;
za = z / a;
let xPixel, yPixel;
let xOffset, yOffset;
if (xa == 1) {
// Right
xPixel = Math.round(((((za + 1) / 2) - 1) * cubeFaceWidth) - 0.5);
xOffset = 2 * cubeFaceWidth; // Offset
yPixel = Math.round((((ya + 1) / 2) * cubeFaceHeight) - 0.5);
yOffset = cubeFaceHeight; // Offset
}
else if (xa == -1) {
// Left
xPixel = Math.round(((((za + 1) / 2)) * cubeFaceWidth) - 0.5);
xOffset = 0;
yPixel = Math.round((((ya + 1) / 2) * cubeFaceHeight) - 0.5);
yOffset = cubeFaceHeight;
}
else if (ya == 1) {
// Up
xPixel = Math.round(((((xa + 1) / 2)) * cubeFaceWidth) - 0.5);
xOffset = cubeFaceWidth;
yPixel = Math.round(((((za + 1) / 2) - 1) * cubeFaceHeight) - 0.5);
yOffset = 2 * cubeFaceHeight;
}
else if (ya == -1) {
// Down
xPixel = Math.round(((((xa + 1) / 2)) * cubeFaceWidth) - 0, 5);
xOffset = cubeFaceWidth;
yPixel = Math.round(((((za + 1) / 2)) * cubeFaceHeight) - 0.5);
yOffset = 0;
}
else if (za == 1) {
// Front
xPixel = Math.round(((((xa + 1) / 2)) * cubeFaceWidth) - 0.5);
xOffset = cubeFaceWidth;
yPixel = Math.round(((((ya + 1) / 2)) * cubeFaceHeight) - 0.5);
yOffset = cubeFaceHeight;
}
else if (za == -1) {
//Back
xPixel = ~~((((xa + 1) / 2) - 1) * cubeFaceWidth);
xOffset = 3 * cubeFaceWidth;
yPixel = ~~((((ya + 1) / 2)) * cubeFaceHeight);
yOffset = cubeFaceHeight;
}
else {
console.warn("Unknown face, something went wrong");
xPixel = 0;
yPixel = 0;
xOffset = 0;
yOffset = 0;
}
xPixel = Math.abs(xPixel);
yPixel = Math.abs(yPixel);
xPixel += xOffset;
yPixel += yOffset;
const index = 4 * (xPixel + yPixel * sourceTexture.width);
const tindex = 4 * (i + j * equiTexture.width);
equiTexture.data[tindex] = sourceTexture.data[index ]; // red color
equiTexture.data[tindex+1] = sourceTexture.data[index + 1]; // green color
equiTexture.data[tindex+2] = sourceTexture.data[index + 2]; // blue color
equiTexture.data[tindex+3] = sourceTexture.data[index + 3];
}
}
// create canvas and draw equirectangular pixels in it
const equiCanvas = document.createElement('canvas');
equiCanvas.width = outputWidth;
equiCanvas.height = outputHeight;
const equiCtx = equiCanvas.getContext('2d');
const equiImageData = equiCtx.createImageData(outputWidth, outputHeight);
equiImageData.data.set(equiTexture);
equiCtx.putImageData(equiImageData, 0, 0);
equiCanvas.toBlob(function (blob) {
if (blob instanceof Blob) {
data = { files: [blob] };
var event = document.createEvent('MouseEvent');
event.dataTransfer = data;
onGalleryDrop(event)
}
else {
console.log("no blob from toBlob?!")
}
}, 'image/png');
})
})
}
/* routine based on disseminate/cube2equi github.com, default Github license
function convertto_equi__() {
// W, H are output size width
let W, H
const EquiCoordToPolar = (x, y) => {
const xNorm = ( 2 * x / W ) - 1;
const yNorm = 1 - ( 2 * y / H );
const xNorm = (2 * x / W) - 1;
const yNorm = 1 - (2 * y / H);
const theta = xNorm * Math.PI;
const phi = Math.asin( yNorm );
const phi = Math.asin(yNorm);
return [theta, phi];
};
const PolarToUnitVector = (theta, phi) => {
const x = Math.cos( phi ) * Math.cos( theta );
const y = Math.sin( phi );
const z = Math.cos( phi ) * Math.sin( theta );
const x = Math.cos(phi) * Math.cos(theta);
const y = Math.sin(phi);
const z = Math.cos(phi) * Math.sin(theta);
return [x, y, z];
};
const DotProduct = (a, b) => {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
};
const Normalize = (a) => {
const len = Math.sqrt( DotProduct( a, a ) );
const len = Math.sqrt(DotProduct(a, a));
return [a[0] / len, a[1] / len, a[2] / len];
};
const Mul = (a, scalar) => {
return [a[0] * scalar, a[1] * scalar, a[2] * scalar];
};
SIDE_BACK = 1;
SIDE_LEFT = 5;
SIDE_FRONT = 0;
SIDE_RIGHT = 4;
SIDE_TOP = 2;
SIDE_BOTTOM = 3;
const IntersectRayWithPlane = (side, normal, p0, ray) => {
const denom = DotProduct( normal, ray );
if( Math.abs( denom ) > 0.0000001 ) {
const t = DotProduct( p0, normal ) / denom;
if( t >= 0 ) {
const denom = DotProduct(normal, ray);
if (Math.abs(denom) > 0.0000001) {
const t = DotProduct(p0, normal) / denom;
if (t >= 0) {
const newVec = Mul(ray, t);
if( side === SIDE_LEFT ) {
if( newVec[0] >= -1 && newVec[0] <= 1 && newVec[1] >= -1 && newVec[1] <= 1 ) {
if (side === SIDE_LEFT) {
if (newVec[0] >= -1 && newVec[0] <= 1 && newVec[1] >= -1 && newVec[1] <= 1) {
return [(newVec[0] + 1) / 2, (newVec[1] + 1) / 2];
}
} else if( side === SIDE_RIGHT ) {
if( newVec[0] >= -1 && newVec[0] <= 1 && newVec[1] >= -1 && newVec[1] <= 1 ) {
} else if (side === SIDE_RIGHT) {
if (newVec[0] >= -1 && newVec[0] <= 1 && newVec[1] >= -1 && newVec[1] <= 1) {
return [1 - (newVec[0] + 1) / 2, (newVec[1] + 1) / 2];
}
} else if( side === SIDE_FRONT ) {
if( newVec[1] >= -1 && newVec[1] <= 1 && newVec[2] >= -1 && newVec[2] <= 1 ) {
} else if (side === SIDE_FRONT) {
if (newVec[1] >= -1 && newVec[1] <= 1 && newVec[2] >= -1 && newVec[2] <= 1) {
return [(newVec[2] + 1) / 2, (newVec[1] + 1) / 2];
}
} else if( side === SIDE_BACK ) {
if( newVec[1] >= -1 && newVec[1] <= 1 && newVec[2] >= -1 && newVec[2] <= 1 ) {
} else if (side === SIDE_BACK) {
if (newVec[1] >= -1 && newVec[1] <= 1 && newVec[2] >= -1 && newVec[2] <= 1) {
return [1 - (newVec[2] + 1) / 2, 1 - (newVec[1] + 1) / 2];
}
} else if( side === SIDE_TOP ) {
if( newVec[0] >= -1 && newVec[0] <= 1 && newVec[2] >= -1 && newVec[2] <= 1 ) {
} else if (side === SIDE_TOP) {
if (newVec[0] >= -1 && newVec[0] <= 1 && newVec[2] >= -1 && newVec[2] <= 1) {
return [1 - (newVec[0] + 1) / 2, 1 - (newVec[2] + 1) / 2];
}
} else if( side === SIDE_BOTTOM ) {
if( newVec[0] >= -1 && newVec[0] <= 1 && newVec[2] >= -1 && newVec[2] <= 1 ) {
} else if (side === SIDE_BOTTOM) {
if (newVec[0] >= -1 && newVec[0] <= 1 && newVec[2] >= -1 && newVec[2] <= 1) {
return [(newVec[0] + 1) / 2, (newVec[2] + 1) / 2];
}
}
}
}
};
const MV = (vec) => {
return [-vec[0], -vec[1], -vec[2]];
};
const IntersectRayWithBoxes = (ray) => {
let t;
const boxes = [
[1, 0, 0],
[-1, 0, 0],
@ -473,80 +613,126 @@ function convertto_cubemap() {
[0, 0, 1],
[0, 0, -1],
];
for( let i = 0; i < boxes.length; i++ ) {
for (let i = 0; i < boxes.length; i++) {
xy = IntersectRayWithPlane(i, MV(boxes[i]), boxes[i], Normalize(ray));
if( xy !== undefined ) {
if (xy !== undefined) {
return [i, xy[0], xy[1]];
}
}
};
const SideXYToCubemap = (side, x, y) => {
let newY, newX;
switch(side) {
switch (side) {
case SIDE_BACK:
newY = (1/3) + y * (1/3);
newY = (1 / 3) + y * (1 / 3);
return [x * 0.25, newY];
case SIDE_LEFT:
newY = (2/3) - y * (1/3);
newY = (2 / 3) - y * (1 / 3);
return [0.25 + x * 0.25, newY];
case SIDE_FRONT:
newY = (2/3) - y * (1/3);
newY = (2 / 3) - y * (1 / 3);
return [0.5 + x * 0.25, newY];
case SIDE_RIGHT:
newY = (2/3) - y * (1/3);
newY = (2 / 3) - y * (1 / 3);
return [0.75 + x * 0.25, newY];
case SIDE_TOP:
newY = y * ( 1/3 );
newY = y * (1 / 3);
newX = 0.5 - x * 0.25;
return [newX, newY];
case SIDE_BOTTOM:
newY = (2/3) + y * ( 1/3 );
newY = (2 / 3) + y * (1 / 3);
newX = 0.25 + x * 0.25;
return [newX, newY];
}
};
fs.createReadStream( program.input )
.pipe( new PNG({
filterType: 4
}) )
.on( 'parsed', function() {
const png = this;
const outPNG = new PNG( {
function doIt() {
W = png.width;
H = W / 2;
const outPNG = new PNG({
width: W,
height: H,
colorType: 2,
inputHasAlpha: false
});
for( let j = 0; j < H; j++ ) {
for( let i = 0; i < W; i++ ) {
const angs = EquiCoordToPolar( i, j );
const ray = PolarToUnitVector( angs[0], angs[1] );
const sxc = IntersectRayWithBoxes( ray );
const xy = SideXYToCubemap( sxc[0], sxc[1], sxc[2] );
const sampleX = Math.floor( xy[0] * png.width );
const sampleY = Math.floor( xy[1] * png.height );
for (let j = 0; j < H; j++) {
for (let i = 0; i < W; i++) {
const angs = EquiCoordToPolar(i, j);
const ray = PolarToUnitVector(angs[0], angs[1]);
const sxc = IntersectRayWithBoxes(ray);
const xy = SideXYToCubemap(sxc[0], sxc[1], sxc[2]);
const sampleX = Math.floor(xy[0] * png.width);
const sampleY = Math.floor(xy[1] * png.height);
const idx = (png.width * sampleY + sampleX) << 2;
const oidx = (W * j + i) * 3;
outPNG.data[oidx] = png.data[idx];
outPNG.data[oidx + 1] = png.data[idx + 1];
outPNG.data[oidx + 2] = png.data[idx + 2];
}
}
outPNG.pack().pipe( fs.createWriteStream( program.output ) );
} );
const outBuffer = PNG.sync.write(outPNG);
const blob = new Blob([outBuffer], { type: 'image/png' });
//const dataTransfer = new DataTransfer();
//dataTransfer.items.add(new File([blob], 'equi.png', { type: 'image/png' }));
// Transfer the image data to another element
//const targetElement = document.getElementById('target');
//targetElement.dispatchEvent(new ClipboardEvent('paste', { clipboardData: dataTransfer }));
if (blob instanceof Blob) {
data = { files: [blob] };
var event = document.createEvent('MouseEvent');
event.dataTransfer = data;
onGalleryDrop(event);
}
else {
console.log("no blob from toBlob?!");
}
}
function handlePNGParsed(error, png) {
if (error) {
console.error('Failed to parse PNG:', error);
return;
}
doIt(png)
}
panorama_get_image_from_gallery()
.then((dataURL) => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const img = new Image();
img.src = dataURL
img.addEventListener('load', () => {
const { width, height } = img;
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0);
const data = ctx.getImageData(0, 0, width, height);
const png = new PNG({
width: canvas.width,
height: canvas.height
});
// Copy the pixel data from the ImageData object to the PNG object
png.data.set(imageData.data);
doIt(png);
});
})
}
*/
/* routine based on jerx/github, gpl3 */
function convertto_cubemap() {