Skip to content

Commit

Permalink
Initial work for computing bounding sphere
Browse files Browse the repository at this point in the history
  • Loading branch information
lilleyse committed Jun 27, 2018
1 parent b166766 commit f6dc8ee
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 18 deletions.
72 changes: 60 additions & 12 deletions Source/Scene/PointCloud.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
define([
'../Core/arraySlice',
'../Core/BoundingSphere',
'../Core/Cartesian3',
'../Core/Cartesian4',
'../Core/Math',
'../Core/Check',
'../Core/Color',
'../Core/combine',
Expand Down Expand Up @@ -39,8 +41,10 @@ define([
'./ShadowMode'
], function(
arraySlice,
BoundingSphere,
Cartesian3,
Cartesian4,
CesiumMath,
Check,
Color,
combine,
Expand Down Expand Up @@ -161,6 +165,7 @@ define([
this._batchTableLoaded = options.batchTableLoaded;
this._pickIdLoaded = options.pickIdLoaded;
this._opaquePass = defaultValue(options.opaquePass, Pass.OPAQUE);
this._cull = defaultValue(options.cull, true);

this.style = undefined;
this._style = undefined;
Expand All @@ -171,7 +176,7 @@ define([

this.time = 0.0; // For styling
this.shadows = ShadowMode.ENABLED;
this.boundingVolume = undefined;
this.boundingSphere = undefined;

this.clippingPlanes = undefined;
this.isClipped = false;
Expand Down Expand Up @@ -452,6 +457,31 @@ define([
pointCloud._hasBatchIds = hasBatchIds;
}

var scratchMin = new Cartesian3();
var scratchMax = new Cartesian3();
var scratchPosition = new Cartesian3();

function computeApproximateBoundingSphereFromPositions(positions) {
var pointsLength = positions.length / 3;
var samplesLength = Math.min(pointsLength, 20);
var maxValue = Number.MAX_VALUE;
var minValue = -Number.MAX_VALUE;
var min = Cartesian3.fromElements(maxValue, maxValue, maxValue, scratchMin);
var max = Cartesian3.fromElements(minValue, minValue, minValue, scratchMax);
for (var i = 0; i < samplesLength; ++i) {
var index = Math.floor(i * pointsLength / samplesLength);
var position = Cartesian3.unpack(positions, index * 3, scratchPosition);
Cartesian3.minimumByComponent(min, position, min);
Cartesian3.maximumByComponent(max, position, max);
}

var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
if (pointsLength === 1) {
boundingSphere.radius = CesiumMath.EPSILON2; // To avoid radius of zero
}
return boundingSphere;
}

function prepareVertexAttribute(typedArray) {
// WebGL does not support UNSIGNED_INT, INT, or DOUBLE vertex attributes. Convert these to FLOAT.
var componentDatatype = ComponentDatatype.fromTypedArray(typedArray);
Expand All @@ -473,6 +503,7 @@ define([
var numberOfAttributes = 4;

var scratchClippingPlaneMatrix = new Matrix4();

function createResources(pointCloud, frameState) {
var context = frameState.context;
var parsedContent = pointCloud._parsedContent;
Expand Down Expand Up @@ -602,6 +633,18 @@ define([
strideInBytes : 0
});

if (pointCloud._cull) {
if (isQuantized || isQuantizedDraco) {
// Quantized volume offset is applied to the model matrix, not the bounding sphere
var scale = pointCloud._quantizedVolumeScale;
var center = Cartesian3.multiplyByScalar(scale, 0.5, new Cartesian3());
var radius = Cartesian3.maximumComponent(scale) * 0.5;
pointCloud.boundingSphere = new BoundingSphere(center, radius);
} else {
pointCloud.boundingSphere = computeApproximateBoundingSphereFromPositions(positions);
}
}

if (hasColors) {
if (isRGB565) {
attributes.push({
Expand Down Expand Up @@ -685,8 +728,8 @@ define([
});

pointCloud._drawCommand = new DrawCommand({
boundingVolume : undefined, // Updated in update
cull : false, // Already culled by 3D Tiles
boundingVolume : new BoundingSphere(),
cull : pointCloud._cull,
modelMatrix : new Matrix4(),
primitiveType : PrimitiveType.POINTS,
vertexArray : vertexArray,
Expand Down Expand Up @@ -1148,10 +1191,6 @@ define([
}
}

var scratchComputedTranslation = new Cartesian4();
var scratchComputedMatrixIn2D = new Matrix4();
var scratchModelMatrix = new Matrix4();

function decodeDraco(pointCloud, context) {
if (pointCloud._decodingState === DecodingState.READY) {
return false;
Expand Down Expand Up @@ -1207,6 +1246,10 @@ define([
return true;
}

var scratchComputedTranslation = new Cartesian4();
var scratchModelMatrix = new Matrix4();
var scratchScale = new Cartesian3();

PointCloud.prototype.update = function(frameState) {
var context = frameState.context;
var decoding = decodeDraco(this, context);
Expand All @@ -1229,6 +1272,7 @@ define([
this._ready = true;
this._readyPromise.resolve(this);
this._parsedContent = undefined; // Unload
this._drawCommand.boundingVolume = this.boundingSphere.clone();
}

if (modelMatrixDirty) {
Expand All @@ -1247,16 +1291,20 @@ define([
var translation = Matrix4.getColumn(modelMatrix, 3, scratchComputedTranslation);
if (!Cartesian4.equals(translation, Cartesian4.UNIT_W)) {
Transforms.basisTo2D(projection, modelMatrix, modelMatrix);
} else {
var center = this.boundingVolume.center;
var to2D = Transforms.wgs84To2DModelMatrix(projection, center, scratchComputedMatrixIn2D);
Matrix4.multiply(to2D, modelMatrix, modelMatrix);
}
}

Matrix4.clone(modelMatrix, this._drawCommand.modelMatrix);

this._drawCommand.boundingVolume = this.boundingVolume;
var boundingSphere = this._drawCommand.boundingVolume;
BoundingSphere.clone(this.boundingSphere, boundingSphere);

if (this._cull) {
var center = boundingSphere.center;
Matrix4.multiplyByPoint(modelMatrix, center, center);
var scale = Matrix4.getScale(modelMatrix, scratchScale);
boundingSphere.radius *= Cartesian3.maximumComponent(scale);
}
}

if (this.clippingPlanesDirty) {
Expand Down
9 changes: 5 additions & 4 deletions Source/Scene/PointCloud3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ define([
this._pointCloud = new PointCloud({
arrayBuffer : arrayBuffer,
byteOffset : byteOffset,
cull : false,
opaquePass : Pass.CESIUM_3D_TILE,
vertexShaderLoaded : getVertexShaderLoaded(this),
fragmentShaderLoaded : getFragmentShaderLoaded(this),
Expand Down Expand Up @@ -286,11 +287,11 @@ define([
batchTable.update(tileset, frameState);
}

var boundingVolume;
var boundingSphere;
if (defined(tile._contentBoundingVolume)) {
boundingVolume = mode === SceneMode.SCENE3D ? tile._contentBoundingVolume.boundingSphere : tile._contentBoundingVolume2D.boundingSphere;
boundingSphere = mode === SceneMode.SCENE3D ? tile._contentBoundingVolume.boundingSphere : tile._contentBoundingVolume2D.boundingSphere;
} else {
boundingVolume = mode === SceneMode.SCENE3D ? tile._boundingVolume.boundingSphere : tile._boundingVolume2D.boundingSphere;
boundingSphere = mode === SceneMode.SCENE3D ? tile._boundingVolume.boundingSphere : tile._boundingVolume2D.boundingSphere;
}

var styleDirty = this._styleDirty;
Expand All @@ -301,7 +302,7 @@ define([
pointCloud.modelMatrix = tile.computedTransform;
pointCloud.time = tileset.timeSinceLoad;
pointCloud.shadows = tileset.shadows;
pointCloud.boundingVolume = boundingVolume;
pointCloud.boundingSphere = boundingSphere;
pointCloud.clippingPlanes = clippingPlanes;
pointCloud.isClipped = defined(clippingPlanes) && clippingPlanes.enabled && tile._isClipped;
pointCloud.clippingPlanesDirty = tile.clippingPlanesDirty;
Expand Down
23 changes: 21 additions & 2 deletions Source/Scene/TimeDynamicPointCloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ define([
}).then(function(arrayBuffer) {
frame.pointCloud = new PointCloud({
arrayBuffer : arrayBuffer,
cull : true,
fragmentShaderLoaded : getFragmentShaderLoaded,
uniformMapLoaded : getUniformMapLoaded(that),
pickIdLoaded : getPickIdLoaded
Expand Down Expand Up @@ -373,6 +374,24 @@ define([

var scratchModelMatrix = new Matrix4();

function getGeometricError(that, pointCloud) {
var pointCloudShading = that.pointCloudShading;
if (defined(pointCloudShading) && defined(pointCloudShading.baseResolution)) {
return pointCloudShading.baseResolution;
}
return CesiumMath.cbrt(pointCloud.boundingSphere.volume() / pointCloud.pointsLength);
}

function getMaximumAttenuation(that) {
var pointCloudShading = that.pointCloudShading;
if (defined(pointCloudShading) && defined(pointCloudShading.maximumAttenuation)) {
return pointCloudShading.maximumAttenuation;
}

// Return a hardcoded maximum attenuation. For a tileset this would instead be the maximum screen space error.
return 10.0;
}

function renderFrame(that, frame, timeSinceLoad, isClipped, clippingPlanesDirty, frameState) {
var pointCloud = frame.pointCloud;
var transform = defaultValue(frame.transform, Matrix4.IDENTITY);
Expand All @@ -388,9 +407,9 @@ define([
var pointCloudShading = that.pointCloudShading;
if (defined(pointCloudShading)) {
pointCloud.attenuation = pointCloudShading.attenuation;
pointCloud.geometricError = 10.0; // TODO : If we had a bounding volume we could derive it
pointCloud.geometricError = getGeometricError(that, pointCloud);
pointCloud.geometricErrorScale = pointCloudShading.geometricErrorScale;
pointCloud.maximumAttenuation = defined(pointCloudShading.maximumAttenuation) ? pointCloudShading.maximumAttenuation : 10;
pointCloud.maximumAttenuation = getMaximumAttenuation(that);
}
pointCloud.update(frameState);
frame.touchedFrameNumber = frameState.frameNumber;
Expand Down

0 comments on commit f6dc8ee

Please sign in to comment.