Skip to content

Commit

Permalink
fix(core): fix wrong 3dtiles's OBB using BuilderEllipsoidTile
Browse files Browse the repository at this point in the history
fix #656
  • Loading branch information
gchoqueux committed Mar 1, 2018
1 parent 8414a5d commit ca6daf1
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 114 deletions.
9 changes: 3 additions & 6 deletions src/Core/Scheduler/Providers/3dTiles_Provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PntsLoader from '../../../Renderer/ThreeExtended/PntsLoader';
import Fetcher from './Fetcher';
import OBB from '../../../Renderer/ThreeExtended/OBB';
import Extent from '../../Geographic/Extent';
import MathExtended from '../../Math/MathExtended';
import { UNIT } from '../../Geographic/Coordinates';
import Capabilities from '../../System/Capabilities';
import PrecisionQualifier from '../../../Renderer/Shader/Chunk/PrecisionQualifier.glsl';
import { init3dTilesLayer } from '../../../Process/3dTilesProcessing';
Expand Down Expand Up @@ -78,12 +78,9 @@ function preprocessDataLayer(layer, view, scheduler) {
function getBox(volume, inverseTileTransform) {
if (volume.region) {
const region = volume.region;
const extent = new Extent('EPSG:4326', MathExtended.radToDeg(region[0]), MathExtended.radToDeg(region[2]), MathExtended.radToDeg(region[1]), MathExtended.radToDeg(region[3]));
const extent = new Extent('EPSG:4326', region[0], region[2], region[1], region[3]);
extent._internalStorageUnit = UNIT.RADIAN;
const box = OBB.extentToOBB(extent, region[4], region[5]);
// update position
box.position.add(extent.center().as('EPSG:4978').xyz());
// compute box.matrix from box.position/rotation.
box.updateMatrix();
// at this point box.matrix = box.epsg4978_from_local, so
// we transform it in parent_from_local by using parent's epsg4978_from_local
// which from our point of view is epsg4978_from_parent.
Expand Down
131 changes: 23 additions & 108 deletions src/Renderer/ThreeExtended/OBB.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as THREE from 'three';
import Coordinates, { C, UNIT } from '../../Core/Geographic/Coordinates';
import TileGeometry from '../../Core/TileGeometry';
import BuilderEllipsoidTile from '../../Core/Prefab/Globe/BuilderEllipsoidTile';

function OBB(min, max) {
THREE.Object3D.call(this);
Expand Down Expand Up @@ -103,119 +105,32 @@ for (let i = 0; i < 9; i++) {
}

// get oriented bounding box of tile
OBB.extentToOBB = function extentToOBB(extent, minHeight = 0, maxHeight = 0) {
const builder = new BuilderEllipsoidTile();
OBB.extentToOBB = function _extentToOBB(extent, minHeight = 0, maxHeight = 0) {
if (extent._crs != 'EPSG:4326') {
throw new Error('The extent crs is not a Geographic Coordinates (EPSG:4326)');
}

// Calcule the center world position with the extent.
extent.center(tmp.cardinals[8]);

const bboxDimension = extent.dimensions(UNIT.RADIAN);
const phiStart = extent.west(UNIT.RADIAN);
const phiLength = bboxDimension.x;

const thetaStart = extent.south(UNIT.RADIAN);
const thetaLength = bboxDimension.y;
// 0---1---2
// | |
// 7 8 3
// | |
// 6---5---4
// tmp.cardinals[0]._values[0] = phiStart;
// tmp.cardinals[0]._values[1] = thetaStart;
// tmp.cardinals[0]._normal = undefined;

tmp.cardinals[0].set('EPSG:4326', phiStart, thetaStart, 0);
tmp.cardinals[0]._internalStorageUnit = UNIT.RADIAN;
tmp.cardinals[1].set('EPSG:4326', phiStart + bboxDimension.x * 0.5, thetaStart, 0);
tmp.cardinals[1]._internalStorageUnit = UNIT.RADIAN;
tmp.cardinals[2].set('EPSG:4326', phiStart + phiLength, thetaStart, 0);
tmp.cardinals[2]._internalStorageUnit = UNIT.RADIAN;
tmp.cardinals[3].set('EPSG:4326', phiStart + phiLength, thetaStart + bboxDimension.y * 0.5, 0);
tmp.cardinals[3]._internalStorageUnit = UNIT.RADIAN;
tmp.cardinals[4].set('EPSG:4326', phiStart + phiLength, thetaStart + thetaLength, 0);
tmp.cardinals[4]._internalStorageUnit = UNIT.RADIAN;
tmp.cardinals[5].set('EPSG:4326', phiStart + bboxDimension.x * 0.5, thetaStart + thetaLength, 0);
tmp.cardinals[5]._internalStorageUnit = UNIT.RADIAN;
tmp.cardinals[6].set('EPSG:4326', phiStart, thetaStart + thetaLength, 0);
tmp.cardinals[6]._internalStorageUnit = UNIT.RADIAN;
tmp.cardinals[7].set('EPSG:4326', phiStart, thetaStart + bboxDimension.y * 0.5, 0);
tmp.cardinals[7]._internalStorageUnit = UNIT.RADIAN;

const cardinalsXYZ = [];
const centersLongitude = tmp.cardinals[8].longitude(UNIT.RADIAN);
for (const cardinal of tmp.cardinals) {
cardinalsXYZ.push(cardinal.as('EPSG:4978').xyz());
}

return this.cardinalsXYZToOBB(cardinalsXYZ, centersLongitude, true, tmp.cardinals[8].geodesicNormal, minHeight, maxHeight);
};

/**
* Computes the OBB of a portion of a ellipsoid.
* @param {Vector3[]} cardinals - 8 cardinals of the portion + the center.
* @param {number} centerLongitude - the longitude at the center of the portion
* @param {boolean} isEllipsoid - should be true when computing for the globe, false otherwise
* @param {Vector3} geodesicNormal - geodesic normal at extent's center
* @param {number} minHeight
* @param {number} maxHeight
* @return {OBB}
*/
OBB.cardinalsXYZToOBB = function cardinalsXYZToOBB(cardinals, centerLongitude, isEllipsoid, geodesicNormal, minHeight = 0, maxHeight = 0) {
tmp.maxV.set(-1000, -1000, -1000);
tmp.minV.set(1000, 1000, 1000);

let halfMaxHeight = 0;
tmp.normal.copy(geodesicNormal);
tmp.tangentPlaneAtOrigin.set(tmp.normal, 0);

// Compute the rotation transforming the tile so that it's normal becomes (0, 0, 1)
tmp.transformNormalToZ.setFromUnitVectors(tmp.normal, tmp.zUp);
// Compute the rotation to get the line [1,8,5] aligned on (0, 1, 0)
tmp.alignTileOnWorldXY.setFromAxisAngle(tmp.zUp, -centerLongitude);
const rotateTile = tmp.alignTileOnWorldXY.multiply(tmp.transformNormalToZ);

let point5InPlaneX;
for (let i = 0; i < cardinals.length; i++) {
const vec = tmp.tangentPlaneAtOrigin.projectPoint(cardinals[i], tmp.cardinal3D);
const d = vec.distanceTo(cardinals[i].sub(cardinals[8]));
halfMaxHeight = Math.max(halfMaxHeight, d * 0.5);
vec.applyQuaternion(rotateTile);
// compute tile's min/max
tmp.maxV.max(vec);
tmp.minV.min(vec);

if (i == 5) {
point5InPlaneX = vec.x;
}
}

const halfLength = Math.abs(tmp.maxV.y - tmp.minV.y) * 0.5;
const halfWidth = Math.abs(tmp.maxV.x - tmp.minV.x) * 0.5;

const nHalfSize = Math.abs(-halfMaxHeight + (minHeight - maxHeight) * 0.5);

const max = new THREE.Vector3(halfLength, halfWidth, nHalfSize);
const min = new THREE.Vector3(-halfLength, -halfWidth, -nHalfSize);

// delta is the distance between line `([6],[4])` and the point `[5]`
// These points [6],[5],[4] aren't aligned because of the ellipsoid shape
const delta = isEllipsoid ? (halfWidth - Math.abs(point5InPlaneX)) : 0;
tmp.translate.set(0, delta, -halfMaxHeight);

const obb = new OBB(min, max);

obb.lookAt(tmp.normal);
obb.translateX(tmp.translate.x);
obb.translateY(tmp.translate.y);
obb.translateZ(tmp.translate.z);

// for 3D
if (minHeight !== 0 || maxHeight !== 0) {
obb.translateZ(-halfMaxHeight + minHeight + nHalfSize);
if (extent._internalStorageUnit != UNIT.RADIAN) {
throw new Error('The extent internalStorageUnit is not in radian unit');
}

const { sharableExtent, quaternion, position } = builder.computeSharableExtent(extent);
const paramsGeometry = {
extent: sharableExtent,
level: 0,
segment: 2,
disableSkirt: true,
};

const geometry = new TileGeometry(paramsGeometry, builder);
const obb = geometry.OBB;
obb.updateZ(minHeight, maxHeight);
obb.position.copy(position);
obb.quaternion.copy(quaternion);
obb.update();

// Calling geometry.dispose() is not needed since this geometry never gets rendered
return obb;
};

export default OBB;

0 comments on commit ca6daf1

Please sign in to comment.