Created class Chunk with a corresponding rendering method

This commit is contained in:
Erik Broberg
2016-05-10 20:00:15 -04:00
parent e6d6c15874
commit 5cade91a37
9 changed files with 262 additions and 146 deletions

View File

@@ -33,6 +33,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunklodglobe.h
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunknode.h
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunkindex.h
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunk.h
${CMAKE_CURRENT_SOURCE_DIR}/meshes/trianglesoup.h
${CMAKE_CURRENT_SOURCE_DIR}/meshes/grid.h
@@ -66,6 +67,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunklodglobe.cpp
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunknode.cpp
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunkindex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/globes/chunk.cpp
${CMAKE_CURRENT_SOURCE_DIR}/meshes/trianglesoup.cpp

View File

@@ -0,0 +1,129 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <ghoul/misc/assert.h>
#include <openspace/engine/openspaceengine.h>
#include <modules/globebrowsing/globes/chunk.h>
#include <modules/globebrowsing/globes/chunklodglobe.h>
namespace {
const std::string _loggerCat = "Chunk";
}
namespace openspace {
Chunk::Chunk(ChunkLodGlobe* owner, const ChunkIndex& chunkIndex)
: _owner(owner)
, _surfacePatch(chunkIndex)
, _index(chunkIndex)
, _isVisible(true)
{
}
const GeodeticPatch& Chunk::surfacePatch() const {
return _surfacePatch;
}
ChunkLodGlobe* const Chunk::owner() const {
return _owner;
}
const ChunkIndex Chunk::index() const {
return _index;
}
bool Chunk::isVisible() const {
return _isVisible;
}
void Chunk::setIndex(const ChunkIndex& index) {
_index = index;
_surfacePatch = GeodeticPatch(index);
}
void Chunk::setOwner(ChunkLodGlobe* newOwner) {
_owner = newOwner;
}
Chunk::Status Chunk::update(const RenderData& data) {
//Uses horizon culling, frustum culling and distance to camera to determine a
//desired level.
//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.
_isVisible = true;
Vec3 globePosition = data.position.dvec3();
auto center = _surfacePatch.center();
auto ellipsoid = _owner->ellipsoid();
Vec3 patchPosition = globePosition + ellipsoid.geodetic2ToCartesian(center);
Vec3 cameraPosition = data.camera.position().dvec3();
Vec3 cameraToChunk = patchPosition - cameraPosition;
Scalar minimumGlobeRadius = ellipsoid.minimumRadius();
// Do horizon culling
const int maxHeight = 8700; // should be read from gdal dataset or mod file
if (!HorizonCuller::isVisible(data, _surfacePatch, ellipsoid, maxHeight)) {
_isVisible = false;
return WANT_MERGE;
}
// Do frustum culling
if (!FrustumCuller::isVisible(data, _surfacePatch, ellipsoid)) {
_isVisible = false;
return WANT_MERGE;
}
// Calculate desired level based on distance
Scalar distance = glm::length(cameraToChunk);
_owner->minDistToCamera = fmin(_owner->minDistToCamera, distance);
Scalar scaleFactor = 10 * minimumGlobeRadius;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = floor(log2(projectedScaleFactor));
// clamp level
desiredLevel = glm::clamp(desiredLevel, _owner->minSplitDepth, _owner->maxSplitDepth);
if (desiredLevel < _index.level) return WANT_MERGE;
else if (_index.level < desiredLevel) return WANT_SPLIT;
else return DO_NOTHING;
}
} // namespace openspace

View File

@@ -0,0 +1,79 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __CHUNK_H__
#define __CHUNK_H__
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <ostream>
#include <modules/globebrowsing/rendering/culling.h>
#include <modules/globebrowsing/globes/chunkindex.h>
#include <modules/globebrowsing/geodetics/geodetic2.h>
namespace openspace {
class ChunkLodGlobe;
class Chunk {
public:
enum Status{
DO_NOTHING,
WANT_MERGE,
WANT_SPLIT,
};
Chunk(ChunkLodGlobe* owner, const ChunkIndex& chunkIndex);
/// Updates chunk internally and returns a desired level
Status update(const RenderData& data);
const GeodeticPatch& surfacePatch() const;
ChunkLodGlobe* const owner() const;
const ChunkIndex index() const;
bool isVisible() const;
void setIndex(const ChunkIndex& index);
void setOwner(ChunkLodGlobe* newOwner);
private:
ChunkLodGlobe* _owner;
ChunkIndex _index;
bool _isVisible;
GeodeticPatch _surfacePatch;
};
}
#endif // __CHUNK_H__

View File

