Skip to content

Commit

Permalink
Merge pull request #2329 from AnalyticalGraphicsInc/geometry-perf
Browse files Browse the repository at this point in the history
Improve extruded polygon and wall performance.
  • Loading branch information
pjcozzi committed Dec 17, 2014
2 parents 890357c + d0b128c commit 297b879
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 161 deletions.
1 change: 0 additions & 1 deletion Apps/Sandcastle/gallery/Wall.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@
maximumHeights: maximumHeights,
minimumHeights: minimumHeights,
vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT

}),
attributes : {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE)
Expand Down
10 changes: 5 additions & 5 deletions Source/Core/IntersectionTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ define([
var sScratch = new Cartesian3();
var closestScratch = new Cartesian3();
var surfPointScratch = new Cartographic();

/**
* Provides the point along the ray which is nearest to the ellipsoid.
*
Expand All @@ -593,19 +594,18 @@ define([
var position = ray.origin;
var direction = ray.direction;

var normal = ellipsoid.geodeticSurfaceNormal(position);

var normal = ellipsoid.geodeticSurfaceNormal(position, firstAxisScratch);
if (Cartesian3.dot(direction, normal) >= 0.0) { // The location provided is the closest point in altitude
return position;
}

var intersects = defined(this.rayEllipsoid(ray, ellipsoid));

// Compute the scaled direction vector.
var f = ellipsoid.transformPositionToScaledSpace(direction);
var f = ellipsoid.transformPositionToScaledSpace(direction, firstAxisScratch);

// Constructs a basis from the unit scaled direction vector. Construct its rotation and transpose.
var firstAxis = Cartesian3.normalize(f, firstAxisScratch);
var firstAxis = Cartesian3.normalize(f, f);
var reference = Cartesian3.mostOrthogonalAxis(f, referenceScratch);
var secondAxis = Cartesian3.normalize(Cartesian3.cross(reference, firstAxis, secondAxisScratch), secondAxisScratch);
var thirdAxis = Cartesian3.normalize(Cartesian3.cross(firstAxis, secondAxis, thirdAxisScratch), thirdAxisScratch);
Expand Down Expand Up @@ -667,7 +667,7 @@ define([
altitude = Cartesian3.magnitude(Cartesian3.subtract(closest, position, referenceScratch)) * Math.sqrt(1.0 - maximumValue * maximumValue);
altitude = intersects ? -altitude : altitude;
surfacePoint.height = altitude;
return ellipsoid.cartographicToCartesian(surfacePoint);
return ellipsoid.cartographicToCartesian(surfacePoint, new Cartesian3());
}

return undefined;
Expand Down
41 changes: 35 additions & 6 deletions Source/Core/Math.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ define([
* @param {Number} value The value to constrain.
* @param {Number} min The minimum value.
* @param {Number} max The maximum value.
* @returns The value clamped so that min <= value <= max.
* @returns {Number} The value clamped so that min <= value <= max.
*/
CesiumMath.clamp = function(value, min, max) {
//>>includeStart('debug', pragmas.debug);
Expand Down Expand Up @@ -718,7 +718,7 @@ define([
* Generates a random number in the range of [0.0, 1.0)
* using a Mersenne twister.
*
* @returns A random number in the range of [0.0, 1.0).
* @returns {Number} A random number in the range of [0.0, 1.0).
*
* @see CesiumMath.setRandomNumberSeed
* @see {@link http://en.wikipedia.org/wiki/Mersenne_twister|Mersenne twister on Wikipedia}
Expand All @@ -731,25 +731,54 @@ define([
* Computes <code>Math.acos(value)</acode>, but first clamps <code>value</code> to the range [-1.0, 1.0]
* so that the function will never return NaN.
*
* @param value The value for which to compute acos.
* @returns {number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0,
* @param {Number} value The value for which to compute acos.
* @returns {Number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0,
* whichever is closer, if the value is outside the range.
*/
CesiumMath.acosClamped = function(value) {
//>>includeStart('debug', pragmas.debug);
if (!defined(value)) {
throw new DeveloperError('value is required.');
}
//>>includeEnd('debug');
return Math.acos(CesiumMath.clamp(value, -1.0, 1.0));
};

/**
* Computes <code>Math.asin(value)</acode>, but first clamps <code>value</code> to the range [-1.0, 1.0]
* so that the function will never return NaN.
*
* @param value The value for which to compute asin.
* @returns {number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0,
* @param {Number} value The value for which to compute asin.
* @returns {Number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0,
* whichever is closer, if the value is outside the range.
*/
CesiumMath.asinClamped = function(value) {
//>>includeStart('debug', pragmas.debug);
if (!defined(value)) {
throw new DeveloperError('value is required.');
}
//>>includeEnd('debug');
return Math.asin(CesiumMath.clamp(value, -1.0, 1.0));
};

/**
* Finds the chord length between two points given the circle's radius and the angle between the points.
*
* @param {Number} angle The angle between the two points.
* @param {Number} radius The radius of the circle.
* @returns {Number} The chord length.
*/
CesiumMath.chordLength = function(angle, radius) {
//>>includeStart('debug', pragmas.debug);
if (!defined(angle)) {
throw new DeveloperError('angle is required.');
}
if (!defined(radius)) {
throw new DeveloperError('radius is required.');
}
//>>includeEnd('debug');
return 2.0 * radius * Math.sin(angle * 0.5);
};

return CesiumMath;
});
116 changes: 78 additions & 38 deletions Source/Core/PolygonGeometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,51 +329,89 @@ define([
return geometry;
}

var computeWallIndicesSubdivided = [];

function computeWallIndices(positions, ellipsoid, granularity, perPositionHeight){
var edgePositions = [];
var subdividedEdge;
var edgeIndex;
var UL, UR, LL, LR;
var edgePositions;
var topEdgeLength;
var i;

var length = positions.length;
var p1;
var p2;

var length = positions.length;
var index = 0;

if (!perPositionHeight) {
var radius = ellipsoid.maximumRadius;
var minDistance = 2.0 * radius * Math.sin(granularity * 0.5);
var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);

var numVertices = 0;
for (i = 0; i < length; i++) {
numVertices += PolygonGeometryLibrary.subdivideLineCount(positions[i], positions[(i + 1) % length], minDistance);
}

topEdgeLength = (numVertices + length) * 3;
edgePositions = new Array(topEdgeLength * 2);
for (i = 0; i < length; i++) {
p1 = positions[i];
p2 = positions[(i + 1) % length];
subdividedEdge = PolygonGeometryLibrary.subdivideLine(p1, p2, minDistance);
subdividedEdge.push(p2.x, p2.y, p2.z);
edgePositions = edgePositions.concat(subdividedEdge);

var tempPositions = PolygonGeometryLibrary.subdivideLine(p1, p2, minDistance, computeWallIndicesSubdivided);
var tempPositionsLength = tempPositions.length;
for (var j = 0; j < tempPositionsLength; ++j, ++index) {
edgePositions[index] = tempPositions[j];
edgePositions[index + topEdgeLength] = tempPositions[j];
}

edgePositions[index] = p2.x;
edgePositions[index + topEdgeLength] = p2.x;
++index;

edgePositions[index] = p2.y;
edgePositions[index + topEdgeLength] = p2.y;
++index;

edgePositions[index] = p2.z;
edgePositions[index + topEdgeLength] = p2.z;
++index;
}
} else {
topEdgeLength = length * 3 * 2;
edgePositions = new Array(topEdgeLength * 2);
for (i = 0; i < length; i++) {
p1 = positions[i];
p2 = positions[(i + 1) % length];
edgePositions.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
edgePositions[index] = edgePositions[index + topEdgeLength] = p1.x;
++index;
edgePositions[index] = edgePositions[index + topEdgeLength] = p1.y;
++index;
edgePositions[index] = edgePositions[index + topEdgeLength] = p1.z;
++index;
edgePositions[index] = edgePositions[index + topEdgeLength] = p2.x;
++index;
edgePositions[index] = edgePositions[index + topEdgeLength] = p2.y;
++index;
edgePositions[index] = edgePositions[index + topEdgeLength] = p2.z;
++index;
}
}

edgePositions = edgePositions.concat(edgePositions);
length = edgePositions.length;
var indices = IndexDatatype.createTypedArray(length / 3, length - positions.length * 6);
edgeIndex = 0;
var edgeIndex = 0;
length /= 6;

for (i = 0; i < length; i++) {
UL = i;
UR = UL + 1;
var UL = i;
var UR = UL + 1;
var LL = UL + length;
var LR = LL + 1;

p1 = Cartesian3.fromArray(edgePositions, UL * 3, p1Scratch);
p2 = Cartesian3.fromArray(edgePositions, UR * 3, p2Scratch);
if (Cartesian3.equalsEpsilon(p1, p2, CesiumMath.EPSILON6)) {
continue;
}
LL = UL + length;
LR = LL + 1;

indices[edgeIndex++] = UL;
indices[edgeIndex++] = LL;
indices[edgeIndex++] = UR;
Expand All @@ -399,15 +437,20 @@ define([

function createGeometryFromPositionsExtruded(ellipsoid, positions, granularity, hierarchy, perPositionHeight) {
var topGeo = createGeometryFromPositions(ellipsoid, positions, granularity, perPositionHeight).geometry;

var edgePoints = topGeo.attributes.position.values;
var indices = topGeo.indices;

var topBottomPositions = edgePoints.concat(edgePoints);
var numPositions = topBottomPositions.length / 3;

var newIndices = IndexDatatype.createTypedArray(numPositions, indices.length * 2);
newIndices.set(indices);
var ilength = indices.length;

var i;
var length = numPositions / 2;

for (i = 0; i < ilength; i += 3) {
var i0 = newIndices[i] + length;
var i1 = newIndices[i + 1] + length;
Expand All @@ -417,6 +460,7 @@ define([
newIndices[i + 1 + ilength] = i1;
newIndices[i + 2 + ilength] = i0;
}

var topAndBottomGeo = new Geometry({
attributes : new GeometryAttributes({
position : new GeometryAttribute({
Expand All @@ -432,10 +476,10 @@ define([
var geos = {
topAndBottom : new GeometryInstance({
geometry : topAndBottomGeo
})
}),
walls : []
};

geos.walls = [];
var outerRing = hierarchy.outerRing;
var tangentPlane = EllipsoidTangentPlane.fromPoints(outerRing, ellipsoid);
var positions2D = tangentPlane.projectPointsOntoPlane(outerRing, createGeometryFromPositionsExtrudedPositions);
Expand Down Expand Up @@ -732,29 +776,25 @@ define([
if (extrude) {
for (i = 0; i < polygons.length; i++) {
geometry = createGeometryFromPositionsExtruded(ellipsoid, polygons[i], granularity, polygonHierarchy[i], perPositionHeight);
if (defined(geometry)) {
topAndBottom = geometry.topAndBottom;
topAndBottom.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(topAndBottom.geometry, height, extrudedHeight, ellipsoid, perPositionHeight);
topAndBottom.geometry = computeAttributes(vertexFormat, topAndBottom.geometry, outerPositions, ellipsoid, stRotation, true, false);
geometries.push(topAndBottom);

walls = geometry.walls;
for ( var k = 0; k < walls.length; k++) {
var wall = walls[k];
wall.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(wall.geometry, height, extrudedHeight, ellipsoid, perPositionHeight);
wall.geometry = computeAttributes(vertexFormat, wall.geometry, outerPositions, ellipsoid, stRotation, true, true);
geometries.push(wall);
}
topAndBottom = geometry.topAndBottom;
topAndBottom.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(topAndBottom.geometry, height, extrudedHeight, ellipsoid, perPositionHeight);
topAndBottom.geometry = computeAttributes(vertexFormat, topAndBottom.geometry, outerPositions, ellipsoid, stRotation, true, false);
geometries.push(topAndBottom);

walls = geometry.walls;
for ( var k = 0; k < walls.length; k++) {
var wall = walls[k];
wall.geometry = PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(wall.geometry, height, extrudedHeight, ellipsoid, perPositionHeight);
wall.geometry = computeAttributes(vertexFormat, wall.geometry, outerPositions, ellipsoid, stRotation, true, true);
geometries.push(wall);
}
}
} else {
for (i = 0; i < polygons.length; i++) {
geometry = createGeometryFromPositions(ellipsoid, polygons[i], granularity, perPositionHeight);
if (defined(geometry)) {
geometry.geometry = PolygonPipeline.scaleToGeodeticHeight(geometry.geometry, height, ellipsoid, !perPositionHeight);
geometry.geometry = computeAttributes(vertexFormat, geometry.geometry, outerPositions, ellipsoid, stRotation, false, false);
geometries.push(geometry);
}
geometry.geometry = PolygonPipeline.scaleToGeodeticHeight(geometry.geometry, height, ellipsoid, !perPositionHeight);
geometry.geometry = computeAttributes(vertexFormat, geometry.geometry, outerPositions, ellipsoid, stRotation, false, false);
geometries.push(geometry);
}
}

Expand Down
4 changes: 1 addition & 3 deletions Source/Core/PolygonOutlineGeometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,7 @@ define([

var geometry;
var geometries = [];

var radius = ellipsoid.maximumRadius;
var minDistance = 2.0 * radius * Math.sin(granularity * 0.5);
var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);

if (extrude) {
for (i = 0; i < polygons.length; i++) {
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/PolygonPipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ define([
var edges = {};

var radius = ellipsoid.maximumRadius;
var minDistance = 2.0 * radius * Math.sin(granularity * 0.5);
var minDistance = CesiumMath.chordLength(granularity, radius);
var minDistanceSqrd = minDistance * minDistance;

while (triangles.length > 0) {
Expand Down
12 changes: 7 additions & 5 deletions Source/Core/PolylineGeometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ define([
VertexFormat) {
"use strict";

function interpolateColors(p0, p1, color0, color1, granularity) {
var numPoints = PolylinePipeline.numberOfPoints(p0, p1, granularity);
function interpolateColors(p0, p1, color0, color1, minDistance) {
var numPoints = PolylinePipeline.numberOfPoints(p0, p1, minDistance);
var colors = new Array(numPoints);
var i;

Expand Down Expand Up @@ -160,6 +160,8 @@ define([
var granularity = polylineGeometry._granularity;
var ellipsoid = polylineGeometry._ellipsoid;

var minDistance = CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);

var i;
var j;
var k;
Expand Down Expand Up @@ -192,9 +194,9 @@ define([

if (perVertex && i < colors.length) {
c1 = colors[i+1];
newColors = newColors.concat(interpolateColors(p0, p1, c0, c1, granularity));
newColors = newColors.concat(interpolateColors(p0, p1, c0, c1, minDistance));
} else {
var l = PolylinePipeline.numberOfPoints(p0, p1, granularity);
var l = PolylinePipeline.numberOfPoints(p0, p1, minDistance);
for (j = 0; j < l; j++) {
newColors.push(Color.clone(c0));
}
Expand All @@ -206,7 +208,7 @@ define([

positions = PolylinePipeline.generateCartesianArc({
positions: positions,
granularity: granularity,
minDistance: minDistance,
ellipsoid: ellipsoid,
height: heights
});
Expand Down
Loading

0 comments on commit 297b879

Please sign in to comment.