Improving qgis 3d

Introduction
QGIS 3D was introduced in QGIS 3.0 in 2018 and has been improved over the last 2 years. This is a continuation of last year’s summer of code project which was done by Ismail Sunni. I have a list of features I would like to implement that may be useful for QGIS users. You can find my original proposal here: QGIS 3D proposal

Displaying textured 3D models on the map:
Displaying 3D models in the 3D view is already implemented but textured models are not. So it would be a good idea to extend the existing implementation to work on textured 3D objects and maybe not only display the diffuse textures but also handle the object material as well (specular, ambient, shininess...). This feature will be implemented for the mesh layers and vector layers :
 * For mesh layers: We add the texturing to 3D models rendering, these textures will be supplied by the model.
 * For vector layers: The idea is to let users define textures for 3D geometries that represent buildings like specifying walls and roof textures, this can give us the option to define default textures for them too.

Exporting 3D scenes to common 3D formats :
Currently, we can only view 3D maps inside of QGIS. My work consists of using the Asset import library to export the 3D scene to a 3D format in order to do post-processing in advanced 3D software like Blender. This feature will open the conversation of adding Asset import library as a dependency in QGIS and will be discussed during the community bonding period. If adding the Asset import library wasn’t approved I can write a .OBJ models manager to export the 3D scenes. This feature should be implemented after textured 3D models feature to export the map in a consistent manner so that the exported scene looks the same inside QGIS 3D and other 3D software and also to have the option to export the textures along with the scene.

Implementing new 3D rendering techniques :
The idea is to make new rendering techniques for the 3D view, some of the rendering techniques I would like to implement are :
 * Rendering of the scene’s 3D objects as wireframes: This may help in debugging as it should work on the terrain and every other 3D rendered subject on the scene. For the mesh layer, it is already implemented but for the vector layer, I think it is necessary to do the same thing using the same shaders.
 * Directional lights: Currently QGIS 3D only supports point lights which is a bit unrealistic if we want to simulate a light source like the sun.
 * Skybox rendering: The idea is to extend the skybox rendering that is already implemented by Martin Dobias and give the user the ability to choose the skybox. The user should also be able to choose a single color instead of a textured skybox.
 * Shadow rendering: QGIS 3D has no support for shadow rendering at the moment. I will try to make shadows work with a directional light that represents the sun which will give us the ability to cast shadows according to the time given by the user (if we define directions in 3D it can become an accurate representation for the sun position). To make the implementation easier I will suggest making the shadow rendering work with a single directional light source (the sun).

Enabling the Python scripting API to work with a 3D view :
In QGIS there is a system to automatically generate python wrappers for C++ called sipify. I will try to make it so that the user can add 3D entities using python scripting.

Student's Biography
I am Belgacem Nedjima, a fourth year computer science and engineering student from Algeria. I am mostly interested in graphics programming and game engines and passionate about software engineering.

Timeline and progress
Here I will be writing weekly reports and updates about my GSoC project.

Before selection period

 * Making the proposal and sharing it with the community for reviews and suggestions
 * Setup the development environment.
 * Submit student's test.

Community Bonding

 * Projects announcement week (from 4th May untill 7th May) accomplished tasks:
 * Get introduced to the QGIS community.
 * Get in touch with the mentors and plan weekly meetings.
 * Read some of the developer manuals.
 * Part 1 of community bonding period (5 May - 16 May):
 * Start looking into some bugs to fix related to QGIS 3D.
 * Fixed small bug (link to github commit).
 * Started looking into the rendering architecture of QGIS 3D.
 * Part 2 of community bonding period (17 May - 25 May):
 * Making a plan for the implementation of various features.
 * Digging into the code base of QGIS 3D.
 * Discuss the implementation of texturing and the changes that will be made with mentors.
 * Defining the apparent issues with my current vision of the features's implementation.
 * Expanding my knowledge on shadow rendering and finding resources that may help with the implementation.
 * Part 3 of community bonding period (26 May - 1 June):
 * Reading the tessellation code used to generate triangles of building from polygons
 * Experimented with the Qt3DExtras::QDiffuseMapMaterial and explore alternatives. Unfortunately some of the alternatives are not available in the Qt version I use (Qt5.9).
 * Tried compiling QGIS with different Qt versions.
 * Added texture coordinates to the vertex buffer of QgsTessellatedPolygonGeometry.
 * Got the basic functionality of texturing buildings using 1 texture image working for some vector layer projects.
 * Link to screenshot of the texturing support working: vector layer texturing

