diff --git a/docs/guide/adapters/equirectangular-video.md b/docs/guide/adapters/equirectangular-video.md
index b8c40983..e2f61438 100644
--- a/docs/guide/adapters/equirectangular-video.md
+++ b/docs/guide/adapters/equirectangular-video.md
@@ -89,3 +89,7 @@ const viewer = new Viewer({
},
});
```
+
+::: tip `panoData` support
+It is possible to declare the [`panoData`](../config.md#panodata) option if the video does not cover a full sphere.
+:::
diff --git a/docs/guide/adapters/equirectangular.md b/docs/guide/adapters/equirectangular.md
index 2360c5dd..1dc03cff 100644
--- a/docs/guide/adapters/equirectangular.md
+++ b/docs/guide/adapters/equirectangular.md
@@ -100,7 +100,7 @@ The XMP payload is as follow:
0
0
- 0
+ 60
@@ -146,6 +146,26 @@ const viewer = new PhotoSphereViewer.Viewer({
});
```
+#### Default parameters
+
+If the image does not have a 2:1 ratio and no XMP data are found and no `panoData` is provided, a best effort is done to display the image without distortion. The exact algorithm is as follow:
+
+```js
+const fullWidth = Math.max(img.width, img.height * 2);
+const fullHeight = Math.round(fullWidth / 2);
+const croppedX = Math.round((fullWidth - img.width) / 2);
+const croppedY = Math.round((fullHeight - img.height) / 2);
+
+panoData = {
+ fullWidth: fullWidth,
+ fullHeight: fullHeight,
+ croppedWidth: img.width,
+ croppedHeight: img.height,
+ croppedX: croppedX,
+ croppedY: croppedY,
+};
+```
+
### Playground
Use this demo to find the best values for your image.
diff --git a/docs/guide/config.md b/docs/guide/config.md
index de3f21eb..5c6ba9aa 100644
--- a/docs/guide/config.md
+++ b/docs/guide/config.md
@@ -243,10 +243,6 @@ panoData: (image, xmpData) => ({
});
```
-::: warning
-Only the default [equirectangular](./adapters/equirectangular.md) adapter supports `panoData`.
-:::
-
#### `moveSpeed`
- type: `double`
diff --git a/packages/cubemap-tiles-adapter/src/CubemapTilesAdapter.ts b/packages/cubemap-tiles-adapter/src/CubemapTilesAdapter.ts
index 80365ed0..93dd6cdc 100644
--- a/packages/cubemap-tiles-adapter/src/CubemapTilesAdapter.ts
+++ b/packages/cubemap-tiles-adapter/src/CubemapTilesAdapter.ts
@@ -4,12 +4,16 @@ import { CubemapAdapter, CubemapData, CubemapFaces } from '@photo-sphere-viewer/
import { BoxGeometry, BufferAttribute, Group, Mesh, MeshBasicMaterial, Texture, Vector3 } from 'three';
import { Queue, Task } from '../../shared/Queue';
import { buildDebugTexture, buildErrorMaterial, createWireFrame } from '../../shared/tiles-utils';
-import { CubemapMultiTilesPanorama, CubemapTilesAdapterConfig, CubemapTilesPanorama } from './model';
+import { CubemapMultiTilesPanorama, CubemapTilesAdapterConfig, CubemapTilesPanoData, CubemapTilesPanorama } from './model';
import { CubemapTileConfig, checkPanoramaConfig, getTileConfig, getTileConfigByIndex, isTopOrBottom } from './utils';
type CubemapMesh = Mesh;
type CubemapTilesMesh = Mesh;
-type CubemapTilesTextureData = TextureData;
+type CubemapTilesTextureData = TextureData<
+ Texture[],
+ CubemapTilesPanorama | CubemapMultiTilesPanorama,
+ CubemapTilesPanoData
+>;
type CubemapTile = {
face: number;
col: number;
@@ -58,7 +62,7 @@ const vertexPosition = new Vector3();
*/
export class CubemapTilesAdapter extends AbstractAdapter<
CubemapTilesPanorama | CubemapMultiTilesPanorama,
- CubemapData,
+ CubemapTilesPanoData,
Texture[],
Group
> {
@@ -156,11 +160,11 @@ export class CubemapTilesAdapter extends AbstractAdapter<
return !!panorama.baseUrl;
}
- override textureCoordsToSphericalCoords(point: PanoramaPosition, data: CubemapData): Position {
+ override textureCoordsToSphericalCoords(point: PanoramaPosition, data: CubemapTilesPanoData): Position {
return this.adapter.textureCoordsToSphericalCoords(point, data);
}
- override sphericalCoordsToTextureCoords(position: Position, data: CubemapData): PanoramaPosition {
+ override sphericalCoordsToTextureCoords(position: Position, data: CubemapTilesPanoData): PanoramaPosition {
return this.adapter.sphericalCoordsToTextureCoords(position, data);
}
@@ -182,14 +186,20 @@ export class CubemapTilesAdapter extends AbstractAdapter<
return {
panorama,
- panoData,
+ panoData: {
+ ...panoData,
+ baseData: textureData.panoData,
+ },
cacheKey: textureData.cacheKey,
texture: textureData.texture,
};
} else {
return {
panorama,
- panoData,
+ panoData: {
+ ...panoData,
+ baseData: null,
+ },
cacheKey: panorama.tileUrl('front', 0, 0, 0),
texture: null,
};
@@ -241,7 +251,7 @@ export class CubemapTilesAdapter extends AbstractAdapter<
this.adapter.setTexture(baseMesh, {
panorama: textureData.panorama.baseUrl,
texture: textureData.texture,
- panoData: textureData.panoData,
+ panoData: textureData.panoData.baseData,
});
} else {
baseMesh.visible = false;
@@ -281,8 +291,8 @@ export class CubemapTilesAdapter extends AbstractAdapter<
return;
}
- const panorama: CubemapTilesPanorama | CubemapMultiTilesPanorama = this.viewer.state.textureData.panorama;
- const panoData: CubemapData = this.viewer.state.textureData.panoData;
+ const panorama = this.viewer.state.textureData.panorama as CubemapTilesPanorama | CubemapMultiTilesPanorama;
+ const panoData = this.viewer.state.textureData.panoData as CubemapTilesPanoData;
const zoomLevel = this.viewer.getZoomLevel();
const tileConfig = getTileConfig(panorama, zoomLevel, { CUBE_SEGMENTS });
@@ -396,7 +406,7 @@ export class CubemapTilesAdapter extends AbstractAdapter<
* Applies a new texture to the faces
*/
private __swapMaterial(tile: CubemapTile, material: MeshBasicMaterial, isError: boolean) {
- const panoData = this.viewer.state.textureData.panoData as CubemapData;
+ const panoData = this.viewer.state.textureData.panoData as CubemapTilesPanoData;
const uvs = this.state.geom.getAttribute(ATTR_UV) as BufferAttribute;
for (let c = 0; c < tile.config.facesByTile; c++) {
diff --git a/packages/cubemap-tiles-adapter/src/model.ts b/packages/cubemap-tiles-adapter/src/model.ts
index bec2c76f..fc16fa07 100644
--- a/packages/cubemap-tiles-adapter/src/model.ts
+++ b/packages/cubemap-tiles-adapter/src/model.ts
@@ -1,4 +1,4 @@
-import type { Cubemap, CubemapAdapterConfig, CubemapPanorama } from '@photo-sphere-viewer/cubemap-adapter';
+import type { Cubemap, CubemapAdapterConfig, CubemapData, CubemapPanorama } from '@photo-sphere-viewer/cubemap-adapter';
/**
* Configuration of a tiled cubemap
@@ -88,3 +88,7 @@ export type CubemapTilesAdapterConfig = CubemapAdapterConfig & {
*/
debug?: boolean;
};
+
+export type CubemapTilesPanoData = CubemapData & {
+ baseData: CubemapData;
+};
diff --git a/packages/equirectangular-tiles-adapter/src/EquirectangularTilesAdapter.ts b/packages/equirectangular-tiles-adapter/src/EquirectangularTilesAdapter.ts
index 48f3c302..466a1ed6 100644
--- a/packages/equirectangular-tiles-adapter/src/EquirectangularTilesAdapter.ts
+++ b/packages/equirectangular-tiles-adapter/src/EquirectangularTilesAdapter.ts
@@ -6,6 +6,7 @@ import { buildDebugTexture, buildErrorMaterial, createWireFrame } from '../../sh
import {
EquirectangularMultiTilesPanorama,
EquirectangularTilesAdapterConfig,
+ EquirectangularTilesPanoData,
EquirectangularTilesPanorama,
} from './model';
import { EquirectangularTileConfig, checkPanoramaConfig, getTileConfig, getTileConfigByIndex } from './utils';
@@ -47,7 +48,7 @@ type EquirectangularTilesMesh = Mesh;
type EquirectangularTilesTextureData = TextureData<
Texture,
EquirectangularTilesPanorama | EquirectangularMultiTilesPanorama,
- PanoData
+ EquirectangularTilesPanoData
>;
type EquirectangularTile = {
row: number;
@@ -90,7 +91,7 @@ const vertexPosition = new Vector3();
*/
export class EquirectangularTilesAdapter extends AbstractAdapter<
EquirectangularTilesPanorama | EquirectangularMultiTilesPanorama,
- PanoData,
+ EquirectangularTilesPanoData,
Texture,
Group
> {
@@ -198,11 +199,11 @@ export class EquirectangularTilesAdapter extends AbstractAdapter<
return !!panorama.baseUrl;
}
- override textureCoordsToSphericalCoords(point: PanoramaPosition, data: PanoData): Position {
+ override textureCoordsToSphericalCoords(point: PanoramaPosition, data: EquirectangularTilesPanoData): Position {
return this.adapter.textureCoordsToSphericalCoords(point, data);
}
- override sphericalCoordsToTextureCoords(position: Position, data: PanoData): PanoramaPosition {
+ override sphericalCoordsToTextureCoords(position: Position, data: EquirectangularTilesPanoData): PanoramaPosition {
return this.adapter.sphericalCoordsToTextureCoords(position, data);
}
@@ -212,41 +213,48 @@ export class EquirectangularTilesAdapter extends AbstractAdapter<
): Promise {
checkPanoramaConfig(panorama, this);
+ const firstTile = getTileConfig(panorama, 0, this);
+ const panoData: PanoData = {
+ isEquirectangular: true,
+ fullWidth: firstTile.width,
+ fullHeight: firstTile.width / 2,
+ croppedWidth: firstTile.width,
+ croppedHeight: firstTile.width / 2,
+ croppedX: 0,
+ croppedY: 0,
+ poseHeading: 0,
+ posePitch: 0,
+ poseRoll: 0,
+ };
+
if (panorama.baseUrl) {
const textureData = await this.adapter.loadTexture(panorama.baseUrl, loader, panorama.basePanoData, true);
return {
panorama,
- panoData: textureData.panoData,
+ panoData: {
+ ...panoData,
+ baseData: textureData.panoData,
+ },
cacheKey: textureData.cacheKey,
texture: textureData.texture,
};
} else {
- const firstTile = getTileConfig(panorama, 0, this);
- const panoData: PanoData = {
- isEquirectangular: true,
- fullWidth: firstTile.width,
- fullHeight: firstTile.width / 2,
- croppedWidth: firstTile.width,
- croppedHeight: firstTile.width / 2,
- croppedX: 0,
- croppedY: 0,
- poseHeading: 0,
- posePitch: 0,
- poseRoll: 0,
- };
-
+
return {
panorama,
- panoData,
+ panoData: {
+ ...panoData,
+ baseData: null,
+ },
cacheKey: panorama.tileUrl(0, 0, 0),
texture: null,
};
}
}
- createMesh(panoData: PanoData): Group {
- const baseMesh = this.adapter.createMesh(panoData);
+ createMesh(panoData: EquirectangularTilesPanoData): Group {
+ const baseMesh = this.adapter.createMesh(panoData.baseData ?? panoData);
const geometry = new SphereGeometry(
CONSTANTS.SPHERE_RADIUS,
@@ -303,7 +311,7 @@ export class EquirectangularTilesAdapter extends AbstractAdapter<
this.adapter.setTexture(baseMesh, {
panorama: textureData.panorama.baseUrl,
texture: textureData.texture,
- panoData: textureData.panoData,
+ panoData: textureData.panoData.baseData,
});
} else {
baseMesh.visible = false;
@@ -343,7 +351,7 @@ export class EquirectangularTilesAdapter extends AbstractAdapter<
return;
}
- const panorama: EquirectangularTilesPanorama | EquirectangularMultiTilesPanorama = this.viewer.config.panorama;
+ const panorama = this.viewer.config.panorama as EquirectangularTilesPanorama | EquirectangularMultiTilesPanorama;
const zoomLevel = this.viewer.getZoomLevel();
const tileConfig = getTileConfig(panorama, zoomLevel, this);
diff --git a/packages/equirectangular-tiles-adapter/src/model.ts b/packages/equirectangular-tiles-adapter/src/model.ts
index 4d9861bc..d1d5ee3e 100644
--- a/packages/equirectangular-tiles-adapter/src/model.ts
+++ b/packages/equirectangular-tiles-adapter/src/model.ts
@@ -94,3 +94,7 @@ export type EquirectangularTilesAdapterConfig = Omit