Skip to content
Permalink
Browse files

Heuristics for setup of near/far planes of camera

Based on terrain's active nodes, this should configure frustum depth
long enough not to clip away anything that should stay visible and
at the same time make good use of depth buffer (range not too large)
  • Loading branch information
wonder-sk committed Aug 9, 2017
1 parent 7d3cf22 commit 9ac3e9cf6b67d1be5d0fb634c7c938518494ea27
Showing with 64 additions and 0 deletions.
  1. +12 −0 src/3d/cameracontroller.cpp
  2. +3 −0 src/3d/chunks/chunkedentity.h
  3. +49 −0 src/3d/scene.cpp
@@ -135,7 +135,9 @@ void CameraController::setCameraData( float x, float y, float dist, float pitch,
cd.yaw = yaw;

if ( mCamera )
{
cd.setCamera( mCamera );
}
}


@@ -217,6 +219,13 @@ void CameraController::frameTriggered( float dt )
}
}

if ( qIsNaN( cd.x ) || qIsNaN( cd.y ) )
{
// something went horribly wrong but we need to at least try to fix it somehow
qDebug() << "camera position got NaN!";
cd.x = cd.y = 0;
}

if ( cd.pitch > 80 )
cd.pitch = 80; // prevent going under the plane
if ( cd.pitch < 0 )
@@ -234,6 +243,9 @@ void CameraController::frameTriggered( float dt )
void CameraController::resetView()
{
setCameraData( 0, 0, 1000 );
// a basic setup to make frustum depth range long enough that it does not cull everything
mCamera->setNearPlane( 1 );
mCamera->setFarPlane( 10000 );

emit cameraChanged();
}
@@ -45,6 +45,9 @@ class ChunkedEntity : public Qt3DCore::QEntity
//! update already loaded nodes (add to the queue)
void updateNodes( const QList<ChunkNode *> &nodes, ChunkQueueJobFactory *updateJobFactory );

QList<ChunkNode *> getActiveNodes() const { return activeNodes; }
ChunkNode *getRootNode() const { return rootNode; }

protected:
void cancelActiveJob();

@@ -12,6 +12,7 @@
#include "aabb.h"
#include "qgsabstract3drenderer.h"
#include "cameracontroller.h"
#include "chunknode.h"
#include "qgsvectorlayer.h"
#include "map3d.h"
#include "terrain.h"
@@ -165,6 +166,54 @@ void Scene::onCameraChanged()
if ( entity->isEnabled() )
entity->update( _sceneState( mCameraController ) );
}

// Update near and far plane from the terrain.
// this needs to be done with great care as we have kind of circular dependency here:
// active nodes are culled based on the current frustum (which involves near + far plane)
// and then based on active nodes we set near and far plane.
//
// All of this is just heuristics assuming that all other stuff is being rendered somewhere
// around the area where the terrain is.
//
// Near/far plane is setup in order to make best use of the depth buffer to avoid:
// 1. precision errors - if the range is too great
// 2. unwanted clipping of scene - if the range is too small

if ( mTerrain )
{
Qt3DRender::QCamera *camera = cameraController()->camera();
QMatrix4x4 viewMatrix = camera->viewMatrix();
float near = 1e9;
float far = 0;

QList<ChunkNode *> activeNodes = mTerrain->getActiveNodes();
Q_FOREACH ( ChunkNode *node, activeNodes )
{
// project each corner of bbox to camera coordinates
// and determine closest and farthest point.
AABB bbox = node->bbox;
for ( int i = 0; i < 8; ++i )
{
QVector4D p( ( ( i >> 0 ) & 1 ) ? bbox.xMin : bbox.xMax,
( ( i >> 1 ) & 1 ) ? bbox.yMin : bbox.yMax,
( ( i >> 2 ) & 1 ) ? bbox.zMin : bbox.zMax, 1 );
QVector4D pc = viewMatrix * p;

float dst = -pc.z(); // in camera coordinates, x grows right, y grows down, z grows to the back
if ( dst < near )
near = dst;
if ( dst > far )
far = dst;
}
}
//qDebug() << "near/far" << near << far;
if ( near < 1 )
near = 1; // does not really make sense to use negative far plane (behind camera)

// set near/far plane - with some tolerance in front/behind expected near/far planes
camera->setFarPlane( far * 2 );
camera->setNearPlane( near / 2 );
}
}

void Scene::onFrameTriggered( float dt )

0 comments on commit 9ac3e9c

Please sign in to comment.
You can’t perform that action at this time.