mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-25 21:48:57 -05:00
Improve performance of chunk level evaluator by projected area
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user