mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-24 04:58:59 -05:00
Modularize desired chunk level calculation for easy testing of different approaches
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -49,9 +49,6 @@ namespace openspace {
|
||||
namespace openspace {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ChunkNode {
|
||||
public:
|
||||
ChunkNode(const Chunk& chunk, ChunkNode* parent = nullptr);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user