This commit is contained in:
Shaun Reed 2023-03-11 12:31:09 -05:00
parent ae5abb9939
commit 5bde82d956
7 changed files with 122 additions and 79 deletions

142
README.md
View File

@ -1,4 +1,5 @@
# Qtk
[![All Builds](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml)
[![Linting](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml)
@ -11,48 +12,62 @@ practice shader coding or graphics programming techniques. In doing this I hope
to also learn more about the Qt UI framework, and the CMake build system.
Key features that are planned:
* Runtime loading of `.obj` or similar 3D models.
* Drag-and-drop interaction for adding objects to the scene.
* Runtime reloading of modified GLSL shaders attached to objects within scenes.
* Multiple views of a scene at one time.
* Camera control modes such as panning, orbiting, or following objects.
* Save / load for scene data. The current inheritance model is temporary.
* Basic text editor for quickly modifying shaders attached to objects.
* Shader / object properties panel to modify related settings.
* Reduce size of application resources and git references.
The Qtk desktop application provides a model loader using [Assimp](https://assimp.org/) within a Qt widget application.
* Runtime loading of `.obj` or similar 3D models.
* Drag-and-drop interaction for adding objects to the scene.
* Runtime reloading of modified GLSL shaders attached to objects within scenes.
* Multiple views of a scene at one time.
* Camera control modes such as panning, orbiting, or following objects.
* Save / load for scene data. The current inheritance model is temporary.
* Basic text editor for quickly modifying shaders attached to objects.
* Shader / object properties panel to modify related settings.
* Reduce size of application resources and git references.
The Qtk desktop application provides a model loader
using [Assimp](https://assimp.org/) within a Qt widget application.
For examples of using the Qtk API, see the `example-app` project in the root of
this repository.
To get textures loading on models look into [material files](http://www.paulbourke.net/dataformats/mtl/)
To get textures loading on models look
into [material files](http://www.paulbourke.net/dataformats/mtl/)
and see some examples in the `resources/models/` directory.
### Source Builds
Qtk was developed and tested using CLion and [Qt Creator](https://github.com/qt-creator/qt-creator).
Simply open the root `CMakeLists.txt` with either of these editors and configurations will be loaded.
Qtk was developed and tested using CLion
and [Qt Creator](https://github.com/qt-creator/qt-creator).
Simply open the root `CMakeLists.txt` with either of these editors and
configurations will be loaded.
This project has been ported to **Qt 6.5.0**, which is not yet available in Ubuntu apt repositories.
To run this project, you will *need* to install [Qt6 Open Source Binaries](https://www.qt.io/download-qt-installer) for your system, **version 6.5.0** or later.
Be sure to take note of the Qt6 installation directory, as we will need it to correctly set our `CMAKE_PREFIX_PATH` in the next steps.
This project has been ported to **Qt 6.5.0**, which is not yet available in
Ubuntu apt repositories.
To run this project, you will *need* to
install [Qt6 Open Source Binaries](https://www.qt.io/download-qt-installer) for
your system, **version 6.5.0** or later.
Be sure to take note of the Qt6 installation directory, as we will need it to
correctly set our `CMAKE_PREFIX_PATH` in the next steps.
#### Qtk GUI
Once Qt6 is installed, to build and run `qtk` on Ubuntu -
```bash
sudo apt update -y && sudo apt install libassimp-dev cmake build-essential git ccache
sudo apt update -y && sudo apt install libassimp-dev cmake build-essential git ccache -y
git clone https://github.com/shaunrd0/qtk
cmake -S qtk/ -B qtk/build/ -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64
cmake --build qtk/build/ -j $(nproc --ignore=2)
./qtk/build/bin/qtk-main
```
By default, the build will not initialize Assimp as a git submodule and build from source.
We can turn this on by setting the `-DQTK_UPDATE_SUBMODULES=ON` flag when running CMake.
Building using this option will fetch and build Assimp for us, but builds will take longer as a result.
Using `-DQTK_UPDATE_SUBMODULES=ON` supports providing assimp on cross-platform builds (Windows / Mac / Linux) and may be easier to configure.
By default, the build will not initialize Assimp as a git submodule and build
from source.
We can turn this on by setting the `-DQTK_UPDATE_SUBMODULES=ON` flag when
running CMake.
Building using this option will fetch and build Assimp for us, but builds will
take longer as a result.
Using `-DQTK_UPDATE_SUBMODULES=ON` supports providing assimp on cross-platform
builds (Windows / Mac / Linux) and may be easier to configure.
```bash
cmake -S qtk/ -B qtk/build/ -DQTK_UPDATE_SUBMODULES=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64
@ -60,7 +75,8 @@ cmake --build qtk/build/ -j $(nproc --ignore=2)
./qtk/build/bin/qtk-main
```
If any errors are encountered loading plugins, we can debug plugin loading by setting the following environment variable -
If any errors are encountered loading plugins, we can debug plugin loading by
setting the following environment variable -
```bash
QT_DEBUG_PLUGINS=1 ./qtk-main
@ -69,7 +85,9 @@ QT_DEBUG_PLUGINS=1 ./qtk-main
#### Qtk Library
Qtk provides a simple library for working with QOpenGL.
We can install this library on a system path or a custom path and then set `CMAKE_PREFIX_PATH` to point to this location when building an application using libqtk.
We can install this library on a system path or a custom path and then
set `CMAKE_PREFIX_PATH` to point to this location when building an application
using libqtk.
Below is an example of installing on a system path.
@ -103,9 +121,14 @@ sudo cmake --install . --prefix=/usr/local
This project defines a collection of widget plugins for use with Qt Designer.
These plugins were used to build the interface for the Qtk desktop application.
Qt Designer will list Qtk widgets in the side panel when editing a UI file within the designer.
Qtk widgets will also render and behave correctly within the UI preview in designer.
The widgets in the Qtk collection were created by implementing the [QDesignerCustomWidgetInterface](https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html#details) and [QDesignerCustomWidgetCollectionInterface](https://doc.qt.io/qt-6/qdesignercustomwidgetcollectioninterface.html) interfaces.
Qt Designer will list Qtk widgets in the side panel when editing a UI file
within the designer.
Qtk widgets will also render and behave correctly within the UI preview in
designer.
The widgets in the Qtk collection were created by implementing
the [QDesignerCustomWidgetInterface](https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html#details)
and [QDesignerCustomWidgetCollectionInterface](https://doc.qt.io/qt-6/qdesignercustomwidgetcollectioninterface.html)
interfaces.
To build and install the Qtk plugin collection -
@ -115,15 +138,18 @@ cmake --build /path/to/qtk/build
cmake --install /path/to/qtk/build
```
To uninstall after a previous installation, we can run the following command from the root of the repository.
To uninstall after a previous installation, we can run the following command
from the root of the repository.
```bash
xargs rm < build/install_manifest.txt
```
#### Windows / MacOS
If you are building on **Windows / Mac**, consider setting the `-DASSIMP_NEW_INTERFACE` build flag.
If you are building on **Windows / Mac**, consider setting
the `-DASSIMP_NEW_INTERFACE` build flag.
```bash
cmake -S qtk/ -B qtk/build/ -DASSIMP_NEW_INTERFACE=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64;/path/to/assimp/
cmake --build qtk/build/ -j $(nproc --ignore=2)
@ -166,7 +192,9 @@ cmake --build build -j $(nproc --ignore=2)
sudo cmake --build build -j $(nproc --ignore=2) --target install
```
If the `clang-format` version is any earlier than `15.0.0`, running `clang-format` will fail because this project uses configuration options made available since `15.0.0`.
If the `clang-format` version is any earlier than `15.0.0`,
running `clang-format` will fail because this project uses configuration options
made available since `15.0.0`.
```bash
clang-format --version
@ -174,7 +202,8 @@ clang-format version 15.0.5 (git@github.com:llvm/llvm-project.git 154e88af7ec97d
```
CLion has integration for IDE code reformatting actions with `clang-format`.
If you're using CLion, the `.clang-format` configuration will be picked up by CLion automatically.
If you're using CLion, the `.clang-format` configuration will be picked up by
CLion automatically.
`clang-tidy` can be run with the following commands.
@ -214,8 +243,10 @@ changed files:
##### Packaging
Packaging for Qtk is in early development.
This section documents how to package Qtk, but only source builds have been verified on Windows / Mac / Linux.
For this reason, it is recommended to install Qtk by strictly building from source at this time.
This section documents how to package Qtk, but only source builds have been
verified on Windows / Mac / Linux.
For this reason, it is recommended to install Qtk by strictly building from
source at this time.
Below are the steps to package a Qtk release.
@ -228,6 +259,7 @@ cmake --build build --target package_source
```
Alternatively, we can use `cpack` directly -
```bash
cd /path/to/qtk && cmake -B build
# Generate all install packages
@ -242,13 +274,18 @@ cpack -C Release -G DEB
cpack -C Release -G NSIS
```
Any of the above options can be appended with `--trace-expand` to debug package generation issues.
Any of the above options can be appended with `--trace-expand` to debug package
generation issues.
The contents of all packages will depend on how the build was configured.
If we are generating packages for *only* libqtk, we set `-DQTK_INSTALL_LIB=ON` during the cmake configuration step.
To generate packages for Qtk desktop application, we should set `-DQTK_INSTALL_GUI=ON`, and optionally `-DQTK_INSTALL_LIB=ON` if we would like to bundle libqtk with the desktop application.
If we are generating packages for *only* libqtk, we set `-DQTK_INSTALL_LIB=ON`
during the cmake configuration step.
To generate packages for Qtk desktop application, we should
set `-DQTK_INSTALL_GUI=ON`, and optionally `-DQTK_INSTALL_LIB=ON` if we would
like to bundle libqtk with the desktop application.
The NSIS installer will allow component-specific path modification for all of these installation components through a GUI install application.
The NSIS installer will allow component-specific path modification for all of
these installation components through a GUI install application.
##### Resources
@ -258,19 +295,32 @@ Some useful links and resources that I have found while working on this project.
[QtPlugin Import / Export plugins](https://doc.qt.io/qt-6/qtplugin.html)
## Model Artists
"Alien Hominid" (https://skfb.ly/onStx) by Nwilly_art is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Alien Hominid" (https://skfb.ly/onStx) by Nwilly_art is licensed under Creative
Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Scythe World Of Warcraft" (https://skfb.ly/6UooG) by Warcraft-3D-Models is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Scythe World Of Warcraft" (https://skfb.ly/6UooG) by Warcraft-3D-Models is
licensed under Creative Commons
Attribution (http://creativecommons.org/licenses/by/4.0/).
"Spartan Armour MKV - Halo Reach" (https://skfb.ly/6QVvM) by McCarthy3D is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Spartan Armour MKV - Halo Reach" (https://skfb.ly/6QVvM) by McCarthy3D is
licensed under Creative Commons
Attribution (http://creativecommons.org/licenses/by/4.0/).
"Survival Guitar Backpack (Low Poly)" (https://skfb.ly/6RnCB) by Berk Gedik is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
Model by Berk Gedik, from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36
Modified (learnopengl.com) material assignment (Joey de Vries) for easier load in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to specular to match non-PBR lighting setup.
"Survival Guitar Backpack (Low Poly)" (https://skfb.ly/6RnCB) by Berk Gedik is
licensed under Creative Commons
Attribution (http://creativecommons.org/licenses/by/4.0/).
Model by Berk Gedik,
from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36
Modified (learnopengl.com) material assignment (Joey de Vries) for easier load
in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to
specular to match non-PBR lighting setup.
"Terror-bird (NHMW-Geo 2012/0007/0001)" (https://skfb.ly/onAWy) by Natural History Museum Vienna is licensed under Creative Commons Attribution-NonCommercial (http://creativecommons.org/licenses/by-nc/4.0/).
"Terror-bird (NHMW-Geo 2012/0007/0001)" (https://skfb.ly/onAWy) by Natural
History Museum Vienna is licensed under Creative Commons
Attribution-NonCommercial (http://creativecommons.org/licenses/by-nc/4.0/).
"Golden Lion Sitting OBJ Low Poly FREE" (https://skfb.ly/onZAH) by LordSamueliSolo is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
"Golden Lion Sitting OBJ Low Poly FREE" (https://skfb.ly/onZAH) by
LordSamueliSolo is licensed under Creative Commons
Attribution (http://creativecommons.org/licenses/by/4.0/).

View File

@ -1,6 +1,5 @@
This is an example application that is using the Qtk API to create custom Qt
OpenGL widgets. This is very similar to `QtkWidget` in the Qtk desktop
This is an example application that is using the Qtk API to create custom Qt
OpenGL widgets. This is very similar to `QtkWidget` in the Qtk desktop
application source code, but could be modified for different uses if needed.
There are no camera controls supported in this example. The camera is fixed.
@ -11,7 +10,8 @@ You can import your own models within `examplescene.cpp`, inside the
are applied in `ExampleScene::update()`.
The syntax for adding shapes and models is seen in the example below.
This would result in a scene with a red cube and a miniature spartan model placed on top.
This would result in a scene with a red cube and a miniature spartan model
placed on top.
```C++
void ExampleScene::init() {
@ -44,7 +44,6 @@ void ExampleScene::update() {
Other examples can be found in the source files for this example project.
## Build Instructions
Currently, this application requires manual build and installation of Qtk.
@ -58,7 +57,9 @@ cmake -S /path/to/qtk/example-app/ -B /path/to/qtk/example-app/build
cmake --build /path/to/qtk/example-app/build
```
If Qtk was not installed system-wide, we can set `QTK_PATH` to point to the custom installation directory.
If Qtk was not installed system-wide, we can set `QTK_PATH` to point to the
custom installation directory.
```bash
cmake -S /path/to/qtk/example-app/ -B /path/to/qtk/example-app/build -DQTK_PATH=/path/to/qtk/install/
cmake --build /path/to/qtk/example-app/build

View File

@ -15,8 +15,7 @@ using namespace Qtk;
* Constructors, Destructors
******************************************************************************/
QtkScene::QtkScene(Qtk::Scene * scene) :
Qtk::SceneInterface(scene) {
QtkScene::QtkScene(Qtk::Scene * scene) : Qtk::SceneInterface(scene) {
setSceneName("Qtk Scene");
getCamera().getTransform().setTranslation(0.0f, 0.0f, 20.0f);
getCamera().getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
@ -97,8 +96,8 @@ void QtkScene::init() {
model->getTransform().setTranslation(2.0f, -1.0f, -5.0f);
model->getTransform().scale(0.15f);
model =
addObject(new Qtk::Model("My scythe", ":/models/models/scythe/scythe.obj"));
model = addObject(
new Qtk::Model("My scythe", ":/models/models/scythe/scythe.obj"));
model->getTransform().setTranslation(-6.0f, 0.0f, -10.0f);
model->getTransform().rotate(-90.0f, 1.0f, 0.0f, 0.0f);
model->getTransform().rotate(90.0f, 0.0f, 1.0f, 0.0f);
@ -401,15 +400,13 @@ void QtkScene::draw() {
"uLightPosition",
MeshRenderer::getInstance("phongLight")->getTransform().getTranslation());
mTestPhong->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestPhong->releaseShaders();
mTestPhong->draw();
mTestAmbient->bindShaders();
mTestAmbient->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestAmbient->releaseShaders();
mTestAmbient->draw();
@ -422,8 +419,7 @@ void QtkScene::draw() {
->getTransform()
.getTranslation());
mTestDiffuse->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestDiffuse->releaseShaders();
mTestDiffuse->draw();
@ -436,8 +432,7 @@ void QtkScene::draw() {
->getTransform()
.getTranslation());
mTestSpecular->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestSpecular->releaseShaders();
mTestSpecular->draw();
}
@ -455,8 +450,7 @@ void QtkScene::update() {
auto alien = Model::getInstance("alienTest");
alien->setUniform("uLight.position", position);
alien->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
auto posMatrix = alien->getTransform().toMatrix();
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
alien->setUniform("uMVP.model", posMatrix);
@ -470,8 +464,7 @@ void QtkScene::update() {
auto spartan = Model::getInstance("spartanTest");
spartan->setUniform("uLight.position", position);
spartan->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
posMatrix = spartan->getTransform().toMatrix();
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
spartan->setUniform("uMVP.model", posMatrix);
@ -486,8 +479,7 @@ void QtkScene::update() {
MeshRenderer::getInstance("testLight")->getTransform().getTranslation();
phong->setUniform("uLight.position", position);
phong->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
posMatrix = phong->getTransform().toMatrix();
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
phong->setUniform("uMVP.model", posMatrix);

View File

@ -108,7 +108,7 @@ void QtkWidget::paintGL() {
}
void QtkWidget::setScene(Qtk::Scene * scene) {
if (mScene != Q_NULLPTR) {
if(mScene != Q_NULLPTR) {
delete mScene;
connect(
scene, &Qtk::Scene::sceneUpdated, MainWindow::getMainWindow(),

View File

@ -37,18 +37,18 @@ void Qtk::TreeView::updateView(const Qtk::Scene * scene) {
mSceneName = scene->getSceneName();
auto objects = scene->getObjects();
for(const auto & object : objects) {
auto item = new QTreeWidgetItem(QStringList(QString(object->getName().c_str())));
auto item =
new QTreeWidgetItem(QStringList(QString(object->getName().c_str())));
ui->treeWidget->insertTopLevelItem(0, item);
}
}
void Qtk::TreeView::itemFocus(QTreeWidgetItem * item, int column) {
QString name = item->text(column);
auto scene =
MainWindow::getMainWindow()->getQtkWidget()->getScene();
auto scene = MainWindow::getMainWindow()->getQtkWidget()->getScene();
auto & transform = scene->getCamera().getTransform();
auto object = scene->getObject(name);
if (object == Q_NULLPTR) {
if(object == Q_NULLPTR) {
qDebug() << "Attempt to get non-existing object with name '" << name
<< "'\n";
}

View File

@ -200,7 +200,9 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
}
return {vertices, indices, textures, mVertexShader.c_str(), mFragmentShader.c_str()};
return {
vertices, indices, textures, mVertexShader.c_str(),
mFragmentShader.c_str()};
}
ModelMesh::Textures Model::loadMaterialTextures(

View File

@ -195,9 +195,7 @@ namespace Qtk {
class SceneEmpty : public Scene {
public:
void init() override {
setSceneName("Empty Scene");
}
void init() override { setSceneName("Empty Scene"); }
void draw() override { Scene::draw(); }