int main(int ac, char **av) { QApplication app(ac, av); Qt3DExtras::Qt3DWindow view; view.defaultFrameGraph()->setClearColor(Qt::black); // Root entity Qt3DCore::QEntity *sceneRoot = new Qt3DCore::QEntity(); // Scene Camera Qt3DRender::QCamera *camera = view.camera(); camera->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection); camera->setViewCenter(QVector3D(0.0f, 3.5f, 0.0f)); camera->setPosition(QVector3D(0.0f, 3.5f, 25.0f)); camera->setNearPlane(0.001f); camera->setFarPlane(10000.0f); // For camera controls Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(sceneRoot); camController->setCamera(camera); // Scene loader Qt3DCore::QEntity *sceneLoaderEntity = new Qt3DCore::QEntity(sceneRoot); Qt3DRender::QSceneLoader *sceneLoader = new Qt3DRender::QSceneLoader(sceneLoaderEntity); SceneWalker sceneWalker(sceneLoader); QObject::connect(sceneLoader, &Qt3DRender::QSceneLoader::statusChanged, &sceneWalker, &SceneWalker::onStatusChanged); sceneLoaderEntity->addComponent(sceneLoader); QStringList args = QCoreApplication::arguments(); QUrl sourceFileName; if (args.count() <= 1) { QWidget *container = new QWidget(); QFileDialog dialog; dialog.setFileMode(QFileDialog::AnyFile); sourceFileName = dialog.getOpenFileUrl(container, QStringLiteral("Open a scene file")); } else { sourceFileName = QUrl::fromLocalFile(args[1]); } if (sourceFileName.isEmpty()) return 0; sceneLoader->setSource(sourceFileName); view.setRootEntity(sceneRoot); view.show(); return app.exec(); }
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()); }
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; }
float Qgs3DMapScene::worldSpaceError( float epsilon, float distance ) { Qt3DRender::QCamera *camera = mCameraController->camera(); float fov = camera->fieldOfView(); QRect rect = mCameraController->viewport(); float screenSizePx = std::max( rect.width(), rect.height() ); // TODO: is this correct? // in qgschunkedentity_p.cpp there is inverse calculation (world space error to screen space error) // with explanation of the math. float frustumWidthAtDistance = 2 * distance * tan( fov / 2 ); float err = frustumWidthAtDistance * epsilon / screenSizePx; return err; }
int main(int argc, char* argv[]) { QGuiApplication app(argc, argv); Qt3DExtras::Qt3DWindow view; ExampleScene *sceneRoot = new ExampleScene(); // Scene Camera Qt3DRender::QCamera *basicCamera = view.camera(); basicCamera->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection); basicCamera->setAspectRatio(view.width() / view.height()); basicCamera->setUpVector(QVector3D(0.0f, 1.0f, 0.0f)); basicCamera->setViewCenter(QVector3D(0.0f, 3.5f, 0.0f)); basicCamera->setPosition(QVector3D(0.0f, 3.5f, 25.0f)); // For camera controls Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(sceneRoot); camController->setCamera(basicCamera); view.setRootEntity(sceneRoot); view.show(); return app.exec(); }
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; } }