Solve merge conflict.

This commit is contained in:
Kalle Bladin
2016-04-15 17:22:59 -04:00
12 changed files with 242 additions and 105 deletions
@@ -65,86 +65,100 @@ bool ChunkNode::isLeaf() const {
}
void ChunkNode::render(const RenderData& data) {
void ChunkNode::render(const RenderData& data, ChunkIndex traverseData) {
ghoul_assert(isRoot(), "this method should only be invoked on root");
//LDEBUG("-------------");
internalUpdateChunkTree(data, 0);
internalRender(data, 0);
internalUpdateChunkTree(data, traverseData);
internalRender(data, traverseData);
}
// Returns true or false wether this node can be merge or not
bool ChunkNode::internalUpdateChunkTree(const RenderData& data, int depth) {
bool ChunkNode::internalUpdateChunkTree(const RenderData& data, ChunkIndex& traverseData) {
using namespace glm;
LatLon center = _patch.center;
LatLon center = _patch.center();
//LDEBUG("x: " << patch.x << " y: " << patch.y << " level: " << patch.level << " lat: " << center.lat << " lon: " << center.lon);
if (isLeaf()) {
int desiredDepth = desiredSplitDepth(data);
if (desiredDepth > depth) {
int desiredLevel = calculateDesiredLevel(data, traverseData);
if (desiredLevel > traverseData.level) {
split();
}
else if(desiredDepth < depth){
else if(desiredLevel < traverseData.level){
return true; // request a merge from parent
}
return false;
}
else {
int requestedMergeMask = 0;
std::vector<ChunkIndex> childIndices = traverseData.childIndices();
for (int i = 0; i < 4; ++i) {
if (_children[i]->internalUpdateChunkTree(data, depth + 1)) {
if (_children[i]->internalUpdateChunkTree(data, childIndices[i])) {
requestedMergeMask |= (1 << i);
}
}
// check if all children requested merge
if (requestedMergeMask == 0xf) {
merge();
// re-run this method on this, now that this is a leaf node
return internalUpdateChunkTree(data, depth);
return internalUpdateChunkTree(data, traverseData);
}
return false;
}
}
void ChunkNode::internalRender(const RenderData& data, int currLevel) {
void ChunkNode::internalRender(const RenderData& data, ChunkIndex& traverseData) {
if (isLeaf()) {
PatchRenderer& patchRenderer = _owner.getPatchRenderer();
patchRenderer.renderPatch(_patch, data, _owner.globeRadius);
}
else {
std::vector<ChunkIndex> childIndices = traverseData.childIndices();
for (int i = 0; i < 4; ++i) {
_children[i]->internalRender(data, currLevel+1);
_children[i]->internalRender(data, childIndices[i]);
}
}
}
int ChunkNode::desiredSplitDepth(const RenderData& data) {
Vec3 normal = _patch.center.asUnitCartesian();
Vec3 pos = data.position.dvec3() + _owner.globeRadius * normal;
int ChunkNode::calculateDesiredLevel(const RenderData& data, const ChunkIndex& traverseData) {
// Temporay ugly fix for Camera::position() is broken.
Vec3 buggedCameraPos = data.camera.position().dvec3();
Vec3 patchNormal = _patch.center().asUnitCartesian();
Vec3 patchPosition = data.position.dvec3() + _owner.globeRadius * patchNormal;
Vec3 cameraPosition = data.camera.position().dvec3();
Vec3 cameraDirection = Vec3(data.camera.viewDirection());
Vec3 cameraPos = buggedCameraPos;// -_owner.globeRadius * cameraDirection;
Vec3 cameraToChunk = pos - cameraPos;
Vec3 cameraToChunk = patchPosition - cameraPosition;
// 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(normal, cameraDirection);
Scalar cosNormalCameraDirection = glm::dot(patchNormal, cameraDirection);
if (cosNormalCameraDirection > 0.3) {
return _owner.minSplitDepth;
return traverseData.level - 1;
}
// Do frustrum culling
FrustrumCuller& culler = _owner.getFrustrumCuller();
if (!culler.isVisible(data, _patch, _owner.globeRadius)) {
return traverseData.level - 1;
}
// Calculate desired level based on distance
Scalar distance = glm::length(cameraToChunk);
_owner.minDistToCamera = fmin(_owner.minDistToCamera, distance);
Scalar scaleFactor = 40 * _owner.globeRadius;// *150 * _patch.unitArea();
Scalar scaleFactor = 100 * _owner.globeRadius;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredDepth = floor( log2(projectedScaleFactor) );
return glm::clamp(desiredDepth, _owner.minSplitDepth, _owner.maxSplitDepth);
@@ -156,8 +170,8 @@ void ChunkNode::split(int depth) {
if (depth > 0 && isLeaf()) {
// Defining short handles for center, halfSize and quarterSize
const LatLon& c = _patch.center;
const LatLon& hs = _patch.halfSize;
const LatLon& c = _patch.center();
const LatLon& hs = _patch.halfSize();
LatLon qs = LatLon(0.5 * hs.lat, 0.5 * hs.lon);
// Subdivide bounds
@@ -189,7 +203,7 @@ void ChunkNode::merge() {
}
}
const ChunkNode& ChunkNode::getChild(Quad quad) const {
const ChunkNode& ChunkNode::getChild(Quad quad) const {
return *_children[quad];
}
@@ -51,6 +51,20 @@ enum Quad {
};
struct ChunkIndex {
int x, y, level;
std::vector<ChunkIndex> childIndices() const {
return {
{ 2 * x + 0, 2 * y + 0, level + 1 },
{ 2 * x + 1, 2 * y + 0, level + 1 },
{ 2 * x + 0, 2 * y + 1, level + 1 },
{ 2 * x + 1, 2 * y + 1, level + 1 },
};
}
};
class ChunkNode {
@@ -67,15 +81,15 @@ public:
const ChunkNode& getChild(Quad quad) const;
void render(const RenderData& data);
void render(const RenderData& data, ChunkIndex);
static int instanceCount;
private:
void internalRender(const RenderData& data, int currLevel);
bool internalUpdateChunkTree(const RenderData& data, int currLevel);
int desiredSplitDepth(const RenderData& data);
void internalRender(const RenderData& data, ChunkIndex&);
bool internalUpdateChunkTree(const RenderData& data, ChunkIndex&);
int calculateDesiredLevel(const RenderData& data, const ChunkIndex&);
ChunkNode* _parent;
+37 -14
View File
@@ -60,7 +60,7 @@ namespace openspace {
}
Vec3 LatLon::asUnitCartesian() {
Vec3 LatLon::asUnitCartesian() const{
return Vec3(
glm::cos(lat) * glm::cos(lon),
glm::cos(lat) * glm::sin(lon),
@@ -80,47 +80,70 @@ namespace openspace {
//////////////////////////////////////////////////////////////////////////////////////////
LatLonPatch::LatLonPatch(Scalar centerLat, Scalar centerLon, Scalar halfSizeLat, Scalar halfSizeLon)
: center(LatLon(centerLat, centerLon))
, halfSize(LatLon(halfSizeLat, halfSizeLon))
: _center(LatLon(centerLat, centerLon))
, _halfSize(LatLon(halfSizeLat, halfSizeLon))
{
}
LatLonPatch::LatLonPatch(const LatLon& center, const LatLon& halfSize)
: center(center)
, halfSize(halfSize)
: _center(center)
, _halfSize(halfSize)
{
}
LatLonPatch::LatLonPatch(const LatLonPatch& patch)
: center(patch.center)
, halfSize(patch.halfSize)
: _center(patch._center)
, _halfSize(patch._halfSize)
{
}
void LatLonPatch::setCenter(const LatLon& center) {
_center = center;
}
void LatLonPatch::setHalfSize(const LatLon& halfSize) {
_halfSize = halfSize;
}
Scalar LatLonPatch::minimalBoundingRadius() const {
const LatLon& cornerNearEquator = _center.lat > 0 ? southWestCorner() : northWestCorner();
return glm::length(_center.asUnitCartesian() - cornerNearEquator.asUnitCartesian());
}
Scalar LatLonPatch::unitArea() const {
Scalar deltaTheta = 2 * halfSize.lon;
Scalar phiMin = center.lat - halfSize.lat;
Scalar phiMax = center.lat + halfSize.lat;
Scalar deltaTheta = 2 * _halfSize.lon;
Scalar phiMin = _center.lat - _halfSize.lat;
Scalar phiMax = _center.lat + _halfSize.lat;
return deltaTheta * (sin(phiMax) - sin(phiMin));
}
const LatLon& LatLonPatch::center() const {
return _center;
}
const LatLon& LatLonPatch::halfSize() const {
return _halfSize;
}
LatLon LatLonPatch::northWestCorner() const{
return LatLon(center.lat + halfSize.lat, center.lon - halfSize.lon);
return LatLon(_center.lat + _halfSize.lat, _center.lon - _halfSize.lon);
}
LatLon LatLonPatch::northEastCorner() const{
return LatLon(center.lat + halfSize.lat, center.lon + halfSize.lon);
return LatLon(_center.lat + _halfSize.lat, _center.lon + _halfSize.lon);
}
LatLon LatLonPatch::southWestCorner() const{
return LatLon(center.lat - halfSize.lat, center.lon - halfSize.lon);
return LatLon(_center.lat - _halfSize.lat, _center.lon - _halfSize.lon);
}
LatLon LatLonPatch::southEastCorner() const{
return LatLon(center.lat - halfSize.lat, center.lon + halfSize.lon);
return LatLon(_center.lat - _halfSize.lat, _center.lon + _halfSize.lon);
}
} // namespace openspace
+22 -4
View File
@@ -44,7 +44,7 @@ struct LatLon {
LatLon(const LatLon& src);
static LatLon fromCartesian(const Vec3& v);
Vec3 asUnitCartesian();
Vec3 asUnitCartesian() const;
Vec2 toLonLatVec2() const;
inline bool operator==(const LatLon& other);
@@ -54,21 +54,39 @@ struct LatLon {
Scalar lon;
};
struct LatLonPatch {
class LatLonPatch {
public:
LatLonPatch(Scalar, Scalar, Scalar, Scalar);
LatLonPatch(const LatLon& center, const LatLon& halfSize);
LatLonPatch(const LatLonPatch& patch);
void setCenter(const LatLon&);
void setHalfSize(const LatLon&);
// Returns the minimal bounding radius that together with the LatLonPatch's
// center point represents a sphere in which the patch is completely contained
Scalar minimalBoundingRadius() const;
// Returns the area of the patch with unit radius
Scalar unitArea() const;
LatLon northWestCorner() const;
LatLon northEastCorner() const;
LatLon southWestCorner() const;
LatLon southEastCorner() const;
LatLon center;
LatLon halfSize;
const LatLon& center() const;
const LatLon& halfSize() const;
private:
LatLon _center;
LatLon _halfSize;
};
@@ -56,7 +56,7 @@ namespace openspace {
: _leftRoot(new ChunkNode(*this, LEFT_HEMISPHERE))
, _rightRoot(new ChunkNode(*this, RIGHT_HEMISPHERE))
, globeRadius(1e7)
, minSplitDepth(1)
, minSplitDepth(2)
, maxSplitDepth(22)
, _rotation("rotation", "Rotation", 0, 0, 360)
{
@@ -73,6 +73,8 @@ namespace openspace {
// Mainly for debugging purposes @AA
addProperty(_rotation);
globeRadius = dictionary.value<double>("Radius");
// ---------
@@ -85,8 +87,7 @@ namespace openspace {
_patchRenderer.reset(new LatLonPatchRenderer(geometry));
std::shared_ptr<FrustrumCuller> fc(new FrustrumCuller(1.3f));
_patchRenderer->setFrustrumCuller(fc);
_frustrumCuller = std::shared_ptr<FrustrumCuller>(new FrustrumCuller());
}
@@ -111,10 +112,19 @@ namespace openspace {
return *_patchRenderer;
}
FrustrumCuller& ChunkLodGlobe::getFrustrumCuller() {
return *_frustrumCuller;
}
void ChunkLodGlobe::render(const RenderData& data){
minDistToCamera = INFINITY;
_leftRoot->render(data);
_rightRoot->render(data);
ChunkIndex leftRootTileIndex = { 0, 0, 1 };
_leftRoot->render(data, leftRootTileIndex);
ChunkIndex rightRootTileIndex = { 1, 0, 1 };
_rightRoot->render(data, rightRootTileIndex);
//LDEBUG("min distnace to camera: " << minDistToCamera);
@@ -57,6 +57,7 @@ namespace openspace {
~ChunkLodGlobe();
PatchRenderer& getPatchRenderer();
FrustrumCuller& getFrustrumCuller();
bool initialize() override;
bool deinitialize() override;
@@ -67,7 +68,7 @@ namespace openspace {
double minDistToCamera;
const Scalar globeRadius;
Scalar globeRadius;
const int minSplitDepth;
const int maxSplitDepth;
@@ -81,6 +82,9 @@ namespace openspace {
// Covers all positive longitudes
std::unique_ptr<ChunkNode> _rightRoot;
// Frustrum culler
std::shared_ptr<FrustrumCuller> _frustrumCuller;
// the patch used for actual rendering
std::unique_ptr<PatchRenderer> _patchRenderer;
@@ -104,7 +104,7 @@ namespace openspace {
// Set patches to follow camera
for (size_t i = 0; i < _patches.size(); i++)
{
_patches[i].center = LatLon::fromCartesian(data.camera.position().dvec3());
_patches[i].setCenter(LatLon::fromCartesian(data.camera.position().dvec3()));
}
// render patches
for (size_t i = 0; i < _patches.size(); i++)
@@ -1,4 +1,4 @@
/*****************************************************************************************
/*****************************************************************************************
* *
* OpenSpace *
* *
@@ -34,8 +34,7 @@ namespace openspace {
//////////////////////////////////////////////////////////////////////////////////////
// PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
FrustrumCuller::FrustrumCuller(float tolerance)
: _tolerance(tolerance)
FrustrumCuller::FrustrumCuller()
{
}
@@ -45,23 +44,66 @@ namespace openspace {
}
bool FrustrumCuller::isVisible(const vec3& point, const mat4x4& modelViewProjection) {
vec4 pointModelSpace(point, 1.0f);
vec4 pointProjectionSpace = modelViewProjection * pointModelSpace;
vec2 pointScreenSpace = (1.0f / pointProjectionSpace.w) * pointProjectionSpace.xy;
bool FrustrumCuller::isVisible(const RenderData& data, const vec3& point, const glm::vec2& marginScreenSpace) {
// just for readability
mat4 modelTransform = translate(mat4(1), data.position.vec3());
mat4 viewTransform = data.camera.combinedViewMatrix();
mat4 modelViewProjectionTransform = data.camera.projectionMatrix()
* viewTransform * modelTransform;
vec2 pointScreenSpace = transformToScreenSpace(point, modelViewProjectionTransform);
return testPoint(pointScreenSpace, marginScreenSpace);
}
bool FrustrumCuller::isVisible(const RenderData& data, const LatLonPatch& patch, double radius) {
// An axis aligned bounding box based on the patch's minimum boudning sphere is
// used for testnig
// Calculate the MVP matrix
mat4 modelTransform = translate(mat4(1), data.position.vec3());
mat4 viewTransform = data.camera.combinedViewMatrix();
mat4 modelViewProjectionTransform = data.camera.projectionMatrix()
* viewTransform * modelTransform;
// Calculate the patch's center point in screen space
vec4 patchCenterModelSpace = vec4(radius * patch.center().asUnitCartesian(), 1);
vec4 patchCenterProjectionSpace = modelViewProjectionTransform * patchCenterModelSpace;
vec2 pointScreenSpace = (1.0f / patchCenterProjectionSpace.w) * patchCenterProjectionSpace.xy;
// Calculate the screen space margin that represents an axis aligned bounding
// box based on the patch's minimum boudning sphere
double boundingRadius = radius * patch.minimalBoundingRadius();
vec4 marginProjectionSpace = vec4(vec3(boundingRadius), 0) * data.camera.projectionMatrix();
vec2 marginScreenSpace = (1.0f / patchCenterProjectionSpace.w) * marginProjectionSpace.xy;
// Test the bounding box by testing the center point and the corresponding margin
return testPoint(pointScreenSpace, marginScreenSpace);
}
bool FrustrumCuller::testPoint(const glm::vec2& pointScreenSpace,
const glm::vec2& marginScreenSpace) const
{
const vec2& p = pointScreenSpace;
return ((-_tolerance < p.x && p.x < _tolerance) &
(-_tolerance < p.y && p.y < _tolerance));
vec2 cullBounds = vec2(1) + marginScreenSpace;
return ((-cullBounds.x < p.x && p.x < cullBounds.x) &&
(-cullBounds.y < p.y && p.y < cullBounds.y));
}
bool FrustrumCuller::isVisible(const LatLonPatch& patch, double radius, const mat4x4& modelViewProjection) {
return isVisible(radius * patch.northWestCorner().asUnitCartesian(), modelViewProjection)
|| isVisible(radius * patch.northEastCorner().asUnitCartesian(), modelViewProjection)
|| isVisible(radius * patch.southWestCorner().asUnitCartesian(), modelViewProjection)
|| isVisible(radius * patch.southEastCorner().asUnitCartesian(), modelViewProjection);
glm::vec2 FrustrumCuller::transformToScreenSpace(const vec3& point,
const mat4x4& modelViewProjection) const
{
vec4 pointProjectionSpace = modelViewProjection * vec4(point, 1.0f);
vec2 pointScreenSpace = (1.0f / pointProjectionSpace.w) * pointProjectionSpace.xy;
return pointScreenSpace;
}
} // namespace openspace
@@ -45,15 +45,39 @@ namespace openspace {
class FrustrumCuller {
public:
FrustrumCuller(float tolerance = 1.0f);
FrustrumCuller();
~FrustrumCuller();
bool isVisible(const vec3& point, const mat4x4& modelViewProjection);
bool isVisible(const LatLonPatch& patch, double radius, const mat4x4& modelViewProjection);
/// Returns true if the point is inside the view frustrum defined in RenderData.
/// The third argument marginScreenSpace is added to the default screen space
/// boundaries. E.g. for marginScreenSpace = {0.2, 0.2}, all points with
/// 1.2 < x,y < 1.2 would cause isVisible to return true.
bool isVisible(
const RenderData& data,
const vec3& point,
const vec2& marginScreenSpace = vec2(0));
/// Returns false if the patch element is guaranteed to be outside the view
/// frustrum, and true is the patch element MAY be inside the view frustrum.
bool isVisible(
const RenderData& data,
const LatLonPatch& patch,
double radius);
protected:
float _tolerance;
private:
/// Returns true if the point in screen space is inside the view frustrum.
/// The optional screen space margin vector is used to resize area defining
/// what is considered to be inside the view frustrum.
bool testPoint(
const glm::vec2& pointScreenSpace,
const glm::vec2& marginScreenSpace) const;
glm::vec2 transformToScreenSpace(const vec3& point, const mat4x4& modelViewProjection) const;
};
@@ -69,9 +69,7 @@ namespace openspace {
}
}
void PatchRenderer::setFrustrumCuller(std::shared_ptr<FrustrumCuller> fc) {
_frustrumCuller = fc;
}
//////////////////////////////////////////////////////////////////////////////////////
// LATLON PATCH RENDERER //
@@ -105,17 +103,6 @@ namespace openspace {
mat4 modelViewProjectionTransform = data.camera.projectionMatrix()
* viewTransform * modelTransform;
// View frustrum culling
if (_frustrumCuller != nullptr) {
//LatLon center = patch.center;
//vec3 centerPoint = radius * center.asUnitCartesian();
if (!_frustrumCuller->isVisible(patch, radius, modelViewProjectionTransform)) {
// dont render the patch
return;
}
}
// Get the textures that should be used for rendering
glm::ivec3 tileIndex = tileSet.getTileIndex(patch);
LatLonPatch tilePatch = tileSet.getTilePositionAndScale(tileIndex);
@@ -130,7 +117,7 @@ namespace openspace {
LatLon swCorner = patch.southWestCorner();
_programObject->setUniform("modelViewProjectionTransform", modelViewProjectionTransform);
_programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", 2.0f * vec2(patch.halfSize.toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", 2.0f * vec2(patch.halfSize().toLonLatVec2()));
_programObject->setUniform("globeRadius", float(radius));
glEnable(GL_DEPTH_TEST);
@@ -174,18 +161,19 @@ namespace openspace {
// Snap patch position
int segmentsPerPatch = 32;
LatLon halfSize = patch.halfSize();
LatLon stepSize = LatLon(
patch.halfSize.lat * 2 / segmentsPerPatch,
patch.halfSize.lon * 2 / segmentsPerPatch);
halfSize.lat * 2 / segmentsPerPatch,
halfSize.lon * 2 / segmentsPerPatch);
ivec2 patchesToCoverGlobe = ivec2(
M_PI / (patch.halfSize.lat * 2) + 0.5,
M_PI * 2 / (patch.halfSize.lon * 2) + 0.5);
M_PI / (halfSize.lat * 2) + 0.5,
M_PI * 2 / (halfSize.lon * 2) + 0.5);
ivec2 intSnapCoord = ivec2(
patch.center.lat / (M_PI * 2) * segmentsPerPatch * patchesToCoverGlobe.y,
patch.center.lon / (M_PI) * segmentsPerPatch * patchesToCoverGlobe.x);
patch.center().lat / (M_PI * 2) * segmentsPerPatch * patchesToCoverGlobe.y,
patch.center().lon / (M_PI) * segmentsPerPatch * patchesToCoverGlobe.x);
LatLon swCorner = LatLon(
stepSize.lat * intSnapCoord.x - patch.halfSize.lat,
stepSize.lon * intSnapCoord.y - patch.halfSize.lon);
stepSize.lat * intSnapCoord.x - halfSize.lat,
stepSize.lon * intSnapCoord.y - halfSize.lon);
ivec2 contraction = ivec2(intSnapCoord.y % 2, intSnapCoord.x % 2);
@@ -207,7 +195,7 @@ namespace openspace {
_programObject->setUniform("modelViewProjectionTransform", data.camera.projectionMatrix() * viewTransform * modelTransform);
_programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", 2.0f * vec2(patch.halfSize.toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", 2.0f * vec2(halfSize.toLonLatVec2()));
_programObject->setUniform("globeRadius", float(radius));
_programObject->setUniform("contraction", contraction);
@@ -66,7 +66,6 @@ namespace openspace {
unique_ptr<ProgramObject> _programObject;
shared_ptr<Geometry> _geometry;
shared_ptr<FrustrumCuller> _frustrumCuller;
TextureTileSet tileSet;
};
@@ -58,10 +58,11 @@ namespace openspace {
glm::ivec3 TextureTileSet::getTileIndex(LatLonPatch patch)
{
int level = log2(static_cast<int>(glm::max(
_sizeLevel0.lat / patch.halfSize.lat * 2,
_sizeLevel0.lon / patch.halfSize.lon * 2)));
_sizeLevel0.lat / patch.halfSize().lat * 2,
_sizeLevel0.lon / patch.halfSize().lon * 2)));
Vec2 TileSize = _sizeLevel0.toLonLatVec2() / pow(2, level);
glm::ivec2 tileIndex = -(patch.northWestCorner().toLonLatVec2() + _offsetLevel0.toLonLatVec2()) / TileSize;
return glm::ivec3(tileIndex, level);
}