mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-03 09:20:26 -05:00
Clean up and document Chunk code
This commit is contained in:
@@ -43,14 +43,15 @@ namespace globebrowsing {
|
||||
|
||||
const float Chunk::DEFAULT_HEIGHT = 0.0f;
|
||||
|
||||
Chunk::Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex, bool initVisible)
|
||||
Chunk::Chunk(
|
||||
const RenderableGlobe& owner,
|
||||
const TileIndex& tileIndex,
|
||||
bool initVisible)
|
||||
: _owner(owner)
|
||||
, _surfacePatch(tileIndex)
|
||||
, _tileIndex(tileIndex)
|
||||
, _isVisible(initVisible)
|
||||
{
|
||||
|
||||
}
|
||||
{ }
|
||||
|
||||
const GeodeticPatch& Chunk::surfacePatch() const {
|
||||
return _surfacePatch;
|
||||
@@ -68,15 +69,12 @@ namespace globebrowsing {
|
||||
return _isVisible;
|
||||
}
|
||||
|
||||
void Chunk::setIndex(const TileIndex& index) {
|
||||
_tileIndex = index;
|
||||
_surfacePatch = GeodeticPatch(index);
|
||||
}
|
||||
|
||||
Chunk::Status Chunk::update(const RenderData& data) {
|
||||
auto savedCamera = _owner.savedCamera();
|
||||
const Camera& camRef = savedCamera != nullptr ? *savedCamera : data.camera;
|
||||
RenderData myRenderData = { camRef, data.position, data.doPerformanceMeasurement };
|
||||
const Camera& camRef =
|
||||
savedCamera != nullptr ? *savedCamera : data.camera;
|
||||
RenderData myRenderData =
|
||||
{ camRef, data.position, data.doPerformanceMeasurement };
|
||||
|
||||
|
||||
_isVisible = true;
|
||||
@@ -102,13 +100,17 @@ namespace globebrowsing {
|
||||
// One must also handle how to sample pick one out of multiplte heightmaps
|
||||
auto layerManager = owner().chunkedLodGlobe()->layerManager();
|
||||
|
||||
|
||||
auto heightMapProviders = layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
auto heightMapProviders =
|
||||
layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
|
||||
|
||||
// The raster of a height map is the first one. We assume that the height map is
|
||||
// a single raster image. If it is not we will just use the first raster
|
||||
// (that is channel 0).
|
||||
size_t HEIGHT_CHANNEL = 0;
|
||||
const LayerGroup& heightmaps = layerManager->layerGroup(LayerManager::HeightLayers);
|
||||
std::vector<ChunkTile> tiles = TileSelector::getTilesSortedByHighestResolution(heightmaps, _tileIndex);
|
||||
const LayerGroup& heightmaps =
|
||||
layerManager->layerGroup(LayerManager::HeightLayers);
|
||||
std::vector<ChunkTile> tiles =
|
||||
TileSelector::getTilesSortedByHighestResolution(heightmaps, _tileIndex);
|
||||
bool lastHadMissingData = true;
|
||||
for (auto tile : tiles) {
|
||||
bool goodTile = tile.tile.status == Tile::Status::OK;
|
||||
@@ -119,8 +121,10 @@ namespace globebrowsing {
|
||||
|
||||
if (!boundingHeights.available) {
|
||||
if (preprocessData->hasMissingData[HEIGHT_CHANNEL]) {
|
||||
boundingHeights.min = std::min(DEFAULT_HEIGHT, preprocessData->minValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.max = std::max(DEFAULT_HEIGHT, preprocessData->maxValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.min = std::min(
|
||||
DEFAULT_HEIGHT, preprocessData->minValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.max = std::max(
|
||||
DEFAULT_HEIGHT, preprocessData->maxValues[HEIGHT_CHANNEL]);
|
||||
}
|
||||
else {
|
||||
boundingHeights.min = preprocessData->minValues[HEIGHT_CHANNEL];
|
||||
@@ -129,8 +133,10 @@ namespace globebrowsing {
|
||||
boundingHeights.available = true;
|
||||
}
|
||||
else {
|
||||
boundingHeights.min = std::min(boundingHeights.min, preprocessData->minValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.max = std::max(boundingHeights.max, preprocessData->maxValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.min = std::min(
|
||||
boundingHeights.min, preprocessData->minValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.max = std::max(
|
||||
boundingHeights.max, preprocessData->maxValues[HEIGHT_CHANNEL]);
|
||||
}
|
||||
lastHadMissingData = preprocessData->hasMissingData[HEIGHT_CHANNEL];
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ namespace globebrowsing {
|
||||
|
||||
class Chunk {
|
||||
public:
|
||||
|
||||
const static float DEFAULT_HEIGHT;
|
||||
|
||||
struct BoundingHeights {
|
||||
@@ -60,28 +59,51 @@ namespace globebrowsing {
|
||||
WANT_SPLIT,
|
||||
};
|
||||
|
||||
Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex, bool initVisible = true);
|
||||
Chunk(
|
||||
const RenderableGlobe& owner,
|
||||
const TileIndex& tileIndex,
|
||||
bool initVisible = true);
|
||||
|
||||
/// Updates chunk internally and returns a desired level
|
||||
/**
|
||||
* Updates the Chunk internally and returns the Status of the Chunk.
|
||||
*
|
||||
* Tests if the Chunk is cullable and gets the desired level of the Chunk. If the
|
||||
* Chunk is cullable it will be set to invisible and return Status::WANT_MERGE.
|
||||
* If the desired level is smaller than the current level of the chunk it will
|
||||
* return Status::WANT_MERGE, if it is larger it will return Status::WANT_SPLIT,
|
||||
* otherwise Status::DO_NOTHING.
|
||||
*
|
||||
* \returns The Status of the chunk.
|
||||
*/
|
||||
Status update(const RenderData& data);
|
||||
|
||||
/**
|
||||
* Returns a convex polyhedron of eight vertices tightly bounding the volume of
|
||||
* the Chunk.
|
||||
*/
|
||||
std::vector<glm::dvec4> getBoundingPolyhedronCorners() const;
|
||||
|
||||
const GeodeticPatch& surfacePatch() const;
|
||||
const RenderableGlobe& owner() const;
|
||||
const TileIndex tileIndex() const;
|
||||
bool isVisible() const;
|
||||
|
||||
/**
|
||||
* Returns BoundingHeights that fits the Chunk as tightly as possible.
|
||||
*
|
||||
* If the Chunk uses more than one HightLayer, the BoundingHeights will be set
|
||||
* to cover all HightLayers. If the Chunk has a higher level than its highest
|
||||
* resolution HightLayer Tile, it will base its BoundingHeights on that Tile.
|
||||
* This means that high level Chunks can have BoundingHeights that are not
|
||||
* tightly fitting.
|
||||
*/
|
||||
BoundingHeights getBoundingHeights() const;
|
||||
|
||||
void setIndex(const TileIndex& index);
|
||||
|
||||
private:
|
||||
|
||||
const RenderableGlobe& _owner;
|
||||
TileIndex _tileIndex;
|
||||
const TileIndex _tileIndex;
|
||||
bool _isVisible;
|
||||
GeodeticPatch _surfacePatch;
|
||||
|
||||
const GeodeticPatch _surfacePatch;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
|
||||
@@ -42,9 +42,12 @@ namespace {
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
int EvaluateChunkLevelByDistance::getDesiredLevel(const Chunk& chunk, const RenderData& data) const {
|
||||
// Calculations are done in the reference frame of the globe. Hence, the camera
|
||||
// position needs to be transformed with the inverse model matrix
|
||||
int EvaluateChunkLevelByDistance::getDesiredLevel(
|
||||
const Chunk& chunk,
|
||||
const RenderData& data) const {
|
||||
// Calculations are done in the reference frame of the globe
|
||||
// (model space). Hence, the camera position needs to be transformed
|
||||
// with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
const RenderableGlobe& globe = chunk.owner();
|
||||
const Ellipsoid& ellipsoid = globe.ellipsoid();
|
||||
@@ -69,21 +72,26 @@ namespace globebrowsing {
|
||||
Scalar distanceToPatch = glm::length(cameraToChunk);
|
||||
Scalar distance = distanceToPatch;
|
||||
|
||||
Scalar scaleFactor = globe.generalProperties().lodScaleFactor * ellipsoid.minimumRadius();
|
||||
Scalar scaleFactor =
|
||||
globe.generalProperties().lodScaleFactor * ellipsoid.minimumRadius();
|
||||
Scalar projectedScaleFactor = scaleFactor / distance;
|
||||
int desiredLevel = ceil(log2(projectedScaleFactor));
|
||||
return desiredLevel;
|
||||
}
|
||||
|
||||
int EvaluateChunkLevelByProjectedArea::getDesiredLevel(const Chunk& chunk, const RenderData& data) const {
|
||||
// Calculations are done in the reference frame of the globe. Hence, the camera
|
||||
// position needs to be transformed with the inverse model matrix
|
||||
int EvaluateChunkLevelByProjectedArea::getDesiredLevel(
|
||||
const Chunk& chunk,
|
||||
const RenderData& data) const {
|
||||
// Calculations are done in the reference frame of the globe
|
||||
// (model space). Hence, the camera position needs to be transformed
|
||||
// with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
|
||||
const RenderableGlobe& globe = chunk.owner();
|
||||
const Ellipsoid& ellipsoid = globe.ellipsoid();
|
||||
glm::dvec4 cameraPositionModelSpace = glm::dvec4(data.camera.positionVec3(), 1);
|
||||
Vec3 cameraPosition = glm::dvec3(inverseModelTransform * cameraPositionModelSpace);
|
||||
Vec3 cameraPosition =
|
||||
glm::dvec3(inverseModelTransform * cameraPositionModelSpace);
|
||||
Vec3 cameraToEllipsoidCenter = -cameraPosition;
|
||||
|
||||
Geodetic2 cameraGeodeticPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
|
||||
@@ -95,8 +103,8 @@ namespace globebrowsing {
|
||||
// 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);
|
||||
|
||||
const Geodetic2 closestCorner =
|
||||
chunk.surfacePatch().closestCorner(cameraGeodeticPos);
|
||||
|
||||
// Camera
|
||||
// |
|
||||
@@ -112,8 +120,6 @@ namespace globebrowsing {
|
||||
// | center |
|
||||
// | |
|
||||
// +-----------------+ <-- south east corner
|
||||
|
||||
|
||||
|
||||
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
|
||||
const Geodetic3 c = { center, heights.min };
|
||||
@@ -154,32 +160,37 @@ namespace globebrowsing {
|
||||
//
|
||||
|
||||
// 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
|
||||
// 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;
|
||||
double areaABC = 0.5 * glm::length(glm::cross(AC, AB));
|
||||
double projectedChunkAreaApprox = 8 * areaABC;
|
||||
|
||||
double scaledArea = globe.generalProperties().lodScaleFactor * projectedChunkAreaApprox;
|
||||
double scaledArea =
|
||||
globe.generalProperties().lodScaleFactor * projectedChunkAreaApprox;
|
||||
return chunk.tileIndex().level + round(scaledArea - 1);
|
||||
}
|
||||
|
||||
int EvaluateChunkLevelByAvailableTileData::getDesiredLevel(const Chunk& chunk, const RenderData& data) const {
|
||||
int EvaluateChunkLevelByAvailableTileData::getDesiredLevel(
|
||||
const Chunk& chunk,
|
||||
const RenderData& data) const {
|
||||
auto layerManager = chunk.owner().chunkedLodGlobe()->layerManager();
|
||||
auto heightLayers = layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
auto heightLayers =
|
||||
layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
int currLevel = chunk.tileIndex().level;
|
||||
|
||||
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; i++) {
|
||||
for (auto& layer : layerManager->layerGroup(i).activeLayers()) {
|
||||
Tile::Status tileStatus = layer->tileProvider()->getTileStatus(chunk.tileIndex());
|
||||
Tile::Status tileStatus =
|
||||
layer->tileProvider()->getTileStatus(chunk.tileIndex());
|
||||
if (tileStatus == Tile::Status::OK) {
|
||||
return UNKNOWN_DESIRED_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currLevel - 1;;
|
||||
return currLevel - 1;
|
||||
}
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
} // namespace openspace
|
||||
@@ -34,25 +34,44 @@
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
* Abstract class defining an interface for accessing a desired level of a Chunk.
|
||||
* The desired level can be used in the process of determining whether a Chunk should
|
||||
* want to split, merge or do nothing.
|
||||
*/
|
||||
class ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const = 0;
|
||||
static const int UNKNOWN_DESIRED_LEVEL = -1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate the Chunk level depending on the distance from the Camera to the Chunk.
|
||||
* This evaluation method aims to keep the screen size (horizontal length and not
|
||||
* area) of all chunks constant.
|
||||
*/
|
||||
class EvaluateChunkLevelByDistance : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate the chunk level using the area of the non-heightmapped Chunk projected
|
||||
* on a sphere with the center in the position of the camera. A Chunk near the
|
||||
* horizon will have a small projected area and hence a lower desired level. This
|
||||
* evaluation is more forgiving than EvaluateChunkLevelByDistance, meaning it results
|
||||
* in lower desired levels.
|
||||
*/
|
||||
class EvaluateChunkLevelByProjectedArea : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* If this chunk has available tile data for any LayerGroup on any of its active
|
||||
* Layers it will return an UNKNOWN_DESIRED_LEVEL. If no data is available it will
|
||||
* evaluate to a level that is <code>current level -1</code>.
|
||||
*/
|
||||
class EvaluateChunkLevelByAvailableTileData : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
@@ -60,6 +79,4 @@ namespace globebrowsing {
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
|
||||
#endif // __CHUNK_LEVEL_EVALUATOR_H__
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
|
||||
#include <modules/globebrowsing/chunk/culling.h>
|
||||
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "ChunkNode";
|
||||
}
|
||||
@@ -66,12 +65,7 @@ bool ChunkNode::isLeaf() const {
|
||||
return _children[0] == nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Returns true or false wether this node can be merge or not
|
||||
bool ChunkNode::updateChunkTree(const RenderData& data) {
|
||||
//Geodetic2 center = _chunk.surfacePatch.center();
|
||||
//LDEBUG("x: " << patch.x << " y: " << patch.y << " level: " << patch.level << " lat: " << center.lat << " lon: " << center.lon);
|
||||
|
||||
if (isLeaf()) {
|
||||
Chunk::Status status = _chunk.update(data);
|
||||
if (status == Chunk::Status::WANT_SPLIT) {
|
||||
@@ -127,7 +121,8 @@ void ChunkNode::breadthFirst(const std::function<void(const ChunkNode&)>& f) con
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkNode::reverseBreadthFirst(const std::function<void(const ChunkNode&)>& f) const {
|
||||
void ChunkNode::reverseBreadthFirst(
|
||||
const std::function<void(const ChunkNode&)>& f) const {
|
||||
std::stack<const ChunkNode*> S;
|
||||
std::queue<const ChunkNode*> Q;
|
||||
|
||||
@@ -175,25 +170,15 @@ const ChunkNode& ChunkNode::find(const Geodetic2& location) const {
|
||||
return *node;
|
||||
}
|
||||
|
||||
ChunkNode& ChunkNode::find(const Geodetic2& location) {
|
||||
ChunkNode* node = this;
|
||||
CHUNK_NODE_FIND(node, location);
|
||||
return *node;
|
||||
}
|
||||
|
||||
const ChunkNode& ChunkNode::getChild(Quad quad) const {
|
||||
return *_children[quad];
|
||||
}
|
||||
|
||||
ChunkNode& ChunkNode::getChild(Quad quad) {
|
||||
return *_children[quad];
|
||||
}
|
||||
|
||||
void ChunkNode::split(int depth) {
|
||||
if (depth > 0 && isLeaf()) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
Chunk chunk(_chunk.owner(), _chunk.tileIndex().child((Quad)i));
|
||||
_children[i] = std::unique_ptr<ChunkNode>(new ChunkNode(chunk, this));
|
||||
_children[i] = std::make_unique<ChunkNode>(chunk, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +200,6 @@ void ChunkNode::merge() {
|
||||
ghoul_assert(isLeaf(), "ChunkNode must be leaf after merge");
|
||||
}
|
||||
|
||||
|
||||
const Chunk& ChunkNode::getChunk() const {
|
||||
return _chunk;
|
||||
}
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
#include <modules/globebrowsing/rendering/chunkrenderer.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
|
||||
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
@@ -49,32 +47,42 @@ public:
|
||||
ChunkNode(const Chunk& chunk, ChunkNode* parent = nullptr);
|
||||
~ChunkNode();
|
||||
|
||||
|
||||
/**
|
||||
* Recursively split the ChunkNode.
|
||||
*
|
||||
* \param depth defines how deep the recursion should go. If depth == 1 (default),
|
||||
* the ChunkNode will only split once.
|
||||
*/
|
||||
void split(int depth = 1);
|
||||
|
||||
/**
|
||||
* Deletes all children of the ChunkNode recursively.
|
||||
*/
|
||||
void merge();
|
||||
|
||||
bool isRoot() const;
|
||||
bool isLeaf() const;
|
||||
|
||||
void depthFirst(const std::function<void(const ChunkNode&)>& f) const;
|
||||
void breadthFirst(const std::function<void(const ChunkNode&)>& f) const;
|
||||
void reverseBreadthFirst(const std::function<void(const ChunkNode&)>& f) const;
|
||||
void depthFirst( const std::function<void(const ChunkNode&)>& f) const;
|
||||
void breadthFirst( const std::function<void(const ChunkNode&)>& f) const;
|
||||
void reverseBreadthFirst( const std::function<void(const ChunkNode&)>& f) const;
|
||||
|
||||
const ChunkNode& find(const Geodetic2& location) const;
|
||||
ChunkNode& find(const Geodetic2& location);
|
||||
|
||||
const ChunkNode& getChild(Quad quad) const;
|
||||
ChunkNode& getChild(Quad quad);
|
||||
|
||||
const Chunk& getChunk() const;
|
||||
|
||||
/**
|
||||
* Updates all children recursively. If this ChunkNode wants to split it will,
|
||||
* otherwise check if the children wants to merge. If all children wants to merge
|
||||
* and the Status of this Chunk is not Status::WANT_SPLIT it will merge.
|
||||
*
|
||||
* \returns true if the ChunkNode can merge and false if it can not merge.
|
||||
*/
|
||||
bool updateChunkTree(const RenderData& data);
|
||||
|
||||
static int chunkNodeCount;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
ChunkNode* _parent;
|
||||
std::unique_ptr<ChunkNode> _children[4];
|
||||
|
||||
@@ -84,6 +92,4 @@ private:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
|
||||
#endif // __QUADTREE_H__
|
||||
#endif // __QUADTREE_H__
|
||||
@@ -22,10 +22,6 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <modules/globebrowsing/chunk/culling.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
@@ -45,7 +41,7 @@ namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// FRUSTUM CULLER //
|
||||
// FRUSTUM CULLER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
FrustumCuller::FrustumCuller(const AABB3 viewFrustum)
|
||||
: _viewFrustum(viewFrustum){
|
||||
@@ -65,7 +61,6 @@ namespace globebrowsing {
|
||||
|
||||
const std::vector<glm::dvec4>& corners = chunk.getBoundingPolyhedronCorners();
|
||||
|
||||
|
||||
// Create a bounding box that fits the patch corners
|
||||
AABB3 bounds; // in screen space
|
||||
std::vector<vec4> clippingSpaceCorners(8);
|
||||
@@ -73,16 +68,16 @@ namespace globebrowsing {
|
||||
dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i];
|
||||
clippingSpaceCorners[i] = cornerClippingSpace;
|
||||
|
||||
dvec3 cornerScreenSpace = (1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace;
|
||||
dvec3 cornerScreenSpace =
|
||||
(1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace;
|
||||
bounds.expand(cornerScreenSpace);
|
||||
}
|
||||
|
||||
return !_viewFrustum.intersects(bounds);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// HORIZON CULLER //
|
||||
// HORIZON CULLER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
HorizonCuller::HorizonCuller() {
|
||||
|
||||
@@ -93,8 +88,6 @@ namespace globebrowsing {
|
||||
}
|
||||
|
||||
bool HorizonCuller::isCullable(const Chunk& chunk, const RenderData& data) {
|
||||
//return !isVisible(data, chunk.surfacePatch(), chunk.owner()->ellipsoid(), chunk.owner()->chunkHeight);
|
||||
|
||||
// Calculations are done in the reference frame of the globe. Hence, the camera
|
||||
// position needs to be transformed with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
@@ -147,7 +140,8 @@ namespace globebrowsing {
|
||||
Scalar minimumGlobeRadius)
|
||||
{
|
||||
Scalar distanceToHorizon =
|
||||
sqrt(pow(length(cameraPosition - globePosition), 2) - pow(minimumGlobeRadius, 2));
|
||||
sqrt(pow(length(cameraPosition - globePosition), 2) -
|
||||
pow(minimumGlobeRadius, 2));
|
||||
Scalar minimumAllowedDistanceToObjectFromHorizon = sqrt(
|
||||
pow(length(objectPosition - globePosition), 2) -
|
||||
pow(minimumGlobeRadius - objectBoundingSphereRadius, 2));
|
||||
|
||||
@@ -47,12 +47,29 @@ namespace globebrowsing {
|
||||
class ChunkCuller {
|
||||
public:
|
||||
virtual void update() { }
|
||||
|
||||
/**
|
||||
* Determine if the Chunk is cullable. That is return true if removing the
|
||||
* Chunk 'culling it' will not have any result on the final rendering. Culling
|
||||
* it will make the rendering faster.
|
||||
*/
|
||||
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Culls all chunks that are completely outside the view frustum.
|
||||
*
|
||||
* The frustum culling uses a 2D axis aligned bounding box for the Chunk in
|
||||
* screen space. This is calculated from a bounding polyhedron bounding the
|
||||
* Chunk. Hence the culling will not be 'perfect' but fast and good enough for
|
||||
* culling chunks outside the frustum with some margin.
|
||||
*/
|
||||
class FrustumCuller : public ChunkCuller {
|
||||
public:
|
||||
|
||||
/**
|
||||
* \param viewFrustum is the view space in screen space. Hence it is an axis
|
||||
* aligned bounding box and not a real frustum.
|
||||
*/
|
||||
FrustumCuller(const AABB3 viewFrustum);
|
||||
~FrustumCuller();
|
||||
|
||||
@@ -60,15 +77,14 @@ namespace globebrowsing {
|
||||
|
||||
private:
|
||||
const AABB3 _viewFrustum;
|
||||
|
||||
};
|
||||
|
||||
//In the current implementation of the horizon culling and the distance to the
|
||||
//camera, the closer the ellipsoid is to a
|
||||
//sphere, the better this will make the splitting. Using the minimum radius to
|
||||
//be safe. This means that if the ellipsoid has high difference between radii,
|
||||
//splitting might accur even though it is not needed.
|
||||
|
||||
/**
|
||||
* In this implementation of the horizon culling, the closer the ellipsoid is to a
|
||||
* sphere, the better this will make the culling. Using the minimum radius to
|
||||
* be safe. This means that if the ellipsoid has high difference between radii,
|
||||
* splitting might accur even though it may not be needed.
|
||||
*/
|
||||
class HorizonCuller : public ChunkCuller {
|
||||
public:
|
||||
HorizonCuller();
|
||||
|
||||
Reference in New Issue
Block a user