1 /***************************************************************************
2   qgs3dmapscene.h
3   --------------------------------------
4   Date                 : July 2017
5   Copyright            : (C) 2017 by Martin Dobias
6   Email                : wonder dot sk at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #ifndef QGS3DMAPSCENE_H
17 #define QGS3DMAPSCENE_H
18 
19 #include "qgis_3d.h"
20 
21 #include <Qt3DCore/QEntity>
22 
23 #include "qgsfeatureid.h"
24 #include "qgsshadowrenderingframegraph.h"
25 #include "qgsray3d.h"
26 #include "qgscameracontroller.h"
27 
28 namespace Qt3DRender
29 {
30   class QRenderSettings;
31   class QCamera;
32   class QPickEvent;
33   class QObjectPicker;
34 }
35 
36 namespace Qt3DLogic
37 {
38   class QFrameAction;
39 }
40 
41 namespace Qt3DExtras
42 {
43   class QForwardRenderer;
44   class QSkyboxEntity;
45 }
46 
47 class QgsAbstract3DEngine;
48 class QgsAbstract3DRenderer;
49 class QgsMapLayer;
50 class Qgs3DMapScenePickHandler;
51 class Qgs3DMapSettings;
52 class QgsTerrainEntity;
53 class QgsChunkedEntity;
54 class QgsSkyboxEntity;
55 class QgsSkyboxSettings;
56 class Qgs3DMapExportSettings;
57 class QgsShadowRenderingFrameGraph;
58 class QgsPostprocessingEntity;
59 class QgsChunkNode;
60 
61 #define SIP_NO_FILE
62 
63 /**
64  * \ingroup 3d
65  * \brief Entity that encapsulates our 3D scene - contains all other entities (such as terrain) as children.
66  * \note Not available in Python bindings
67  * \since QGIS 3.0
68  */
69 class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
70 {
71     Q_OBJECT
72   public:
73     //! Constructs a 3D scene based on map settings and Qt 3D renderer configuration
74     Qgs3DMapScene( const Qgs3DMapSettings &map, QgsAbstract3DEngine *engine );
75 
76     //! Returns camera controller
cameraController()77     QgsCameraController *cameraController() { return mCameraController; }
78     //! Returns terrain entity (may be temporarily NULLPTR)
terrainEntity()79     QgsTerrainEntity *terrainEntity() { return mTerrain; }
80 
81     //! Resets camera view to show the whole scene (top view)
82     void viewZoomFull();
83 
84     //! Returns number of pending jobs of the terrain entity
85     int terrainPendingJobsCount() const;
86 
87     /**
88      * Returns number of pending jobs for all chunked entities
89      * \since QGIS 3.12
90      */
91     int totalPendingJobsCount() const;
92 
93     //! Enumeration of possible states of the 3D scene
94     enum SceneState
95     {
96       Ready,     //!< The scene is fully loaded/updated
97       Updating,  //!< The scene is still being loaded/updated
98     };
99 
100     //! Returns the current state of the scene
sceneState()101     SceneState sceneState() const { return mSceneState; }
102 
103     //! Registers an object that will get results of pick events on 3D entities. Does not take ownership of the pick handler. Adds object picker components to 3D entities.
104     void registerPickHandler( Qgs3DMapScenePickHandler *pickHandler );
105     //! Unregisters previously registered pick handler. Pick handler is not deleted. Also removes object picker components from 3D entities.
106     void unregisterPickHandler( Qgs3DMapScenePickHandler *pickHandler );
107 
108     /**
109      * Given screen error (in pixels) and distance from camera (in 3D world coordinates), this function
110      * estimates the error in world space. Takes into account camera's field of view and the screen (3D view) size.
111      */
112     float worldSpaceError( float epsilon, float distance );
113 
114     //! Exports the scene according to the scene export settings
115     void exportScene( const Qgs3DMapExportSettings &exportSettings );
116 
117     /**
118      * Returns the active chunk nodes of \a layer
119      *
120      * \since QGIS 3.18
121      */
122     QVector<const QgsChunkNode *> getLayerActiveChunkNodes( QgsMapLayer *layer ) SIP_SKIP;
123 
124     /**
125      * Returns the scene extent in the map's CRS
126      *
127      * \since QGIS 3.20
128      */
129     QgsRectangle sceneExtent();
130   signals:
131     //! Emitted when the current terrain entity is replaced by a new one
132     void terrainEntityChanged();
133     //! Emitted when the number of terrain's pending jobs changes
134     void terrainPendingJobsCountChanged();
135 
136     /**
137      * Emitted when the total number of pending jobs changes
138      * \since QGIS 3.12
139      */
140     void totalPendingJobsCountChanged();
141     //! Emitted when the scene's state has changed
142     void sceneStateChanged();
143 
144     //! Emitted when the FPS count changes
145     void fpsCountChanged( float fpsCount );
146     //! Emitted when the FPS counter is activated or deactivated
147     void fpsCounterEnabledChanged( bool fpsCounterEnabled );
148 
149   public slots:
150     //! Updates the temporale entities
151     void updateTemporal();
152 
153   private slots:
154     void onCameraChanged();
155     void onFrameTriggered( float dt );
156     void createTerrain();
157     void onLayerRenderer3DChanged();
158     void onLayersChanged();
159     void createTerrainDeferred();
160     void onBackgroundColorChanged();
161     void onLayerEntityPickedObject( Qt3DRender::QPickEvent *pickEvent, QgsFeatureId fid );
162     void updateLights();
163     void updateCameraLens();
164     void onRenderersChanged();
165     void onSkyboxSettingsChanged();
166     void onShadowSettingsChanged();
167     void onEyeDomeShadingSettingsChanged();
168     void onDebugShadowMapSettingsChanged();
169     void onDebugDepthMapSettingsChanged();
170     void onCameraMovementSpeedChanged();
171 
172     bool updateCameraNearFarPlanes();
173 
174   private:
175     void addLayerEntity( QgsMapLayer *layer );
176     void removeLayerEntity( QgsMapLayer *layer );
177     void addCameraViewCenterEntity( Qt3DRender::QCamera *camera );
178     void setSceneState( SceneState state );
179     void updateSceneState();
180     void updateScene();
181     void finalizeNewEntity( Qt3DCore::QEntity *newEntity );
182     int maximumTextureSize() const;
183 
184   private:
185     const Qgs3DMapSettings &mMap;
186     QgsAbstract3DEngine *mEngine = nullptr;
187     //! Provides a way to have a synchronous function executed each frame
188     Qt3DLogic::QFrameAction *mFrameAction = nullptr;
189     QgsCameraController *mCameraController = nullptr;
190     QgsTerrainEntity *mTerrain = nullptr;
191     QList<QgsChunkedEntity *> mChunkEntities;
192     //! Entity that shows view center - useful for debugging camera issues
193     Qt3DCore::QEntity *mEntityCameraViewCenter = nullptr;
194     //! Keeps track of entities that belong to a particular layer
195     QMap<QgsMapLayer *, Qt3DCore::QEntity *> mLayerEntities;
196     QMap<const QgsAbstract3DRenderer *, Qt3DCore::QEntity *> mRenderersEntities;
197     bool mTerrainUpdateScheduled = false;
198     SceneState mSceneState = Ready;
199     //! List of currently registered pick handlers (used by identify tool)
200     QList<Qgs3DMapScenePickHandler *> mPickHandlers;
201     //! List of lights in the scene
202     QList<Qt3DCore::QEntity *> mLightEntities;
203     //! List of light origins in the scene
204     QList<Qt3DCore::QEntity *> mLightOriginEntities;
205     QList<QgsMapLayer *> mModelVectorLayers;
206     QgsSkyboxEntity *mSkybox = nullptr;
207 };
208 
209 #endif // QGS3DMAPSCENE_H
210