Skip to content

Commit

Permalink
feature: Add the early support for 3d-tiles Pnts format
Browse files Browse the repository at this point in the history
Issue iTowns#185 tracks the progress
Position and RGB information are supported
  • Loading branch information
NikoSaul committed Jun 20, 2017
1 parent 283d2a3 commit 8aa9d97
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 24 deletions.
10 changes: 10 additions & 0 deletions src/Core/Scheduler/Providers/3dTiles_Provider.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as THREE from 'three';
import Provider from './Provider';
import B3dmLoader from '../../../Renderer/ThreeExtended/B3dmLoader';
import PntsLoader from '../../../Renderer/ThreeExtended/PntsLoader';
import Fetcher from './Fetcher';
import BasicMaterial from '../../../Renderer/BasicMaterial';
import OBB from '../../../Renderer/ThreeExtended/OBB';
Expand Down Expand Up @@ -94,6 +95,12 @@ $3dTiles_Provider.prototype.b3dmToMesh = function b3dmToMesh(data, layer) {
});
};

$3dTiles_Provider.prototype.pntsParse = function pntsParse(data) {
return new Promise((resolve) => {
resolve(PntsLoader.parse(data));
});
};

function configureTile(tile, layer, metadata) {
tile.frustumCulled = false;
tile.loaded = true;
Expand Down Expand Up @@ -124,6 +131,7 @@ $3dTiles_Provider.prototype.executeCommand = function executeCommand(command) {

const supportedFormats = {
b3dm: this.b3dmToMesh.bind(this),
pnts: this.pntsParse.bind(this),
};

return Fetcher.arrayBuffer(url).then((result) => {
Expand All @@ -136,6 +144,8 @@ $3dTiles_Provider.prototype.executeCommand = function executeCommand(command) {
layer.tileIndex.extendTileset(result, metadata.tileId, newPrefix);
} else if (magic == 'b3dm') {
func = supportedFormats.b3dm;
} else if (magic == 'pnts') {
func = supportedFormats.pnts;
} else {
Promise.reject(`Unsupported magic code ${magic}`);
}
Expand Down
1 change: 0 additions & 1 deletion src/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export { Extent };
export { Coordinates };
export { Fetcher };


// Others can be directly exported
export { UNIT } from './Core/Geographic/Coordinates';
export { processTiledGeometryNode, initTiledGeometryLayer } from './Process/TiledNodeProcessing';
Expand Down
42 changes: 19 additions & 23 deletions src/Renderer/Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,8 @@ Camera.prototype.setRotation = function setRotation(rotation) {
this.camera3D.quaternion.copy(rotation);
};

const temp = new THREE.Vector3();
const frustum = new THREE.Frustum();
const obbViewMatrix = new THREE.Matrix4();
const tempMatrix = new THREE.Matrix4();
const tempBox3d = new THREE.Box3();

function _prepareBox3AndMatrix(box3d, matrixWorld, visibilityTestingOffset) {
if (matrixWorld) {
tempMatrix.copy(matrixWorld);
Expand All @@ -103,13 +99,27 @@ function _prepareBox3AndMatrix(box3d, matrixWorld, visibilityTestingOffset) {
tempMatrix.elements[14] -= visibilityTestingOffset.z + temp.z;
}

Camera.prototype.isBox3DVisible = function isBox3DVisible(box3d, matrixWorld) {
_prepareBox3AndMatrix(box3d, matrixWorld, this._visibilityTestingOffset);
const temp = new THREE.Vector3();
const frustum = new THREE.Frustum();
const localViewMatrix = new THREE.Matrix4();
function localTranslationFrustum(matrixWorld, camera) {
temp.setFromMatrixPosition(matrixWorld);
matrixWorld.elements[12] -= camera._visibilityTestingOffset.x;
matrixWorld.elements[13] -= camera._visibilityTestingOffset.y;
matrixWorld.elements[14] -= camera._visibilityTestingOffset.z;

localViewMatrix.multiplyMatrices(camera._viewMatrix, matrixWorld);

obbViewMatrix.multiplyMatrices(this._viewMatrix, tempMatrix);
frustum.setFromMatrix(obbViewMatrix);
matrixWorld.setPosition(temp);
frustum.setFromMatrix(localViewMatrix);
return frustum;
}

return frustum.intersectsBox(tempBox3d);
Camera.prototype.isBox3DVisible = function isBox3DVisible(box3d, matrixWorld) {
return localTranslationFrustum(matrixWorld, this).intersectsBox(box3d);
};
Camera.prototype.isSphereVisible = function isSphereVisible(sphere, matrixWorld) {
return localTranslationFrustum(matrixWorld, this).intersectsSphere(sphere);
};

Camera.prototype.box3DSizeOnScreen = function box3DSizeOnScreen(box3d, matrixWorld) {
Expand All @@ -119,18 +129,4 @@ Camera.prototype.box3DSizeOnScreen = function box3DSizeOnScreen(box3d, matrixWor
return tempBox3d.applyMatrix4(tempMatrix);
};

Camera.prototype.isSphereVisible = function isSphereVisible(sphere, matrixWorld) {
temp.setFromMatrixPosition(matrixWorld);
matrixWorld.elements[12] -= this._visibilityTestingOffset.x;
matrixWorld.elements[13] -= this._visibilityTestingOffset.y;
matrixWorld.elements[14] -= this._visibilityTestingOffset.z;

obbViewMatrix.multiplyMatrices(this._viewMatrix, matrixWorld);

matrixWorld.setPosition(temp);

frustum.setFromMatrix(obbViewMatrix);
return frustum.intersectsSphere(sphere);
};

export default Camera;
97 changes: 97 additions & 0 deletions src/Renderer/ThreeExtended/PntsLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import * as THREE from 'three';

const textDecoder = new TextDecoder('utf-8');
export default {
parse: function parse(buffer) {
if (!buffer) {
throw new Error('No array buffer provided.');
}
const view = new DataView(buffer);

let byteOffset = 0;
const pntsHeader = {};

// Magic type is unsigned char [4]
pntsHeader.magic = textDecoder.decode(new Uint8Array(buffer, byteOffset, 4));
byteOffset += 4;

if (pntsHeader.magic) {
// Version, byteLength, batchTableJSONByteLength, batchTableBinaryByteLength and batchTable types are uint32
pntsHeader.version = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.byteLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.FTJSONLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.FTBinaryLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.BTJSONLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.BTBinaryLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

// binary table
if (pntsHeader.FTBinaryLength > 0) {
return parseFeatureBinary(buffer, byteOffset, pntsHeader.FTJSONLength);
}

// batch table
if (pntsHeader.BTBinaryLength > 0) {
throw new Error('For pnts loader, BTBinaryLength: not yet managed');
}
} else {
throw new Error('Invalid pnts file.');
}
},
};

function parseFeatureBinary(array, byteOffset, FTJSONLength) {
// Init geometry
const geometry = new THREE.BufferGeometry();
const material = new THREE.PointsMaterial({ size: 0.05, vertexColors: THREE.VertexColors, sizeAttenuation: true });

// init Array feature binary
const subArrayJson = textDecoder.decode(new Uint8Array(array, byteOffset, FTJSONLength));
const parseJSON = JSON.parse(subArrayJson);
let lengthFeature;
if (parseJSON.POINTS_LENGTH) {
lengthFeature = parseJSON.POINTS_LENGTH;
}
if (parseJSON.POSITION) {
const byteOffsetPos = (parseJSON.POSITION.byteOffset + subArrayJson.length + byteOffset);
const positionArray = new Float32Array(array, byteOffsetPos, lengthFeature * 3);
geometry.addAttribute('position', new THREE.BufferAttribute(positionArray, 3));
}
if (parseJSON.RGB) {
const byteOffsetCol = parseJSON.RGB.byteOffset + subArrayJson.length + byteOffset;
const colorArray = new Uint8Array(array, byteOffsetCol, lengthFeature * 3);
geometry.addAttribute('color', new THREE.BufferAttribute(colorArray, 3, true));
}
if (parseJSON.POSITION_QUANTIZED) {
throw new Error('For pnts loader, POSITION_QUANTIZED: not yet managed');
}
if (parseJSON.RGBA) {
throw new Error('For pnts loader, RGBA: not yet managed');
}
if (parseJSON.RGB565) {
throw new Error('For pnts loader, RGB565: not yet managed');
}
if (parseJSON.NORMAL) {
throw new Error('For pnts loader, NORMAL: not yet managed');
}
if (parseJSON.NORMAL_OCT16P) {
throw new Error('For pnts loader, NORMAL_OCT16P: not yet managed');
}
if (parseJSON.BATCH_ID) {
throw new Error('For pnts loader, BATCH_ID: not yet managed');
}
// creation points with geometry and material
const points = new THREE.Points(geometry, material);
points.realPointCount = lengthFeature;
return points;
}

0 comments on commit 8aa9d97

Please sign in to comment.