QgsChunkedEntity::SceneState _sceneState( QgsCameraController *cameraController ) { Qt3DRender::QCamera *camera = cameraController->camera(); QgsChunkedEntity::SceneState state; state.cameraFov = camera->fieldOfView(); state.cameraPos = camera->position(); QRect rect = cameraController->viewport(); state.screenSizePx = std::max( rect.width(), rect.height() ); // TODO: is this correct? state.viewProjectionMatrix = camera->projectionMatrix() * camera->viewMatrix(); return state; }
bool Qgs3DMapScene::updateCameraNearFarPlanes() { // 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 fnear = 1e9; float ffar = 0; QList<QgsChunkNode *> activeNodes = mTerrain->activeNodes(); // it could be that there are no active nodes - they could be all culled or because root node // is not yet loaded - we still need at least something to understand bounds of our scene // so lets use the root node if ( activeNodes.isEmpty() ) activeNodes << mTerrain->rootNode(); Q_FOREACH ( QgsChunkNode *node, activeNodes ) { // project each corner of bbox to camera coordinates // and determine closest and farthest point. QgsAABB 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 < fnear ) fnear = dst; if ( dst > ffar ) ffar = dst; } } if ( fnear < 1 ) fnear = 1; // does not really make sense to use negative far plane (behind camera) if ( fnear == 1e9 && ffar == 0 ) { // the update didn't work out... this should not happen // well at least temprarily use some conservative starting values qDebug() << "oops... this should not happen! couldn't determine near/far plane. defaulting to 1...1e9"; fnear = 1; ffar = 1e9; } // set near/far plane - with some tolerance in front/behind expected near/far planes float newFar = ffar * 2; float newNear = fnear / 2; if ( !qgsFloatNear( newFar, camera->farPlane() ) || !qgsFloatNear( newNear, camera->nearPlane() ) ) { camera->setFarPlane( newFar ); camera->setNearPlane( newNear ); return true; } }
void checkSyncFrustumCullingExecution() { // GIVEN Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); Qt3DRender::QFrustumCulling *frustumCulling = new Qt3DRender::QFrustumCulling(clearBuffer); Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(frustumCulling); Qt3DRender::QCamera *camera = new Qt3DRender::QCamera(); cameraSelector->setCamera(camera); Qt3DRender::TestAspect testAspect(buildSimpleScene(viewport)); // THEN Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(cameraSelector->id()); QVERIFY(leafNode != nullptr); // WHEN Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); renderViewBuilder.prepareJobs(); renderViewBuilder.buildJobHierachy(); // THEN QCOMPARE(renderViewBuilder.frustumCullingJob()->viewProjection(), QMatrix4x4()); // WHEN renderViewBuilder.renderViewJob()->run(); renderViewBuilder.syncFrustumCullingJob()->run(); // THEN QCOMPARE(renderViewBuilder.frustumCullingJob()->viewProjection(), camera->projectionMatrix() * camera->viewMatrix()); }