Modularize desired chunk level calculation for easy testing of different approaches

This commit is contained in:
Erik Broberg
2016-06-13 16:30:22 -04:00
parent ff3ac1b368
commit 84e6e9a7af
8 changed files with 160 additions and 123 deletions
+107 -105
View File
@@ -77,123 +77,21 @@ namespace openspace {
const Camera& camRef = savedCamera != nullptr ? *savedCamera : data.camera;
RenderData myRenderData = { camRef, data.position, data.doPerformanceMeasurement };
_isVisible = true;
if (_owner->testIfCullable(*this, myRenderData)) {
_isVisible = false;
return Status::WANT_MERGE;
}
//int desiredLevel = desiredLevelByDistance(myRenderData);
int desiredLevel = desiredLevelByProjectedArea(myRenderData);
// clamp level
desiredLevel = glm::clamp(desiredLevel, _owner->minSplitDepth, _owner->maxSplitDepth);
int desiredLevel = _owner->getDesiredLevel(*this, myRenderData);
if (desiredLevel < _index.level) return Status::WANT_MERGE;
else if (_index.level < desiredLevel) return Status::WANT_SPLIT;
else return Status::DO_NOTHING;
}
int Chunk::desiredLevelByDistance(const RenderData& data) const {
const Ellipsoid& ellipsoid = _owner->ellipsoid();
Vec3 cameraPosition = data.camera.positionVec3();
Geodetic2 pointOnPatch = _surfacePatch.closestPoint(
ellipsoid.cartesianToGeodetic2(cameraPosition));
Vec3 globePosition = data.position.dvec3();
Vec3 patchPosition = globePosition + ellipsoid.cartesianSurfacePosition(pointOnPatch);
Vec3 cameraToChunk = patchPosition - cameraPosition;
// Calculate desired level based on distance
Scalar distance = glm::length(cameraToChunk);
_owner->minDistToCamera = fmin(_owner->minDistToCamera, distance);
Scalar scaleFactor = _owner->lodScaleFactor * ellipsoid.minimumRadius();;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = ceil(log2(projectedScaleFactor));
return desiredLevel;
}
int Chunk::desiredLevelByProjectedArea(const RenderData& data) const {
const Ellipsoid& ellipsoid = _owner->ellipsoid();
Vec3 cameraPosition = data.camera.positionVec3();
Vec3 globePosition = data.position.dvec3();
Vec3 cameraToEllipseCenter = globePosition - cameraPosition;
const Geodetic2 nwCorner = _surfacePatch.northWestCorner();
const Geodetic2 neCorner = _surfacePatch.northEastCorner();
const Geodetic2 swCorner = _surfacePatch.southWestCorner();
const Geodetic2 seCorner = _surfacePatch.southEastCorner();
Geodetic2 camPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
struct CornerDist {
Geodetic2 corner;
float dist;
};
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 = _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;;
}
std::sort(cornerDists.begin(), cornerDists.end(), byDist);
BoundingHeights heights = getBoundingHeights();
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 };
Vec3 A = cameraToEllipseCenter + ellipsoid.cartesianPosition(c0);
Vec3 B = cameraToEllipseCenter + ellipsoid.cartesianPosition(c1);
Vec3 C = cameraToEllipseCenter + ellipsoid.cartesianPosition(c2);
Vec3 D = cameraToEllipseCenter + ellipsoid.cartesianPosition(c3);
// Project points onto unit sphere
A = glm::normalize(A);
B = glm::normalize(B);
C = glm::normalize(C);
D = glm::normalize(D);
/*
A-----____
| '''-----B
| __--' |
| __--'' |
C-----------------D
*/
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 scaledArea = _owner->lodScaleFactor * projectedChunkAreaApprox;
return _index.level + round(scaledArea - 1);
}
Chunk::BoundingHeights Chunk::getBoundingHeights() const {
BoundingHeights boundingHeights;
BoundingHeights boundingHeights;
boundingHeights.max = _owner->chunkHeight;
boundingHeights.min = 0;
boundingHeights.available = false;
@@ -221,6 +119,110 @@ namespace openspace {
void Chunk::render(const RenderData& data) const {
_owner->getPatchRenderer().renderChunk(*this, data);
}
//////////////////////////////////////////////////////////////////////////////////////
// Chunk evaluation //
//////////////////////////////////////////////////////////////////////////////////////
int EvaluateChunkLevelByDistance::getDesiredLevel(const Chunk& chunk, const RenderData& data) const {
ChunkedLodGlobe const * globe = chunk.owner();
const Ellipsoid& ellipsoid = globe->ellipsoid();
Vec3 cameraPosition = data.camera.positionVec3();
Geodetic2 pointOnPatch = chunk.surfacePatch().closestPoint(
ellipsoid.cartesianToGeodetic2(cameraPosition));
Vec3 globePosition = data.position.dvec3();
Vec3 patchPosition = globePosition + ellipsoid.cartesianSurfacePosition(pointOnPatch);
Vec3 cameraToChunk = patchPosition - cameraPosition;
// Calculate desired level based on distance
Scalar distance = glm::length(cameraToChunk);
Scalar scaleFactor = globe->lodScaleFactor * ellipsoid.minimumRadius();;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = ceil(log2(projectedScaleFactor));
return desiredLevel;
}
int EvaluateChunkLevelByProjectedArea::getDesiredLevel(const Chunk& chunk, const RenderData& data) const {
ChunkedLodGlobe const * globe = chunk.owner();
const Ellipsoid& ellipsoid = globe->ellipsoid();
Vec3 cameraPosition = data.camera.positionVec3();
Vec3 globePosition = data.position.dvec3();
Vec3 cameraToEllipseCenter = globePosition - cameraPosition;
Geodetic2 camPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
struct CornerDist {
Geodetic2 corner;
float dist;
};
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;;
}
std::sort(cornerDists.begin(), cornerDists.end(), byDist);
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
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 };
Vec3 A = cameraToEllipseCenter + ellipsoid.cartesianPosition(c0);
Vec3 B = cameraToEllipseCenter + ellipsoid.cartesianPosition(c1);
Vec3 C = cameraToEllipseCenter + ellipsoid.cartesianPosition(c2);
Vec3 D = cameraToEllipseCenter + ellipsoid.cartesianPosition(c3);
// Project points onto unit sphere
A = glm::normalize(A);
B = glm::normalize(B);
C = glm::normalize(C);
D = glm::normalize(D);
/*
A-----____
| '''-----B
| __--' |
| __--'' |
C-----------------D
*/
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 scaledArea = globe->lodScaleFactor * projectedChunkAreaApprox;
return chunk.index().level + round(scaledArea - 1);
}
int EvaluateChunkLevelByAvailableTileData::getDesiredLevel(const Chunk& chunk, const RenderData& data) const {
return -1;
}
} // namespace openspace
+25 -3
View File
@@ -48,7 +48,7 @@ namespace openspace {
bool available;
};
enum class Status{
enum class Status {
DO_NOTHING,
WANT_MERGE,
WANT_SPLIT,
@@ -71,8 +71,6 @@ namespace openspace {
private:
int desiredLevelByDistance(const RenderData& data) const;
int desiredLevelByProjectedArea(const RenderData& data) const;
ChunkedLodGlobe* _owner;
ChunkIndex _index;
@@ -81,6 +79,30 @@ namespace openspace {
};
class DesiredChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const = 0;
};
class EvaluateChunkLevelByDistance : public DesiredChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
class EvaluateChunkLevelByProjectedArea : public DesiredChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
class EvaluateChunkLevelByAvailableTileData : public DesiredChunkLevelEvaluator {
public:
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
};
}
@@ -60,23 +60,26 @@ namespace openspace {
, _leftRoot(new ChunkNode(Chunk(this, LEFT_HEMISPHERE_INDEX)))
, _rightRoot(new ChunkNode(Chunk(this, RIGHT_HEMISPHERE_INDEX)))
, minSplitDepth(2)
, maxSplitDepth(22)
, maxSplitDepth(15)
, _savedCamera(nullptr)
, _tileProviderManager(tileProviderManager)
{
auto geometry = std::shared_ptr<SkirtedGrid>(new SkirtedGrid(
segmentsPerPatch,
segmentsPerPatch,
auto geometry = std::make_shared<SkirtedGrid>(
(unsigned int) segmentsPerPatch,
(unsigned int) segmentsPerPatch,
TriangleSoup::Positions::No,
TriangleSoup::TextureCoordinates::Yes,
TriangleSoup::Normals::No));
TriangleSoup::Normals::No);
_chunkCullers.push_back(new HorizonCuller());
_chunkCullers.push_back(new FrustumCuller(AABB3(vec3(-1, -1, 0), vec3(1, 1, 1e35))));
_patchRenderer.reset(new ChunkRenderer(geometry, tileProviderManager));
//_chunkEvaluater = std::make_unique<EvaluateChunkByArea>();
_chunkEvaluater = std::make_unique<EvaluateChunkLevelByDistance>();
_patchRenderer = std::make_unique<ChunkRenderer>(geometry, tileProviderManager);
}
ChunkedLodGlobe::~ChunkedLodGlobe() {
@@ -105,7 +108,7 @@ namespace openspace {
return *_patchRenderer;
}
bool ChunkedLodGlobe::testIfCullable(const Chunk& chunk, const RenderData& renderData) {
bool ChunkedLodGlobe::testIfCullable(const Chunk& chunk, const RenderData& renderData) const {
if (doHorizonCulling && _chunkCullers[0]->isCullable(chunk, renderData)) {
return true;
}
@@ -115,6 +118,12 @@ namespace openspace {
return false;
}
int ChunkedLodGlobe::getDesiredLevel(const Chunk& chunk, const RenderData& renderData) const {
int desiredLevel = _chunkEvaluater->getDesiredLevel(chunk, renderData);
desiredLevel = glm::clamp(desiredLevel, minSplitDepth, maxSplitDepth);
return desiredLevel;
}
void ChunkedLodGlobe::render(const RenderData& data){
minDistToCamera = INFINITY;
@@ -72,7 +72,8 @@ namespace openspace {
void setStateMatrix(const glm::dmat3& stateMatrix);
bool testIfCullable(const Chunk& chunk, const RenderData& renderData);
bool testIfCullable(const Chunk& chunk, const RenderData& renderData) const;
int getDesiredLevel(const Chunk& chunk, const RenderData& renderData) const;
double minDistToCamera;
@@ -132,6 +133,8 @@ namespace openspace {
std::vector<ChunkCuller*> _chunkCullers;
std::unique_ptr<DesiredChunkLevelEvaluator> _chunkEvaluater;
const Ellipsoid& _ellipsoid;
glm::dmat3 _stateMatrix;
-3
View File
@@ -49,9 +49,6 @@ namespace openspace {
namespace openspace {
class ChunkNode {
public:
ChunkNode(const Chunk& chunk, ChunkNode* parent = nullptr);
+5 -2
View File
@@ -32,6 +32,7 @@
#include <modules/globebrowsing/geometry/ellipsoid.h>
#include <modules/globebrowsing/geometry/convexhull.h>
#include <modules/globebrowsing/meshes/trianglesoup.h>
@@ -83,6 +84,7 @@ namespace openspace {
// Create a bounding box that fits the patch corners
AABB3 bounds; // in screen space
int numPositiveZ = 0;
std::vector<vec2> screenSpaceCorners(8);
for (size_t i = 0; i < 8; i++) {
Quad q = (Quad)(i % 4);
double cornerHeight = i < 4 ? minCornerHeight : maxCornerHeight;
@@ -90,10 +92,11 @@ namespace openspace {
dvec4 cornerModelSpace = dvec4(ellipsoid.cartesianPosition(cornerGeodetic), 1);
vec4 cornerClippingSpace = modelViewProjectionTransform * cornerModelSpace;
vec3 cornerScreenSpace = (1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace.xyz();
screenSpaceCorners[i] = vec2(cornerScreenSpace);
bounds.expand(cornerScreenSpace);
}
return !bounds.intersects(_viewFrustum);
return !_viewFrustum.intersects(bounds);
}
@@ -81,7 +81,7 @@ namespace openspace {
{
// Keep removing top while the angle formed by points next-to-top,
// top, and points[i] makes a non-left turn
while (orientation(oneBelowTop(S), S.top(), points[i]) != 2)
while (orientation(oneBelowTop(S), S.top(), points[i]) == 1)
S.pop();
S.push(points[i]);
}
@@ -75,6 +75,7 @@ namespace openspace {
virtual ~TileProvider() { }
virtual TileAndTransform getHighestResolutionTile(ChunkIndex chunkIndex, int parents = 0) = 0;
//virtual Tile getTile(ChunkIndex chunkIndex) = 0;
virtual TileDepthTransform depthTransform() = 0;
virtual void prerender() = 0;
};