Coding Period

 * Week 1 (1 June - 7 June):
 * Tasks done:
 * Got the texturing support working with non planar roofs.
 * Made a pull request containing the texturing support implementation that you can see here: https://github.com/qgis/QGIS/pull/36981
 * I had some issues debugging things related to the normals of surfaces not generated properly and then found out that was just because of the point light position and there was no issues with the code. Then I decided to implement directional lights so I don't have similar issues in the future.
 * Made a pull request with the directional lights implementation that you can find here: https://github.com/qgis/QGIS/pull/37016
 * Tasks to be done:
 * Do the implementation of the separation between roofs and walls
 * Apply some of the community suggestions.
 * Discuss next features implementation and whether prioritizing some of them is better.
 * Blocking issues: None for the moment.
 * Week 2 (8 June - 16 June):
 * Tasks done:
 * Got the separation between walls and roof working as you can in this screenshot.
 * Got the textures rotation working (Very useful for roof textures to be aligned properly).
 * Finishing the implementation of directional lights (PR link : https://github.com/qgis/QGIS/pull/37016).
 * Refactoring the code in vector layer texturing PR according to suggestions (PR link : https://github.com/qgis/QGIS/pull/36981).
 * Fixing some bugs with the vector layer texturing implementation.
 * Tasks to be done:
 * Finish the implementation of vector layer texture support.
 * Document the feature implemented more and enhance the UI.
 * Get my pull requests approved.
 * Discuss next features implementation (mainly exporting scenes).
 * Blocking issues: I had some trouble organizing my time due to some school project but everything is going well I think.
 * Week 3 (14 June - 21 June):
 * Tasks done:
 * Got the directional lights implementation merged into the main QGIS repository.
 * Discussed the 3D export feature with mentors.
 * Tasks to be done:
 * Finish the other pull request and get it merged as soon as possible.
 * Start working on the 3D exporting feature and making classes for managing .obj files.
 * Blocking issues: this week I didn't have time to work on QGIS 3D because I had 3 school projects to deliver the same week all in different subjects. Fortunately I finished all my school work and will not have problems like that again.
 * Week 4 (21 June - 28 June):
 * Tasks done:
 * Fixing some bugs in the vector layer texturing PR
 * Documenting about wavefront .obj files format.
 * Started implementing the scene exporter.
 * Made a branch in my github fork where I will be implementing the scene export feature that you can see at github
 * Tasks to be done:
 * Get the scene exporting feature working for the vector layer and specially QgsTessellatedPolygonGeometry class.
 * Try to do the 3D export feature using Qt3D's QEntity and QGeometry only.
 * Figure out how to save materials (associate .mtl files).
 * Blocking issues: Currently I'm trying to figure out how to get triangle position data out of Qt3DRender::QBuffer class using the Qt3DRender::QAttribute.
 * Week 5 (28 June - 5 July):
 * Tasks done:
 * Got exporting the vector layer data working.
 * Saw how the flat terrain is generated and how the level of details system works.
 * Exported visible terrain tiles by taking the Qt3DRender::QAttribute objects directly and parsing the data.
 * Exported invisible terrain tiles by generating geometries manually.
 * Exported DEM terrain tiles (I had some troubles with non square height maps giving me wrong values but I eventually fixed the problem).
 * Discovered smooth edges parameter in the wavefront .obj standard and implemented it (I'm following this very useful spec obj-spec)
 * Gave the user the ability to choose at which level of details he wants to export.
 * Made initial UI and classes for the scene export settings.
 * Switched from the user specifying the level of details to specifying the resolution of the terrain (more predictable in terms of loading speed and vertex count).
 * Made separate class named Qgs3DExportObject that will handle the object name and various 3D data (to handle absence of texture coordinates data in a better way in the future).
 * Gave each object in the scene it's own object name in the .obj file so that users can edit the scene in a better way.
 * Documented the code and made a draft pull request that you can find here: https://github.com/qgis/QGIS/pull/37588
 * Discussed what I implemented with mentors.
 * Screenshots:
 * DEM terrain inside QGIS: https://imgur.com/aZl0E03
 * Exported DEM terrain (smoothing option to the left): https://imgur.com/Jkl9kfu
 * Exported vector layer with a flat terrain: https://imgur.com/LWBtHqf
 * Tasks to be done:
 * Export other types of layers (mesh layers, 3D symbol layers...).
 * Handle exporting of normals.
 * Handle exporting of texture coordinates.
 * Export textures as displayed in the scene to an image file.
 * Manage material file (.mtl) construction.
 * Blocking issues: Not really a blocking issue but I wanted to do export scene hierarchy in the .obj file but that didn't seem to work in blender :(.
 * Week 6 (6 July - 12 July):
 * Tasks done:
 * Exporting normals.
 * Exporting of texture coordinates.
 * Exporting of 3D terrain texture to a .jpg image.
 * Added the terrain resolution parameter.
 * Managing material file construction inside Qgs3DExportObject.
 * Handling the scale of the exported model.
 * Cleanup the code according to reviews.
 * Switched from synchronous loading to using waitForFinished functions to started loading entities in a background thread and waiting for them to finish according to mentor suggestion.
 * Saving the export dialog window settings and reloading.
 * Exported Phong material settings of polygons and buffered lines to the mtl file
 * Screenshots:
 * A textured DEM terrain exported to mesh lab: MeshLab screenshot (how it looks in blender: Blender screenshot).
 * The .obj model for previous screenshots: terrain .obj model
 * Vector layer on a flat terrain: MeshLab screenshot
 * The .obj model for previous screenshots: vector layer .obj model
 * Tasks to be done:
 * Export other vector layer shapes.
 * Handle materials for other vector layer shapes.
 * Export different material for each object based on its 3D symbol for rule based vector layer.
 * Blocking issues: None
 * Week 7 (7 July - 19 July):
 * Tasks done:
 * Export rule based renderer entities with different materials for each rule.
 * Code refactoring.
 * Export mesh layer position data to .obj file (with no material).
 * Export line geometries.
 * Export billboard entities as point objects.
 * Screenshots:
 * A model of buildings with different materials generated with rule based renderer: mesh lab screenshot
 * Tasks to be done:
 * Export vector layer textured materials.
 * Review the implementation and merge it if possible.
 * Start working on next features.
 * Blocking issues: Not really a blocking issue but I noticed that lines and points are not displayed correctly in a uniform way by different 3D software, for example MeshLab doesn't show lines or points if faces exist within the 3D model.
 * Week 8 (20 July - 26 July):
 * Tasks done:
 * Export vector layer textured materials.
 * Added layer name as a prefix of the .obj file object names.
 * Fixed merge conflict and adjusted the code to use QgsAbstractMaterialSettings instead of a class specific to phong material.
 * Created a branch for the skybox rendering.
 * Started working on skybox rendering.
 * Tasks to be done:
 * Finish the skybox rendering feature.
 * Start working on wire frames rendering.
 * Week 9 (27 July - 2 August):
 * Tasks done:
 * The scene export feature is merged with the master branch and contributors can check the scene export export feature.
 * Read the code Qt3DExtras::QSkyboxEntity from the Qt3D source files and found a bug that prevented textures from loading correctly.
 * Implement QqgSkyboxEntity class based on Qt3DExtras::QSkyboxEntity implementation.
 * Implement rendering of skyboxes using either a collection of textures in the same directory or 6 images for each cube face.
 * Implement rendering of skyboxes using a single 360 image (I tested .hdr images from https://hdrihaven.com/ and it worked well).
 * Make QgsSkyboxSettings class and necessary UI for the skybox configuration.
 * Added documentations and some refactoring.
 * Made a pull request you can check at github.
 * Screenshots:
 * skybox1
 * skybox2
 * Tasks to be done:
 * Fix github checks and address reviews.
 * Work on wire frames rendering.
 * Week 10:
 * Tasks done:
 * Fix skybox rendering pull request github checks.
 * Address skybox pull request reviews.
 * skybox feature was merged into the master QGIS branch.
 * Experiment with how the wireframe rendering can be done.
 * Found that we were able to display buildings wireframes by disabling facades rendering and it was already implemented for mesh terrains.
 * Discussed wireframe rendering with mentors and we concluded that global wireframes rendering will take much more work than it deserves for now so I needed to work on next remaining features.
 * Discussed shadow rendering with mentors and we decided to use shadow mapping technique.
 * Started converting Qt3D shadow mapping tutorial code from QML to pure C++.
 * Tasks to be done:
 * Finish converting the Qt3D shadow mapping tutorial code to pure C++.
 * Make separate classes for the frame graph used by the 3D view.
 * Try to complete the shadow rendering feature.
 * Week 11:
 * Tasks done:
 * Finished converting Qt3D shadow mapping tutorial code to pure C++ (github repository).
 * Implemented the custom frame graph for a post processing effect with a shader (which will eventually be for shadows).
 * Test post processing pass with some kernels from wikipedia (kernels wikipedia page).
 * Screenshots:
 * Shadow rendering using Qt3D C++ only
 * edge detection kernel running as post processing render pass in QGIS
 * Tasks to be done:
 * Finish the shadow rendering in QGIS 3D view.
 * Experiment with some techniques to reduce peter panning issue.
 * Make a pull request to the QGIS repository.
 * Blocking issues: None
 * Week 12:
 * Tasks done:
 * Made the shadow rendering implementation inside QGIS.
 * Improved the resolution of shadows by moving the light camera to fit into the main camera view frustum.
 * Applied a technique called percentage closer filtering to make the shadows look softer.
 * Added maximum shadow rendering distance to handle the case when the view frustum area is big (when looking into the sky).
 * Made a draft PR for the shadow rendering that you can check at github
 * Screenshots:
 * shadows1
 * shadows2
 * shadows 3
 * shadows 3 zooming in
 * Blocking issues: I had some visual artifacts in some situation like self shadowing and peter panning that I found a solution for them by getting the normal for the pixel at each position which wasn't an option because I was doing the shadow rendering as a post processing effect (had access to only the depth and color buffers which isn't the case for something like if we were using G-buffers or if we had our own materials and shaders in QGIS and modified them).

Final report
My final Google summer of code project that I posted on the GSoC website can be found here

Mentors
Martin Dobias

Peter Petrik