Improve performance of chunk level evaluator by projected area

This commit is contained in:
Erik Broberg
2016-07-12 13:10:20 -04:00
parent edf114cda2
commit 0d1c042b0e
@@ -77,78 +77,84 @@ namespace openspace {
ChunkedLodGlobe const * globe = chunk.owner();
const Ellipsoid& ellipsoid = globe->ellipsoid();
Vec3 cameraPosition =
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
Vec3 cameraToEllipsoidCenter = - cameraPosition;
glm::dvec4 cameraPositionModelSpace = glm::dvec4(data.camera.positionVec3(), 1);
Vec3 cameraPosition = glm::dvec3(inverseModelTransform * cameraPositionModelSpace);
Vec3 cameraToEllipsoidCenter = -cameraPosition;
Geodetic2 camPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
/*
struct CornerDist {
Geodetic2 corner;
float dist;
};
Geodetic2 cameraGeodeticPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
// Approach:
// The projected area of the chunk will be calculated based on a small area that
// is close to the camera, and the scaled up to represent the full area.
// The advantage of doing this is that it will better handle the cases where the
// full patch is very curved (e.g. stretches from latitude 0 to 90 deg).
const Geodetic2 center = chunk.surfacePatch().center();
const Geodetic2 closestCorner = chunk.surfacePatch().closestCorner(cameraGeodeticPos);
struct {
bool operator()(const CornerDist& a, const CornerDist& b) {
return a.dist < b.dist;
}
} byDist;
std::vector<CornerDist> cornerDists(4);
for (size_t i = 0; i < 4; i++) {
const Geodetic2& c = chunk.surfacePatch().getCorner((Quad)i);
Geodetic2 diff = (camPos - c);
float latDiff = fAngle::fromRadians(diff.lat).getNormalizedAround(fAngle::ZERO).asRadians();
float lonDiff = fAngle::fromRadians(diff.lon).getNormalizedAround(fAngle::ZERO).asRadians();
cornerDists[i].corner = c;
cornerDists[i].dist = latDiff*latDiff + lonDiff*lonDiff;;
}
// Camera
// |
// V
//
// oo
// [ ]<
// *geodetic space*
//
// closestCorner
// +-----------------+ <-- north east corner
// | |
// | center |
// | |
// +-----------------+ <-- south east corner
std::sort(cornerDists.begin(), cornerDists.end(), byDist);
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
const Geodetic3 c0 = { closestCorner, heights.min };
const Geodetic3 c1 = { Geodetic2(center.lat, closestCorner.lon), heights.min };
const Geodetic3 c2 = { Geodetic2(closestCorner.lat, center.lon), heights.min };
// Camera
// |
// V
//
// oo
// [ ]<
// *geodetic space*
//
// c0-------c2-------+ <-- north east corner
// | |
// c1 center |
// | |
// +-----------------+ <-- south east corner
const Geodetic3 c0 = { cornerDists[0].corner, heights.min };
const Geodetic3 c1 = { cornerDists[1].corner, heights.min };
const Geodetic3 c2 = { cornerDists[2].corner, heights.max };
const Geodetic3 c3 = { cornerDists[3].corner, heights.max };
*/
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
const Geodetic3 c0 = { chunk.surfacePatch().getCorner((Quad)0), heights.min };
const Geodetic3 c1 = { chunk.surfacePatch().getCorner((Quad)1), heights.min };
const Geodetic3 c2 = { chunk.surfacePatch().getCorner((Quad)2), heights.min };
const Geodetic3 c3 = { chunk.surfacePatch().getCorner((Quad)3), heights.min };
// Go from geodetic to cartesian space
Vec3 A = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c0);
Vec3 B = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c1);
Vec3 C = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c2);
Vec3 D = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c3);
// Project points onto unit sphere
// Project onto unit sphere
A = glm::normalize(A);
B = glm::normalize(B);
C = glm::normalize(C);
D = glm::normalize(D);
// Camera *cartesian space*
// | +--------+---+
// V __--'' __--'' /
// C-------center---- +
// oo / / /
//[ ]< A-------B----------+
//
/*
A-----____
| '''-----B
| __--' |
| __--'' |
C-----------------D
*/
// If the geodetic patch is small (i.e. has small width), that means the patch in
// cartesian space will be almost flat, and in turn, the triangle ABC will roughly
// correspond to 1/8 of the full area
const Vec3 AB = B - A;
const Vec3 AC = C - A;
const Vec3 DC = C - D;
const Vec3 DB = B - D;
double areaTriangle1 = 0.5 * glm::length(glm::cross(AC, AB));
double areaTriangle2 = 0.5 * glm::length(glm::cross(DC, DB));
double projectedChunkAreaApprox = areaTriangle1 + areaTriangle2;
double areaABC = 0.5 * glm::length(glm::cross(AC, AB));
double projectedChunkAreaApprox = 8 * areaABC;
double scaledArea = globe->lodScaleFactor * projectedChunkAreaApprox;
return chunk.index().level + round(scaledArea - 1);