@@ -55,8 +55,8 @@ namespace openspace {
const Ellipsoid& ellipsoid,
std::shared_ptr<TileProviderManager> tileProviderManager)
: _ellipsoid(ellipsoid)
, _leftRoot(new ChunkNode(*this, LEFT_HEMISPHERE_INDEX))
, _rightRoot(new ChunkNode(*this, RIGHT_HEMISPHERE_INDEX))
, _leftRoot(new ChunkNode(Chunk(this, LEFT_HEMISPHERE_INDEX)))
, _rightRoot(new ChunkNode(Chunk(this, RIGHT_HEMISPHERE_INDEX)))
, minSplitDepth(2)
, maxSplitDepth(22)
{
@@ -67,7 +67,7 @@ namespace openspace {
TriangleSoup::TextureCoordinates::Yes,
TriangleSoup::Normals::No));
_patchRenderer.reset(new LatLonPatchRenderer(geometry, tileProviderManager));
_patchRenderer.reset(new ChunkRenderer(geometry, tileProviderManager));
}
ChunkLodGlobe::~ChunkLodGlobe() {
@@ -87,7 +87,7 @@ namespace openspace {
return ready;
}
LatLonPatchRenderer& ChunkLodGlobe::getPatchRenderer() {
ChunkRenderer& ChunkLodGlobe::getPatchRenderer() const{
return *_patchRenderer;
}

View File

@@ -59,7 +59,7 @@ namespace openspace {
std::shared_ptr<TileProviderManager> tileProviderManager);
~ChunkLodGlobe();
LatLonPatchRenderer& getPatchRenderer();
ChunkRenderer& getPatchRenderer() const;
bool initialize() override;
bool deinitialize() override;
@@ -85,7 +85,7 @@ namespace openspace {
std::unique_ptr<ChunkNode> _rightRoot;
// the patch used for actual rendering
std::unique_ptr<LatLonPatchRenderer> _patchRenderer;
std::unique_ptr<ChunkRenderer> _patchRenderer;
static const GeodeticPatch LEFT_HEMISPHERE;
static const GeodeticPatch RIGHT_HEMISPHERE;

View File

@@ -42,12 +42,9 @@ namespace openspace {
int ChunkNode::instanceCount = 0;
int ChunkNode::renderedPatches = 0;
ChunkNode::ChunkNode(ChunkLodGlobe& owner, const ChunkIndex& index, ChunkNode* parent)
: _owner(owner)
, _index(index)
, _patch(index)
ChunkNode::ChunkNode(const Chunk& chunk, ChunkNode* parent)
: _chunk(chunk)
, _parent(parent)
, _isVisible(true)
{
_children[0] = nullptr;
_children[1] = nullptr;
@@ -79,26 +76,19 @@ void ChunkNode::render(const RenderData& data) {
// Returns true or false wether this node can be merge or not
bool ChunkNode::internalUpdateChunkTree(const RenderData& data) {
using namespace glm;
Geodetic2 center = _patch.center();
//Geodetic2 center = _chunk.surfacePatch.center();
//LDEBUG("x: " << patch.x << " y: " << patch.y << " level: " << patch.level << " lat: " << center.lat << " lon: " << center.lon);
if (isLeaf()) {
int desiredLevel = calculateDesiredLevelAndUpdateIsVisible(data, _index);
desiredLevel = glm::clamp(desiredLevel, _owner.minSplitDepth, _owner.maxSplitDepth);
if (desiredLevel > _index.level) {
Chunk::Status status = _chunk.update(data);
if (status == Chunk::WANT_SPLIT) {
split();
}
else if(desiredLevel < _index.level){
return true; // request a merge from parent
}
return false;
return status == Chunk::WANT_MERGE;
}
else {
int requestedMergeMask = 0;
char requestedMergeMask = 0;
for (int i = 0; i < 4; ++i) {
if (_children[i]->internalUpdateChunkTree(data)) {
requestedMergeMask |= (1 << i);
@@ -119,10 +109,11 @@ bool ChunkNode::internalUpdateChunkTree(const RenderData& data) {
void ChunkNode::internalRender(const RenderData& data) {
if (isLeaf()) {
if (_isVisible) {
LatLonPatchRenderer& patchRenderer = _owner.getPatchRenderer();
patchRenderer.renderPatch(_patch, data, _owner.ellipsoid(), _index);
if (_chunk.isVisible()) {
ChunkRenderer& patchRenderer = _chunk.owner()->getPatchRenderer();
patchRenderer.renderChunk(_chunk, _chunk.owner()->ellipsoid(), data);
//patchRenderer.renderPatch(_chunk.surfacePatch, data, _chunk.owner->ellipsoid(), _chunk.index);
ChunkNode::renderedPatches++;
}
}
@@ -133,90 +124,16 @@ void ChunkNode::internalRender(const RenderData& data) {
}
}
int ChunkNode::calculateDesiredLevelAndUpdateIsVisible(
const RenderData& data,
const ChunkIndex& traverseData) {
_isVisible = true;
Vec3 globePosition = data.position.dvec3();
Vec3 patchPosition =
globePosition +
_owner.ellipsoid().geodetic2ToCartesian(_patch.center());
Vec3 cameraPosition = data.camera.position().dvec3();
//Vec3 cameraDirection = Vec3(data.camera.viewDirection());
Vec3 cameraToChunk = patchPosition - cameraPosition;
Scalar minimumGlobeRadius = _owner.ellipsoid().minimumRadius();
/*
// if camera points at same direction as latlon patch normal,
// we see the back side and dont have to split it
//Scalar cosNormalCameraDirection = glm::dot(patchNormal, cameraDirection);
Vec3 globeToCamera = cameraPosition - globePosition;
Geodetic2 cameraPositionOnGlobe =
_owner.ellipsoid().cartesianToGeodetic2(globeToCamera);
Geodetic2 closestPatchPoint = _patch.closestPoint(cameraPositionOnGlobe);
Vec3 normalOfClosestPatchPoint =
_owner.ellipsoid().geodeticSurfaceNormal(closestPatchPoint);
Scalar cosPatchNormalNormalizedGlobeToCamera =
glm::dot(normalOfClosestPatchPoint, glm::normalize(globeToCamera));
//LDEBUG(cosPatchNormalCameraDirection);
// Get the minimum radius from the ellipsoid. 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.
Scalar minimumGlobeRadius = _owner.ellipsoid().minimumRadius();
double cosAngleToHorizon = minimumGlobeRadius / glm::length(globeToCamera);
if (cosPatchNormalNormalizedGlobeToCamera < cosAngleToHorizon) {
_isVisible = false;
return traverseData.level - 1;
}
*/
if (!HorizonCuller::isVisible(
data,
_patch,
_owner.ellipsoid(),
8700))
{
_isVisible = false;
return traverseData.level - 1;
}
// Do frustrum culling
//FrustumCuller& culler = _owner.getFrustumCuller();
if (!FrustumCuller::isVisible(data, _patch, _owner.ellipsoid())) {
_isVisible = false;
return traverseData.level - 1;
}
// Calculate desired level based on distance
Scalar distance = glm::length(cameraToChunk);
_owner.minDistToCamera = fmin(_owner.minDistToCamera, distance);
Scalar scaleFactor = 10 * minimumGlobeRadius;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = floor( log2(projectedScaleFactor) );
return desiredLevel;
}
void ChunkNode::split(int depth) {
if (depth > 0 && isLeaf()) {
auto childIndices = _index.childIndices();
auto childIndices = _chunk.index().childIndices();
for (size_t i = 0; i < childIndices.size(); i++) {
_children[i] = std::unique_ptr<ChunkNode>(
new ChunkNode(_owner, childIndices[i], this));
new ChunkNode(Chunk(_chunk.owner(), childIndices[i]), this));
}
}

View File

@@ -31,6 +31,7 @@
#include <ostream>
#include <modules/globebrowsing/globes/chunkindex.h>
#include <modules/globebrowsing/globes/chunk.h>
#include <modules/globebrowsing/geodetics/geodetic2.h>
#include <modules/globebrowsing/rendering/patchrenderer.h>
@@ -46,9 +47,11 @@ namespace openspace {
class ChunkNode {
public:
ChunkNode(ChunkLodGlobe&, const ChunkIndex&, ChunkNode* parent = nullptr);
ChunkNode(const Chunk& chunk, ChunkNode* parent = nullptr);
~ChunkNode();
@@ -72,26 +75,13 @@ private:
void internalRender(const RenderData& data);
bool internalUpdateChunkTree(const RenderData& data);
/**
Uses horizon culling, frustum culling and distance to camera to determine a
desired level.
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.
*/
int calculateDesiredLevelAndUpdateIsVisible(
const RenderData& data,
const ChunkIndex& traverseData);
ChunkNode* _parent;
std::unique_ptr<ChunkNode> _children[4];
ChunkLodGlobe& _owner;
GeodeticPatch _patch;
ChunkIndex _index;
bool _isVisible;
Chunk _chunk;
};
} // namespace openspace

View File

@@ -22,8 +22,8 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/rendering/patchrenderer.h>
#include <modules/globebrowsing/rendering/patchrenderer.h>
#include <modules/globebrowsing/meshes/clipmapgrid.h>
// open space includes
@@ -85,7 +85,7 @@ namespace openspace {
//////////////////////////////////////////////////////////////////////////////////////
// LATLON PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
LatLonPatchRenderer::LatLonPatchRenderer(
ChunkRenderer::ChunkRenderer(
shared_ptr<Grid> grid,
shared_ptr<TileProviderManager> tileProviderManager)
: PatchRenderer(tileProviderManager)
@@ -101,14 +101,13 @@ namespace openspace {
_programObjectGlobalRendering->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes);
}
void LatLonPatchRenderer::renderPatch(
const GeodeticPatch& patch,
const RenderData& data,
const Ellipsoid& ellipsoid,
const ChunkIndex& chunkIndex)
void ChunkRenderer::renderChunk(const Chunk& chunk, const Ellipsoid& ellipsoid,
const RenderData& data)
{
using namespace glm;
// TODO : Model transform should be fetched as a matrix directly.
mat4 modelTransform = translate(mat4(1), data.position.vec3());
@@ -118,16 +117,16 @@ namespace openspace {
// activate shader
_programObjectGlobalRendering->activate();
// For now just pick the first one from height maps
auto heightMapProviders = _tileProviderManager->heightMapProviders();
auto tileProviderHeight = heightMapProviders.begin()->second;
// Get the textures that should be used for rendering
Tile heightTile = tileProviderHeight->getMostHiResTile(chunkIndex);
Tile heightTile = tileProviderHeight->getMostHiResTile(chunk.index());
// Bind and use the texture
ghoul::opengl::TextureUnit texUnitHeight;
texUnitHeight.activate();
@@ -135,15 +134,13 @@ namespace openspace {
_programObjectGlobalRendering->setUniform("textureSamplerHeight", texUnitHeight);
_programObjectGlobalRendering->setUniform("heightSamplingScale", heightTile.uvScale);
_programObjectGlobalRendering->setUniform("heightSamplingOffset", heightTile.uvOffset);
// Pick the first color texture
auto colorTextureProviders = _tileProviderManager->colorTextureProviders();
auto tileProviderColor = colorTextureProviders.begin()->second;
Tile colorTile = tileProviderColor->getMostHiResTile(chunkIndex);
Tile colorTile = tileProviderColor->getMostHiResTile(chunk.index());
// Bind and use the texture
@@ -155,8 +152,8 @@ namespace openspace {
_programObjectGlobalRendering->setUniform("colorSamplingOffset", colorTile.uvOffset);
Geodetic2 swCorner = patch.southWestCorner();
auto patchSize = patch.size();
Geodetic2 swCorner = chunk.surfacePatch().southWestCorner();
auto patchSize = chunk.surfacePatch().size();
_programObjectGlobalRendering->setUniform("modelViewProjectionTransform", modelViewProjectionTransform);
_programObjectGlobalRendering->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
_programObjectGlobalRendering->setUniform("lonLatScalingFactor", vec2(patchSize.toLonLatVec2()));
@@ -172,6 +169,8 @@ namespace openspace {
// disable shader
_programObjectGlobalRendering->deactivate();
}
//////////////////////////////////////////////////////////////////////////////////////
// CLIPMAP PATCH RENDERER //

View File

@@ -39,7 +39,8 @@
#include <modules/globebrowsing/other/texturetileset.h>
#include <modules/globebrowsing/other/patchcoverageprovider.h>
#include <modules/globebrowsing/other/tileprovidermanager.h>
#include <modules/globebrowsing/globes/chunkindex.h>
#include <modules/globebrowsing/globes/chunknode.h>
namespace ghoul {
@@ -77,23 +78,22 @@ namespace openspace {
// PATCH RENDERER SUBCLASSES //
//////////////////////////////////////////////////////////////////////////////////////
class LatLonPatchRenderer : public PatchRenderer {
class ChunkRenderer : public PatchRenderer {
public:
LatLonPatchRenderer(
shared_ptr<Grid> grid,
shared_ptr<TileProviderManager> tileProviderManager);
ChunkRenderer(shared_ptr<Grid> grid,
shared_ptr<TileProviderManager> tileProviderManager);
void ChunkRenderer::renderChunk(const Chunk& chunk, const Ellipsoid& ellipsoid, const RenderData& data);
void renderPatch(
const GeodeticPatch& patch,
const RenderData& data,
const Ellipsoid& ellipsoid,
const ChunkIndex& chunkIndex);
private:
shared_ptr<Grid> _grid;
};
class ClipMapPatchRenderer : public PatchRenderer {
public:
ClipMapPatchRenderer(