README screenshots.
57
README.md
@ -9,38 +9,53 @@ that allow rendering geometry in 2D and 3D using custom GLSL shader programs.
|
|||||||
The Qtk desktop application provides a model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
The Qtk desktop application provides a model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
||||||
You can fly around the scene using WASD while holding down the right mouse button.
|
You can fly around the scene using WASD while holding down the right mouse button.
|
||||||
|
|
||||||
|
Object names can be double-clicked in the tree view panel for quick camera navigation.
|
||||||
|
Properties of the object, like shader code and translation / scale, can be viewed and modified in the side panel.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
All side panels and toolbars are dockable widgets that can be popped out
|
||||||
|
and reorganized as needed. Panels can also be stacked to create a docked widget with
|
||||||
|
tabs. The central widget that provides the camera view into the scene cannot be
|
||||||
|
detached from the main window in this way.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The small triangles floating near 3D models represent the light source being used for the shader.
|
||||||
|
These appear on models using phong, specular, and diffuse lighting techniques.
|
||||||
|
|
||||||
|
The default scene contains basic examples like texture mapping to make a crate from basic cube geometry
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Examples of Ambient, Diffuse, and Specular GLSL shaders.
|
||||||
|
|
||||||
|
| Ambient | Diffuse | Specular |
|
||||||
|
|-------------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------|
|
||||||
|
| <img src="resources/screenshots/screen-ambient.png"/> | <img src="resources/screenshots/screen-diffuse.png"/> | <img src="resources/screenshots/screen-specular.png"/> |
|
||||||
|
|
||||||
|
And more advanced techniques like Phong lighting (ambient + diffuse + specular) and normal mapping.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
| Normal Mapping Disabled | Normal Mapping Enabled |
|
||||||
|
|------------------------------------------------------|--------------------------------------------------------|
|
||||||
|
| <img src="resources/screenshots/spartan-phong.png"/> | <img src="resources/screenshots/spartan-normals.png"/> |
|
||||||
|
|
||||||
|
See the `View` toolbar menu to enable debug console widgets for open scenes or reopen previously closed panels.
|
||||||
|
|
||||||
Key features that are planned:
|
Key features that are planned:
|
||||||
|
|
||||||
- [x] Runtime loading of `.obj` or similar 3D models.
|
- [x] Runtime loading of `.obj` or similar 3D models.
|
||||||
- [x] Drag-and-drop interaction for adding objects to the scene.
|
- [x] Drag-and-drop interaction for adding objects to the scene.
|
||||||
|
- [x] Shader / object properties panel to modify related settings.
|
||||||
- [ ] Runtime reloading of modified GLSL shaders attached to objects within scenes.
|
- [ ] Runtime reloading of modified GLSL shaders attached to objects within scenes.
|
||||||
- [ ] Multiple views of a scene at one time.
|
- [ ] Multiple views of a scene at one time.
|
||||||
- [ ] Camera control modes such as panning, orbiting, or following objects.
|
- [ ] Camera control modes such as panning, orbiting, or following objects.
|
||||||
- [ ] Save / load for scene data. The current inheritance model is temporary.
|
- [ ] Save / load for scene data. The current inheritance model is temporary.
|
||||||
- [ ] Basic text editor for quickly modifying shaders attached to objects.
|
- [ ] 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.
|
- [ ] Reduce size of application resources and git references.
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Spartan with no normals -
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Spartan with normals -
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Object names can be double-clicked in the tree view panel for quick camera
|
|
||||||
navigation. All side panels and toolbars are dockable widgets that can be popped out
|
|
||||||
and reorganized as needed. Panels can also be stacked to create a docked widget with
|
|
||||||
tabs. The central widget that provides the camera view into the scene cannot be
|
|
||||||
detached from the main window in this way. See the `View` menu to enable debug
|
|
||||||
console widgets for open scenes or reopen previously closed panels.
|
|
||||||
|
|
||||||
The small triangles floating near 3D models represent the light source being used for the shader.
|
|
||||||
These appear on models using phong, specular, and diffuse lighting techniques.
|
|
||||||
|
|
||||||
For examples of using the Qtk API, see the `example-app` project in the root of
|
For examples of using the Qtk API, see the `example-app` project in the root of
|
||||||
this repository.
|
this repository.
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@
|
|||||||
<file alias="solid-phong.vert">shaders/vertex/solid-phong.vert</file>
|
<file alias="solid-phong.vert">shaders/vertex/solid-phong.vert</file>
|
||||||
<file alias="model-basic.frag">shaders/fragment/model-basic.frag</file>
|
<file alias="model-basic.frag">shaders/fragment/model-basic.frag</file>
|
||||||
<file alias="model-basic.vert">shaders/vertex/model-basic.vert</file>
|
<file alias="model-basic.vert">shaders/vertex/model-basic.vert</file>
|
||||||
<file alias="model-specular.frag">shaders/fragment/model-specular.frag</file>
|
<file alias="model-phong.frag">shaders/fragment/model-phong.frag</file>
|
||||||
<file alias="model-specular.vert">shaders/vertex/model-specular.vert</file>
|
<file alias="model-phong.vert">shaders/vertex/model-phong.vert</file>
|
||||||
<file alias="model-normals.frag">shaders/fragment/model-normals.frag</file>
|
<file alias="model-normals.frag">shaders/fragment/model-normals.frag</file>
|
||||||
<file alias="model-normals.vert">shaders/vertex/model-normals.vert</file>
|
<file alias="model-normals.vert">shaders/vertex/model-normals.vert</file>
|
||||||
<file alias="skybox.frag">skybox/skybox.frag</file>
|
<file alias="skybox.frag">skybox/skybox.frag</file>
|
||||||
|
Before Width: | Height: | Size: 316 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 263 KiB After Width: | Height: | Size: 263 KiB |
BIN
resources/screenshots/screen-1.png
Normal file
After Width: | Height: | Size: 428 KiB |
BIN
resources/screenshots/screen-ambient.png
Normal file
After Width: | Height: | Size: 205 KiB |
BIN
resources/screenshots/screen-diffuse.png
Normal file
After Width: | Height: | Size: 188 KiB |
BIN
resources/screenshots/screen-phong.png
Normal file
After Width: | Height: | Size: 264 KiB |
BIN
resources/screenshots/screen-specular.png
Normal file
After Width: | Height: | Size: 176 KiB |
BIN
resources/screenshots/screen-texture.png
Normal file
After Width: | Height: | Size: 288 KiB |
BIN
resources/screenshots/screen.png
Normal file
After Width: | Height: | Size: 437 KiB |
BIN
resources/screenshots/spartan-normals.png
Normal file
After Width: | Height: | Size: 359 KiB |
BIN
resources/screenshots/spartan-phong.png
Normal file
After Width: | Height: | Size: 349 KiB |
Before Width: | Height: | Size: 660 KiB |
Before Width: | Height: | Size: 646 KiB |
@ -260,8 +260,8 @@ void QtkScene::init()
|
|||||||
/* Test spartan Model with phong lighting, specular and normal mapping. */
|
/* Test spartan Model with phong lighting, specular and normal mapping. */
|
||||||
model = addObject(new Qtk::Model("spartanTest",
|
model = addObject(new Qtk::Model("spartanTest",
|
||||||
":/models/models/spartan/spartan.obj",
|
":/models/models/spartan/spartan.obj",
|
||||||
":/shaders/model-normals.vert",
|
":/shaders/model-phong.vert",
|
||||||
":/shaders/model-normals.frag"));
|
":/shaders/model-phong.frag"));
|
||||||
model->getTransform().setTranslation(0.0f, -1.0f, 10.0f);
|
model->getTransform().setTranslation(0.0f, -1.0f, 10.0f);
|
||||||
model->getTransform().scale(2.0f);
|
model->getTransform().scale(2.0f);
|
||||||
model->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
model->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||||
|
@ -41,36 +41,33 @@ void Qtk::TreeView::updateView(const Qtk::Scene * scene)
|
|||||||
mSceneName = scene->getSceneName();
|
mSceneName = scene->getSceneName();
|
||||||
auto objects = scene->getObjects();
|
auto objects = scene->getObjects();
|
||||||
for (const auto & object : objects) {
|
for (const auto & object : objects) {
|
||||||
auto item =
|
QStringList list(QStringList(QString(object->getName().c_str())));
|
||||||
new QTreeWidgetItem(QStringList(QString(object->getName().c_str())));
|
ui->treeWidget->insertTopLevelItem(0, new QTreeWidgetItem(list));
|
||||||
ui->treeWidget->insertTopLevelItem(0, item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qtk::TreeView::itemFocus(QTreeWidgetItem * item, int column)
|
void Qtk::TreeView::itemFocus(QTreeWidgetItem * item, int column)
|
||||||
{
|
{
|
||||||
QString name = item->text(column);
|
const QString & name = item->text(column);
|
||||||
auto scene = MainWindow::getMainWindow()->getQtkWidget()->getScene();
|
auto scene = MainWindow::getMainWindow()->getQtkWidget()->getScene();
|
||||||
auto & transform = Qtk::Scene::getCamera().getTransform();
|
|
||||||
auto object = scene->getObject(name);
|
auto object = scene->getObject(name);
|
||||||
Transform3D * objectTransform;
|
|
||||||
// If the object is a mesh or model, focus the camera on it.
|
// If the object is a mesh or model, focus the camera on it.
|
||||||
if (object == Q_NULLPTR) {
|
if (object == Q_NULLPTR) {
|
||||||
qDebug() << "Attempt to get non-existing object with name '" << name
|
qDebug() << "Attempt to get non-existing object with name '" << name
|
||||||
<< "'\n";
|
<< "'\n";
|
||||||
} else if (object->getType() == Object::QTK_MESH) {
|
return;
|
||||||
objectTransform = &dynamic_cast<MeshRenderer *>(object)->getTransform();
|
|
||||||
} else if (object->getType() == Object::QTK_MODEL) {
|
|
||||||
objectTransform = &dynamic_cast<Model *>(object)->getTransform();
|
|
||||||
}
|
}
|
||||||
auto focusScale = objectTransform->getScale();
|
const Transform3D& objectTransform = object->getTransform();
|
||||||
|
|
||||||
|
auto & camera_transform = Qtk::Scene::getCamera().getTransform();
|
||||||
|
auto focusScale = objectTransform.getScale();
|
||||||
float width = focusScale.x() / 2.0f;
|
float width = focusScale.x() / 2.0f;
|
||||||
float height = focusScale.y() / 2.0f;
|
float height = focusScale.y() / 2.0f;
|
||||||
QVector3D pos = objectTransform->getTranslation();
|
QVector3D pos = objectTransform.getTranslation();
|
||||||
// pos.setX(pos.x() + width);
|
// pos.setX(pos.x() + width);
|
||||||
pos.setY(pos.y() + height);
|
pos.setY(pos.y() + height);
|
||||||
transform.setTranslation(pos);
|
camera_transform.setTranslation(pos);
|
||||||
transform.translate(0.0f, 0.0f, 3.0f);
|
camera_transform.translate(0.0f, 0.0f, 3.0f);
|
||||||
|
|
||||||
// Emit signal from qtk widget for new object focus. Triggers GUI updates.
|
// Emit signal from qtk widget for new object focus. Triggers GUI updates.
|
||||||
emit MainWindow::getMainWindow() -> getQtkWidget()->objectFocusChanged(name);
|
emit MainWindow::getMainWindow() -> getQtkWidget()->objectFocusChanged(name);
|
||||||
|
@ -111,6 +111,11 @@ namespace Qtk
|
|||||||
return mTransform;
|
return mTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline virtual Transform3D & getTransform()
|
||||||
|
{
|
||||||
|
return mTransform;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline virtual std::string getVertexShader() const
|
[[nodiscard]] inline virtual std::string getVertexShader() const
|
||||||
{
|
{
|
||||||
return "Base Object has no vertex shader.";
|
return "Base Object has no vertex shader.";
|
||||||
|
@ -118,11 +118,9 @@ void Scene::setSkybox(Skybox * skybox)
|
|||||||
|
|
||||||
void Scene::initSceneObjectName(Object * object)
|
void Scene::initSceneObjectName(Object * object)
|
||||||
{
|
{
|
||||||
if (!mObjectCount.count(object->getName())) {
|
mObjectCount[object->getName()] = mObjectCount.count(object->getName()) + 1;
|
||||||
mObjectCount[object->getName()] = 1;
|
|
||||||
} else {
|
// If the object exists make it's name unique.
|
||||||
mObjectCount[object->getName()]++;
|
|
||||||
}
|
|
||||||
auto count = mObjectCount[object->getName()];
|
auto count = mObjectCount[object->getName()];
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
object->setName(object->getName() + " (" + std::to_string(count) + ")");
|
object->setName(object->getName() + " (" + std::to_string(count) + ")");
|
||||||
|