From aebab76915b05a2bc53e9116781d578ae351e2f3 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Sun, 19 Sep 2021 14:06:41 -0400 Subject: [PATCH] Add Scene class to manage active object data + Move MainWidget::Camera() to Scene::Camera() + Move MainWidget::Projection() to Scene::Projection() + Add Scene::View() static function to retrieve camera view matrix --- CMakeLists.txt | 23 +- README.md | 6 +- lib/mainwidget.cpp | 755 ++---------------------------------------- lib/mainwidget.h | 19 +- lib/meshrenderer.cpp | 6 +- lib/model.cpp | 8 +- lib/scene.cpp | 759 +++++++++++++++++++++++++++++++++++++++++++ lib/scene.h | 45 +++ lib/skybox.cpp | 5 +- lib/skybox.h | 1 - 10 files changed, 855 insertions(+), 772 deletions(-) create mode 100644 lib/scene.cpp create mode 100644 lib/scene.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bab8140..3f7d690 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,21 +73,23 @@ target_link_libraries(texture PUBLIC Qt5::Widgets) add_library(object lib/object.cpp) target_include_directories(object PUBLIC lib/) target_link_libraries(object PUBLIC Qt5::Widgets) +target_link_libraries(object INTERFACE mesh) # MeshRenderer add_library(meshrenderer lib/meshrenderer.cpp) target_include_directories(meshrenderer PUBLIC lib/) -target_link_libraries(meshrenderer PUBLIC Qt5::Widgets) +target_link_libraries(meshrenderer PUBLIC object) # Camera3D add_library(camera3d lib/camera3d.cpp) target_include_directories(camera3d PUBLIC lib/) +target_link_libraries(camera3d INTERFACE input) target_link_libraries(camera3d PUBLIC Qt5::Widgets) # Skybox add_library(skybox lib/skybox.cpp) +# Skybox needs Mesh, Camera3D, and Qt5::Widgets target_link_libraries(skybox PRIVATE mesh) -# Skybox needs Mesh and Camera3D and Qt5::Widgets target_link_libraries(skybox PRIVATE camera3d) # Transform3D @@ -102,19 +104,22 @@ target_link_libraries(model PRIVATE assimp) # Model library requires transform3d and Qt5::Widgets target_link_libraries(model PUBLIC transform3d) +# Scene +add_library(scene lib/scene.cpp) +target_include_directories(scene PUBLIC lib/) +target_link_libraries(scene PUBLIC model) +target_link_libraries(scene PUBLIC meshrenderer) +target_link_libraries(scene PUBLIC skybox) +target_link_libraries(scene PUBLIC texture) + ################################################################################ # Final Application ################################################################################ -target_link_libraries(main-widget PUBLIC model) -target_link_libraries(main-widget PRIVATE input) -target_link_libraries(main-widget PRIVATE transform3d) -target_link_libraries(main-widget PRIVATE object) -target_link_libraries(main-widget PRIVATE meshrenderer) -target_link_libraries(main-widget PRIVATE texture) -target_link_libraries(main-widget PRIVATE skybox) +#target_link_libraries(main-widget PRIVATE input) target_link_libraries(main-widget PRIVATE mesh) +target_link_libraries(main-widget PUBLIC scene) # Link qtk executable to main main-widget library target_link_libraries(qtk PUBLIC main-widget) diff --git a/README.md b/README.md index cac69ee..5fbf68c 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,14 @@ You can import your own models within `mainwdget.cpp`, inside the to explain which model or example I'm modifying. Rotations and translations happen in `MainWidget::update()`, 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. +examples in the `resources/models/` directory. For more in-depth examples, see +`scene.h` and `scene.cpp` Can be built with cmake manually or using [Qt Creator](https://github.com/qt-creator/qt-creator). To build and run `qtk` on Ubuntu - ```bash -# Qt Creator sudo apt update -y && sudo apt install qttools5-dev freeglut3-dev libassimp-dev cmake build-essential git clone https://gitlab.com/shaunrd0/qtk && cd qtk mkdir build && cd build @@ -45,7 +45,7 @@ Spartan with normals - "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" () 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 diff --git a/lib/mainwidget.cpp b/lib/mainwidget.cpp index 1cc2f50..c135da0 100644 --- a/lib/mainwidget.cpp +++ b/lib/mainwidget.cpp @@ -10,18 +10,11 @@ #include #include -#include -#include #include -#include -#include +#include #include -// Static member initialization -QMatrix4x4 MainWidget::mProjection; -Camera3D MainWidget::mCamera; - /******************************************************************************* * Constructors, Destructors @@ -66,575 +59,11 @@ void MainWidget::teardownGL() void MainWidget::initObjects() { - mCamera.transform().setTranslation(0.0f, 0.0f, 5.0f); - mCamera.transform().setRotation(180.0f, 0.0f, 1.0f, 0.0f); - - mSkybox = new Skybox; - - // - // Model loading - - mModels.push_back(new Model("backpack", - "../resources/models/backpack/backpack.obj")); - // Sometimes model textures need flipped in certain directions - mModels.back()->flipTexture("diffuse.jpg", false, true); - mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f); - - mModels.push_back( - new Model("bird", - "../resources/models/bird/bird.obj")); - mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f); - // Sometimes the models are very large - mModels.back()->mTransform.scale(0.0025f); - mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f); - - mModels.push_back(new Model("lion", - "../resources/models/lion/lion.obj")); - mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f); - mModels.back()->mTransform.scale(0.15f); - - mModels.push_back( - new Model("alien", - "../resources/models/alien-hominid/alien.obj")); - mModels.back()->mTransform.setTranslation(2.0f, -1.0f, -5.0f); - mModels.back()->mTransform.scale(0.15f); - - mModels.push_back( - new Model("scythe", - "../resources/models/scythe/scythe.obj") - ); - mModels.back()->mTransform.setTranslation(-6.0f, 0.0f, -10.0f); - mModels.back()->mTransform.rotate(-90.0f, 1.0f, 0.0f, 0.0f); - mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f); - - mModels.push_back( - new Model("masterChief", - "../resources/models/spartan/spartan.obj")); - mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f); - - - // Render an alien with specular - // Test alien Model with phong lighting and specular mapping - mMeshes.push_back( - new MeshRenderer("alienTestLight", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f); - mMeshes.back()->mTransform.scale(0.25f); - // This function changes values we have allocated in a buffer, so init() after - mMeshes.back()->setColor(GREEN); - mMeshes.back()->init(); - - mModels.push_back( - new Model("alienTest", - "../resources/models/alien-hominid/alien.obj", - ":/model-specular.vert", ":/model-specular.frag")); - mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f); - mModels.back()->mTransform.scale(0.15f); - mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uMaterial.ambientStrength", 0.8f); - mModels.back()->setUniform("uMaterial.diffuseStrength", 0.8f); - mModels.back()->setUniform("uMaterial.specularStrength", 1.0f); - mModels.back()->setUniform("uMaterial.shine", 32.0f); - - mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f)); - - // Test spartan Model with phong lighting, specular and normal mapping - mMeshes.push_back( - new MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(1.0f, 1.5f, 10.0f); - mMeshes.back()->mTransform.scale(0.25f); - // This function changes values we have allocated in a buffer, so init() after - mMeshes.back()->setColor(GREEN); - mMeshes.back()->init(); - - mModels.push_back( - new Model("spartanTest", - "../resources/models/spartan/spartan.obj", - ":/model-normals.vert", ":/model-normals.frag")); - mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f); - mModels.back()->mTransform.scale(2.0f); - mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uMaterial.ambientStrength", 1.0f); - mModels.back()->setUniform("uMaterial.diffuseStrength", 1.0f); - mModels.back()->setUniform("uMaterial.specularStrength", 1.0f); - mModels.back()->setUniform("uMaterial.shine", 128.0f); - mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); - mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f)); - - - // Test basic cube with phong.vert and phong.frag shaders - mMeshes.push_back( - new MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(5.0f, 1.25f, 10.0f); - mMeshes.back()->mTransform.scale(0.25f); - mMeshes.back()->setDrawType(GL_LINE_LOOP); - // This function changes values we have allocated in a buffer, so init() after - mMeshes.back()->setColor(GREEN); - mMeshes.back()->init(); - - mMeshes.push_back( - new MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS))); - mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 10.0f); - mMeshes.back()->setShaders(":/phong.vert", ":/phong.frag"); - mMeshes.back()->setColor(QVector3D(0.0f, 0.25f, 0.0f)); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - - mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), - mMeshes.back()->normals().size() - * sizeof(mMeshes.back()->normals()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - - mMeshes.back()->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f)); - mMeshes.back()->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f)); - mMeshes.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f)); - mMeshes.back()->setUniform("uMaterial.ambientStrength", 1.0f); - mMeshes.back()->setUniform("uMaterial.diffuseStrength", 1.0f); - mMeshes.back()->setUniform("uMaterial.specularStrength", 1.0f); - mMeshes.back()->setUniform("uMaterial.shine", 64.0f); - mMeshes.back()->setUniform("uLight.ambient", QVector3D(0.25f, 0.2f, 0.075f)); - mMeshes.back()->setUniform("uLight.diffuse", QVector3D(0.75f, 0.6f, 0.22f)); - mMeshes.back()->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f)); - mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); - - mMeshes.back()->mProgram.release(); - - - // - // Creating simple objects with the MeshRenderer class - - mMeshes.push_back( - new MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(-5.0f, 0.0f, -2.0f); - - mMeshes.push_back( - new MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(-7.0f, 0.0f, -2.0f); - - mMeshes.push_back( - new MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(-9.0f, 0.0f, -2.0f); - mMeshes.back()->setDrawType(GL_LINE_LOOP); - - mMeshes.push_back( - new MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(-7.0f, 2.0f, -2.0f); - mMeshes.back()->mTransform.scale(0.25f); - - mMeshes.push_back( - new MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(-7.0f, -2.0f, -2.0f); - mMeshes.back()->mTransform.scale(0.25f); - mMeshes.back()->setColor(GREEN); - // This function changes values we have allocated in a buffer, so init() after - mMeshes.back()->setDrawType(GL_LINE_LOOP); - mMeshes.back()->init(); - - - // - // Testing for normals, texture coordinates - - // RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS - mMeshes.push_back( - new MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS))); - mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 4.0f); - mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); - mMeshes.back()->init(); - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), - mMeshes.back()->normals().size() - * sizeof(mMeshes.back()->normals()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - - mMeshes.back()->mProgram.release(); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - - // RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS - mMeshes.push_back( - new MeshRenderer("rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS))); - mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 2.0f); - mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); - mMeshes.back()->init(); - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), - mMeshes.back()->normals().size() - * sizeof(mMeshes.back()->normals()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - - mMeshes.back()->mProgram.release(); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - - // Texturing a cube using texture coordinates and glDrawArrays - // + Texturing with UVs using glDrawElements requires QTK_DRAW_ELEMENTS_NORMALS - // + UVs required duplicating element position data from QTK_DRAW_ELEMENTS - // + This is because the same position must use different UV coordinates - mMeshes.push_back( - new MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS))); - mMeshes.back()->mTransform.setTranslation(-3.0f, 0.0f, -2.0f); - mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); - mMeshes.back()->setUniform("uTexture", 0); - mMeshes.back()->texture().bind(); - - mMeshes.back()->texture().release(); - - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.destroy(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), - mMeshes.back()->mShape.texCoords().size() - * sizeof(mMeshes.back()->mShape.texCoords()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 2, sizeof(QVector2D)); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - mMeshes.back()->mProgram.release(); - - // Test drawing a cube with texture coordinates using glDrawElements - mMeshes.push_back( - new MeshRenderer("uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS))); - mMeshes.back()->mTransform.setTranslation(-1.7f, 0.0f, -2.0f); - mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); - mMeshes.back()->init(); - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->mNBO.allocate(mMeshes.back()->texCoords().data(), - mMeshes.back()->texCoords().size() - * sizeof(mMeshes.back()->texCoords()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); - - mMeshes.back()->mProgram.setUniformValue("uTexture", 0); - mMeshes.back()->mProgram.release(); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - mMeshes.back()->mTransform.rotate(45.0f, 0.0f, 1.0f, 0.0f); - - // Texturing a cube using a cube map - // + Cube map texturing works with both QTK_DRAW_ARRAYS and QTK_DRAW_ELEMENTS - mMeshes.push_back( - new MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(-3.0f, 1.0f, -2.0f); - mMeshes.back()->mTransform.setRotation(45.0f, 0.0f, 1.0f, 0.0f); - mMeshes.back()->setShaders(":/texture-cubemap.vert", ":/texture-cubemap.frag"); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->setTexture(Texture::initCubeMap(":/crate.png")); - mMeshes.back()->setUniform("uTexture", 0); - - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.destroy(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), - mMeshes.back()->mShape.texCoords().size() - * sizeof(mMeshes.back()->mShape.texCoords()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 2, sizeof(QVector2D)); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - mMeshes.back()->mProgram.release(); - - // Create a cube with custom shaders - // + Apply RGB normals shader and spin the cube for a neat effect - mMeshes.push_back( - new MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS))); - mMeshes.back()->mTransform.setTranslation(5.0f, 2.0f, -2.0f); - mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); - mMeshes.back()->init(); - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), - mMeshes.back()->normals().size() - * sizeof(mMeshes.back()->normals()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - - mMeshes.back()->mProgram.release(); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - - - // RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS - mMeshes.push_back( - new MeshRenderer("rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS))); - mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 2.0f); - mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), - mMeshes.back()->normals().size() - * sizeof(mMeshes.back()->normals()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - mMeshes.back()->mProgram.release(); - - // RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS - mMeshes.push_back( - new MeshRenderer("rgbTriangleElementsTest", - Triangle(QTK_DRAW_ELEMENTS_NORMALS))); - mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 4.0f); - mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), - mMeshes.back()->normals().size() - * sizeof(mMeshes.back()->normals()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - mMeshes.back()->mProgram.release(); - - // Test drawing triangle with glDrawArrays with texture coordinates - mMeshes.push_back( - new MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS))); - mMeshes.back()->mTransform.setTranslation(-3.0f, 2.0f, -2.0f); - mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); - mMeshes.back()->setUniform("uTexture", 0); - mMeshes.back()->texture().bind(); - - mMeshes.back()->texture().release(); - - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.destroy(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), - mMeshes.back()->mShape.texCoords().size() - * sizeof(mMeshes.back()->mShape.texCoords()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 2, sizeof(QVector2D)); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - mMeshes.back()->mProgram.release(); - - // Test drawing triangle with glDrawElements with texture coordinates - mMeshes.push_back( - new MeshRenderer("testTriangleElementsUV", - Triangle(QTK_DRAW_ELEMENTS_NORMALS))); - mMeshes.back()->mTransform.setTranslation(-2.5f, 0.0f, -1.0f); - mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - - mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); - mMeshes.back()->setUniform("uTexture", 0); - mMeshes.back()->texture().bind(); - - mMeshes.back()->texture().release(); - - mMeshes.back()->mVAO.bind(); - mMeshes.back()->mNBO.destroy(); - mMeshes.back()->mNBO.create(); - mMeshes.back()->mNBO.bind(); - mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), - mMeshes.back()->mShape.texCoords().size() - * sizeof(mMeshes.back()->mShape.texCoords()[0])); - mMeshes.back()->mProgram.enableAttributeArray(1); - mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 2, sizeof(QVector2D)); - mMeshes.back()->mNBO.release(); - mMeshes.back()->mVAO.release(); - mMeshes.back()->mProgram.release(); - - - // - // Lighting cube examples - - // Example of a cube with no lighting applied - mMeshes.push_back( - new MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, -2.0f); - mMeshes.back()->setShaders(":/solid-perspective.vert", - ":/solid-perspective.frag"); - mMeshes.back()->init(); - mMeshes.back()->mProgram.bind(); - mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); - mMeshes.back()->mProgram.release(); - - // Create objects that represent light sources for lighting examples - mMeshes.push_back( - new MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(3.0f, 2.0f, -2.0f); - mMeshes.back()->mTransform.scale(0.25f); - - mMeshes.push_back( - new MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(9.0f, 2.0f, -2.0f); - mMeshes.back()->mTransform.scale(0.25f); - - mMeshes.push_back( - new MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS))); - mMeshes.back()->mTransform.setTranslation(11.0f, 2.0f, -2.0f); - mMeshes.back()->mTransform.scale(0.25f); - - // Initialize Phong example cube - mTestPhong = new MeshRenderer("phong", Cube()); - mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f); - mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag"); - mTestPhong->init(); - mTestPhong->mProgram.bind(); - mTestPhong->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); - mTestPhong->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); - mTestPhong->setUniform("uAmbientStrength", 0.2f); - mTestPhong->setUniform("uSpecularStrength", 0.50f); - mTestPhong->setUniform("uSpecularShine", 256); - - mTestPhong->mVAO.bind(); - mTestPhong->mNBO.create(); - mTestPhong->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); - mTestPhong->mNBO.bind(); - mTestPhong->mNBO.allocate(mTestPhong->normals().data(), - mTestPhong->normals().size() - * sizeof(mTestPhong->normals()[0])); - mTestPhong->mProgram.enableAttributeArray(1); - mTestPhong->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - mTestPhong->mNBO.release(); - mTestPhong->mVAO.release(); - mTestPhong->mProgram.release(); - - - // Initialize Ambient example cube - mTestAmbient = new MeshRenderer("ambient", Cube()); - mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f); - mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag"); - mTestAmbient->init(); - mTestAmbient->mProgram.bind(); - mTestAmbient->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); - mTestAmbient->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); - mTestAmbient->setUniform("uAmbientStrength", 0.2f); - - mTestAmbient->mVAO.bind(); - mTestAmbient->mNBO.create(); - mTestAmbient->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); - mTestAmbient->mNBO.bind(); - mTestAmbient->mNBO.allocate(mTestAmbient->normals().data(), - mTestAmbient->normals().size() - * sizeof(mTestAmbient->normals()[0])); - mTestAmbient->mProgram.enableAttributeArray(1); - mTestAmbient->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - mTestAmbient->mNBO.release(); - mTestAmbient->mVAO.release(); - mTestAmbient->mProgram.release(); - - // Initialize Diffuse example cube - mTestDiffuse = new MeshRenderer("diffuse", Cube()); - mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f); - mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag"); - mTestDiffuse->init(); - mTestDiffuse->mProgram.bind(); - mTestDiffuse->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); - mTestDiffuse->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); - mTestDiffuse->setUniform("uAmbientStrength", 0.2f); - - mTestDiffuse->mVAO.bind(); - mTestDiffuse->mNBO.create(); - mTestDiffuse->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); - mTestDiffuse->mNBO.bind(); - mTestDiffuse->mNBO.allocate(mTestDiffuse->normals().data(), - mTestDiffuse->normals().size() - * sizeof(mTestDiffuse->normals()[0])); - mTestDiffuse->mProgram.enableAttributeArray(1); - mTestDiffuse->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - mTestDiffuse->mNBO.release(); - mTestDiffuse->mVAO.release(); - mTestDiffuse->mProgram.release(); - - // Initialize Specular example cube - mTestSpecular = new MeshRenderer("specular", Cube()); - mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f); - mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag"); - mTestSpecular->init(); - mTestSpecular->mProgram.bind(); - mTestSpecular->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); - mTestSpecular->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); - mTestSpecular->setUniform("uAmbientStrength", 0.2f); - mTestSpecular->setUniform("uSpecularStrength", 0.50f); - mTestSpecular->setUniform("uSpecularShine", 256); - - mTestSpecular->mVAO.bind(); - mTestSpecular->mNBO.create(); - mTestSpecular->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); - mTestSpecular->mNBO.bind(); - mTestSpecular->mNBO.allocate(mTestSpecular->normals().data(), - mTestSpecular->normals().size() - * sizeof(mTestSpecular->normals()[0])); - mTestSpecular->mProgram.enableAttributeArray(1); - mTestSpecular->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, - 3, sizeof(QVector3D)); - mTestSpecular->mNBO.release(); - mTestSpecular->mVAO.release(); - mTestSpecular->mProgram.release(); - + mScene = new Scene; // Drawing a primitive object using Qt and OpenGL // The Object class only stores basic QOpenGL* members and shape data + // + Within mainwidget, mObject serves as a basic QOpenGL example mObject = new Object("testObject"); mObject->setVertices(Cube(QTK_DRAW_ELEMENTS).vertices()); mObject->setIndices(Cube(QTK_DRAW_ELEMENTS).indices()); @@ -681,63 +110,19 @@ void MainWidget::paintGL() // Clear buffers glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - mSkybox->draw(); - - for (auto & model : mModels) model->draw(); - - mTestPhong->mProgram.bind(); - mTestPhong->setUniform("uModelInverseTransposed", - mTestPhong->mTransform.toMatrix().normalMatrix()); - mTestPhong->setUniform( - "uLightPosition", - MeshRenderer::getInstance("phongLight")->mTransform.translation()); - mTestPhong->setUniform("uCameraPosition", - mCamera.transform().translation()); - mTestPhong->mProgram.release(); - mTestPhong->draw(); - - mTestAmbient->mProgram.bind(); - mTestAmbient->setUniform("uCameraPosition", - mCamera.transform().translation()); - mTestAmbient->mProgram.release(); - mTestAmbient->draw(); - - mTestDiffuse->mProgram.bind(); - mTestDiffuse->setUniform("uModelInverseTransposed", - mTestDiffuse->mTransform.toMatrix().normalMatrix()); - mTestDiffuse->setUniform( - "uLightPosition", - MeshRenderer::getInstance("diffuseLight")->mTransform.translation()); - mTestDiffuse->setUniform("uCameraPosition", - mCamera.transform().translation()); - mTestDiffuse->mProgram.release(); - mTestDiffuse->draw(); - - mTestSpecular->mProgram.bind(); - mTestSpecular->setUniform( - "uModelInverseTransposed", - mTestSpecular->mTransform.toMatrix().normalMatrix()); - mTestSpecular->setUniform( - "uLightPosition", - MeshRenderer::getInstance("specularLight")->mTransform.translation()); - mTestSpecular->setUniform("uCameraPosition", - mCamera.transform().translation()); - mTestSpecular->mProgram.release(); - mTestSpecular->draw(); - + // Draw the scene first, since it handles drawing our skybox + mScene->draw(); + // Draw any additional objects within mainwidget manually mObject->mProgram.bind(); mObject->mVAO.bind(); - mObject->mProgram.setUniformValue("uModel", - mObject->mTransform.toMatrix()); - mObject->mProgram.setUniformValue("uView", mCamera.toMatrix()); - mObject->mProgram.setUniformValue("uProjection", mProjection); + mObject->mProgram.setUniformValue("uModel", mObject->mTransform.toMatrix()); + mObject->mProgram.setUniformValue("uView", Scene::Camera().toMatrix()); + mObject->mProgram.setUniformValue("uProjection", Scene::Projection()); glDrawElements(GL_TRIANGLES, mObject->indices().size(), GL_UNSIGNED_INT, mObject->indices().data()); mObject->mVAO.release(); mObject->mProgram.release(); - - for (const auto &mesh : mMeshes) mesh->draw(); } void MainWidget::initializeGL() @@ -775,8 +160,8 @@ void MainWidget::initializeGL() void MainWidget::resizeGL(int width, int height) { - mProjection.setToIdentity(); - mProjection.perspective(45.0f, + Scene::Projection().setToIdentity(); + Scene::Projection().perspective(45.0f, float(width) / float(height), 0.1f, 1000.0f); } @@ -790,103 +175,7 @@ void MainWidget::update() { updateCameraInput(); - auto position = MeshRenderer::getInstance("alienTestLight")->mTransform.translation(); - Model::getInstance("alienTest")->setUniform( - "uLight.position", position); - Model::getInstance("alienTest")->setUniform( - "uCameraPosition", mCamera.transform().translation()); - auto posMatrix = Model::getInstance("alienTest")->mTransform.toMatrix(); - Model::getInstance("alienTest")->setUniform( - "uMVP.normalMatrix", posMatrix.normalMatrix()); - Model::getInstance("alienTest")->setUniform( - "uMVP.model", posMatrix); - Model::getInstance("alienTest")->setUniform( - "uMVP.view", MainWidget::Camera().toMatrix()); - Model::getInstance("alienTest")->setUniform( - "uMVP.projection", MainWidget::Projection()); - Model::getInstance("alienTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f); - - position = MeshRenderer::getInstance("spartanTestLight")->mTransform.translation(); - Model::getInstance("spartanTest")->setUniform( - "uLight.position", position); - Model::getInstance("spartanTest")->setUniform( - "uCameraPosition", mCamera.transform().translation()); - posMatrix = Model::getInstance("spartanTest")->mTransform.toMatrix(); - Model::getInstance("spartanTest")->setUniform( - "uMVP.normalMatrix", posMatrix.normalMatrix()); - Model::getInstance("spartanTest")->setUniform( - "uMVP.model", posMatrix); - Model::getInstance("spartanTest")->setUniform( - "uMVP.view", MainWidget::Camera().toMatrix()); - Model::getInstance("spartanTest")->setUniform( - "uMVP.projection", MainWidget::Projection()); - Model::getInstance("spartanTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f); - - - - MeshRenderer::getInstance("testPhong")->mTransform.rotate( - 0.75f, 1.0f, 0.5f, 0.0f); - MeshRenderer::getInstance("testPhong")->mProgram.bind(); - position = MeshRenderer::getInstance("testLight")->mTransform.translation(); - MeshRenderer::getInstance("testPhong")->setUniform( - "uLight.position", position); - MeshRenderer::getInstance("testPhong")->setUniform( - "uCameraPosition", mCamera.transform().translation()); - posMatrix = MeshRenderer::getInstance("testPhong")->mTransform.toMatrix(); - MeshRenderer::getInstance("testPhong")->setUniform( - "uMVP.normalMatrix", posMatrix.normalMatrix()); - MeshRenderer::getInstance("testPhong")->setUniform( - "uMVP.model", posMatrix); - MeshRenderer::getInstance("testPhong")->setUniform( - "uMVP.view", MainWidget::Camera().toMatrix()); - MeshRenderer::getInstance("testPhong")->setUniform( - "uMVP.projection", MainWidget::Projection()); - MeshRenderer::getInstance("testPhong")->mProgram.release(); - - // Rotate lighting example cubes - mTestPhong->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); - MeshRenderer::getInstance("noLight")->mTransform.rotate( - 0.75f, 0.5f, 0.3f, 0.2f); - mTestAmbient->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); - mTestDiffuse->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); - mTestSpecular->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); - - // Examples of various translations and rotations - - // Rotate in multiple directions simultaneously - MeshRenderer::getInstance("rgbNormalsCube")->mTransform.rotate( - 0.75f, 0.2f, 0.4f, 0.6f); - - // Pitch forward and roll sideways - MeshRenderer::getInstance("leftTriangle")->mTransform.rotate( - 0.75f, 1.0f, 0.0f, 0.0f); - MeshRenderer::getInstance("rightTriangle")->mTransform.rotate( - 0.75f, 0.0f, 0.0f, 1.0f); - - // Move between two positions over time - static float translateX = 0.025f; - float limit = -9.0f; // Origin position.x - 2.0f - float posX = - MeshRenderer::getInstance("topTriangle")->mTransform.translation().x(); - if (posX < limit || posX > limit + 4.0f) { - translateX = -translateX; - } - MeshRenderer::getInstance("topTriangle")->mTransform.translate( - translateX, 0.0f, 0.0f); - MeshRenderer::getInstance("bottomTriangle")->mTransform.translate( - -translateX, 0.0f, 0.0f); - // And lets rotate the triangles in two directions at once - MeshRenderer::getInstance("topTriangle")->mTransform.rotate( - 0.75f, 0.2f, 0.0f, 0.4f); - MeshRenderer::getInstance("bottomTriangle")->mTransform.rotate( - 0.75f, 0.0f, 0.2f, 0.4f); - // And make the bottom triangle green, instead of RGB - - // Rotate center cube in several directions simultaneously - // + Not subject to gimbal lock since we are using quaternions :) - MeshRenderer::getInstance("centerCube")->mTransform.rotate( - 0.75f, 0.2f, 0.4f, 0.6f); - + mScene->update(); QWidget::update(); } @@ -1034,31 +323,31 @@ void MainWidget::updateCameraInput() static const float rotSpeed = 0.5f; // Handle rotations - mCamera.transform().rotate(-rotSpeed * Input::mouseDelta().x(), + Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp); - mCamera.transform().rotate(-rotSpeed * Input::mouseDelta().y(), - mCamera.right()); + Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().y(), + Scene::Camera().right()); // Handle translations QVector3D translation; if (Input::keyPressed(Qt::Key_W)) { - translation += mCamera.forward(); + translation += Scene::Camera().forward(); } if (Input::keyPressed(Qt::Key_S)) { - translation -= mCamera.forward(); + translation -= Scene::Camera().forward(); } if (Input::keyPressed(Qt::Key_A)) { - translation -= mCamera.right(); + translation -= Scene::Camera().right(); } if (Input::keyPressed(Qt::Key_D)) { - translation += mCamera.right(); + translation += Scene::Camera().right(); } if (Input::keyPressed(Qt::Key_Q)) { - translation -= mCamera.up() / 2.0f; + translation -= Scene::Camera().up() / 2.0f; } if (Input::keyPressed(Qt::Key_E)) { - translation += mCamera.up() / 2.0f; + translation += Scene::Camera().up() / 2.0f; } - mCamera.transform().translate(transSpeed * translation); + Scene::Camera().transform().translate(transSpeed * translation); } } diff --git a/lib/mainwidget.h b/lib/mainwidget.h index 335013a..7a34360 100644 --- a/lib/mainwidget.h +++ b/lib/mainwidget.h @@ -15,13 +15,12 @@ #include #include -#include - #define QTK_DEBUG class MeshRenderer; class Model; class Object; +class Scene; class Skybox; class Texture; @@ -35,10 +34,6 @@ public: explicit MainWidget(const QSurfaceFormat &format); ~MainWidget() override; - // Static Members - static inline QMatrix4x4 &Projection() { return mProjection;} - static inline Camera3D &Camera() { return mCamera;} - private: void teardownGL(); void initObjects(); @@ -65,18 +60,8 @@ private: void printContextInformation(); void updateCameraInput(); - // Private Members - static Camera3D mCamera; - static QMatrix4x4 mProjection; - - Skybox * mSkybox; + Scene * mScene; Object * mObject; - MeshRenderer * mTestPhong; - MeshRenderer * mTestSpecular; - MeshRenderer * mTestDiffuse; - MeshRenderer * mTestAmbient; - std::vector mMeshes; - std::vector mModels; QOpenGLDebugLogger * mDebugLogger; }; diff --git a/lib/meshrenderer.cpp b/lib/meshrenderer.cpp index d56dd6f..25a6ce3 100644 --- a/lib/meshrenderer.cpp +++ b/lib/meshrenderer.cpp @@ -8,7 +8,7 @@ #include -#include +#include #include #include @@ -129,8 +129,8 @@ void MeshRenderer::setShaders(const std::string & vert, const std::string & frag void MeshRenderer::setUniformMVP(const char * model, const char * view, const char * projection) { - mProgram.setUniformValue(projection, MainWidget::Projection()); - mProgram.setUniformValue(view, MainWidget::Camera().toMatrix()); + mProgram.setUniformValue(projection, Scene::Projection()); + mProgram.setUniformValue(view, Scene::View()); mProgram.setUniformValue(model, mTransform.toMatrix()); } diff --git a/lib/model.cpp b/lib/model.cpp index 3bf922d..54258c1 100644 --- a/lib/model.cpp +++ b/lib/model.cpp @@ -9,7 +9,7 @@ #include -#include +#include #include #include @@ -105,8 +105,8 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader) // Set Model View Projection values shader.setUniformValue("uModel", mTransform.toMatrix()); - shader.setUniformValue("uView", MainWidget::Camera().toMatrix()); - shader.setUniformValue("uProjection", MainWidget::Projection()); + shader.setUniformValue("uView", Scene::View()); + shader.setUniformValue("uProjection", Scene::Projection()); GLuint diffuseCount = 1; GLuint specularCount = 1; @@ -389,7 +389,7 @@ ModelMesh::Textures Model::loadMaterialTextures( void Model::sortModels() { - auto cameraPos = MainWidget::Camera().transform(); + auto cameraPos = Scene::Camera().transform(); auto cameraDistance = [&cameraPos](const ModelMesh &a, const ModelMesh &b) { // Sort by the first vertex position, since all transforms will be the same diff --git a/lib/scene.cpp b/lib/scene.cpp new file mode 100644 index 0000000..97ecfee --- /dev/null +++ b/lib/scene.cpp @@ -0,0 +1,759 @@ +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ## +## About: Classes for managing objects and data within a scene ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +##############################################################################*/ + +#include +#include +#include +#include + +#include + + +Camera3D Scene::mCamera; +QMatrix4x4 Scene::mProjection; + + +/******************************************************************************* + * Constructors, Destructors + ******************************************************************************/ + +Scene::Scene() +{ + init(); +} + +Scene::~Scene() +{ + delete mTestPhong; + delete mTestSpecular; + delete mTestDiffuse; + delete mTestAmbient; + for (auto & mesh : mMeshes) delete mesh; + for (auto & model : mModels) delete model; +} + + +/******************************************************************************* + * Public Member Functions + ******************************************************************************/ + +void Scene::init() +{ + mCamera.transform().setTranslation(0.0f, 0.0f, 5.0f); + mCamera.transform().setRotation(180.0f, 0.0f, 1.0f, 0.0f); + + + // Initialize Phong example cube + mTestPhong = new MeshRenderer("phong", Cube()); + mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f); + mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag"); + mTestPhong->init(); + mTestPhong->mProgram.bind(); + mTestPhong->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); + mTestPhong->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); + mTestPhong->setUniform("uAmbientStrength", 0.2f); + mTestPhong->setUniform("uSpecularStrength", 0.50f); + mTestPhong->setUniform("uSpecularShine", 256); + + mTestPhong->mVAO.bind(); + mTestPhong->mNBO.create(); + mTestPhong->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); + mTestPhong->mNBO.bind(); + mTestPhong->mNBO.allocate(mTestPhong->normals().data(), + mTestPhong->normals().size() + * sizeof(mTestPhong->normals()[0])); + mTestPhong->mProgram.enableAttributeArray(1); + mTestPhong->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + mTestPhong->mNBO.release(); + mTestPhong->mVAO.release(); + mTestPhong->mProgram.release(); + + + // Initialize Ambient example cube + mTestAmbient = new MeshRenderer("ambient", Cube()); + mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f); + mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag"); + mTestAmbient->init(); + mTestAmbient->mProgram.bind(); + mTestAmbient->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); + mTestAmbient->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); + mTestAmbient->setUniform("uAmbientStrength", 0.2f); + + mTestAmbient->mVAO.bind(); + mTestAmbient->mNBO.create(); + mTestAmbient->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); + mTestAmbient->mNBO.bind(); + mTestAmbient->mNBO.allocate(mTestAmbient->normals().data(), + mTestAmbient->normals().size() + * sizeof(mTestAmbient->normals()[0])); + mTestAmbient->mProgram.enableAttributeArray(1); + mTestAmbient->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + mTestAmbient->mNBO.release(); + mTestAmbient->mVAO.release(); + mTestAmbient->mProgram.release(); + + // Initialize Diffuse example cube + mTestDiffuse = new MeshRenderer("diffuse", Cube()); + mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f); + mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag"); + mTestDiffuse->init(); + mTestDiffuse->mProgram.bind(); + mTestDiffuse->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); + mTestDiffuse->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); + mTestDiffuse->setUniform("uAmbientStrength", 0.2f); + + mTestDiffuse->mVAO.bind(); + mTestDiffuse->mNBO.create(); + mTestDiffuse->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); + mTestDiffuse->mNBO.bind(); + mTestDiffuse->mNBO.allocate(mTestDiffuse->normals().data(), + mTestDiffuse->normals().size() + * sizeof(mTestDiffuse->normals()[0])); + mTestDiffuse->mProgram.enableAttributeArray(1); + mTestDiffuse->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + mTestDiffuse->mNBO.release(); + mTestDiffuse->mVAO.release(); + mTestDiffuse->mProgram.release(); + + // Initialize Specular example cube + mTestSpecular = new MeshRenderer("specular", Cube()); + mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f); + mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag"); + mTestSpecular->init(); + mTestSpecular->mProgram.bind(); + mTestSpecular->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); + mTestSpecular->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); + mTestSpecular->setUniform("uAmbientStrength", 0.2f); + mTestSpecular->setUniform("uSpecularStrength", 0.50f); + mTestSpecular->setUniform("uSpecularShine", 256); + + mTestSpecular->mVAO.bind(); + mTestSpecular->mNBO.create(); + mTestSpecular->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw); + mTestSpecular->mNBO.bind(); + mTestSpecular->mNBO.allocate(mTestSpecular->normals().data(), + mTestSpecular->normals().size() + * sizeof(mTestSpecular->normals()[0])); + mTestSpecular->mProgram.enableAttributeArray(1); + mTestSpecular->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + mTestSpecular->mNBO.release(); + mTestSpecular->mVAO.release(); + mTestSpecular->mProgram.release(); + + // + // Model loading + + mModels.push_back(new Model("backpack", + "../resources/models/backpack/backpack.obj")); + // Sometimes model textures need flipped in certain directions + mModels.back()->flipTexture("diffuse.jpg", false, true); + mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f); + + mModels.push_back( + new Model("bird", + "../resources/models/bird/bird.obj")); + mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f); + // Sometimes the models are very large + mModels.back()->mTransform.scale(0.0025f); + mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f); + + mModels.push_back(new Model("lion", + "../resources/models/lion/lion.obj")); + mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f); + mModels.back()->mTransform.scale(0.15f); + + mModels.push_back( + new Model("alien", + "../resources/models/alien-hominid/alien.obj")); + mModels.back()->mTransform.setTranslation(2.0f, -1.0f, -5.0f); + mModels.back()->mTransform.scale(0.15f); + + mModels.push_back( + new Model("scythe", + "../resources/models/scythe/scythe.obj") + ); + mModels.back()->mTransform.setTranslation(-6.0f, 0.0f, -10.0f); + mModels.back()->mTransform.rotate(-90.0f, 1.0f, 0.0f, 0.0f); + mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f); + + mModels.push_back( + new Model("masterChief", + "../resources/models/spartan/spartan.obj")); + mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f); + + + // + // Building example mesh objects + + // Render an alien with specular + // Test alien Model with phong lighting and specular mapping + mMeshes.push_back( + new MeshRenderer("alienTestLight", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f); + mMeshes.back()->mTransform.scale(0.25f); + // This function changes values we have allocated in a buffer, so init() after + mMeshes.back()->setColor(GREEN); + mMeshes.back()->init(); + + mModels.push_back( + new Model("alienTest", + "../resources/models/alien-hominid/alien.obj", + ":/model-specular.vert", ":/model-specular.frag")); + mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f); + mModels.back()->mTransform.scale(0.15f); + mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uMaterial.ambientStrength", 0.8f); + mModels.back()->setUniform("uMaterial.diffuseStrength", 0.8f); + mModels.back()->setUniform("uMaterial.specularStrength", 1.0f); + mModels.back()->setUniform("uMaterial.shine", 32.0f); + + mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f)); + + + // Test spartan Model with phong lighting, specular and normal mapping + mMeshes.push_back( + new MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(1.0f, 1.5f, 10.0f); + mMeshes.back()->mTransform.scale(0.25f); + // This function changes values we have allocated in a buffer, so init() after + mMeshes.back()->setColor(GREEN); + mMeshes.back()->init(); + + mModels.push_back( + new Model("spartanTest", + "../resources/models/spartan/spartan.obj", + ":/model-normals.vert", ":/model-normals.frag")); + mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f); + mModels.back()->mTransform.scale(2.0f); + mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uMaterial.ambientStrength", 1.0f); + mModels.back()->setUniform("uMaterial.diffuseStrength", 1.0f); + mModels.back()->setUniform("uMaterial.specularStrength", 1.0f); + mModels.back()->setUniform("uMaterial.shine", 128.0f); + mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f)); + mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f)); + + + // Test basic cube with phong.vert and phong.frag shaders + mMeshes.push_back( + new MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(5.0f, 1.25f, 10.0f); + mMeshes.back()->mTransform.scale(0.25f); + mMeshes.back()->setDrawType(GL_LINE_LOOP); + // This function changes values we have allocated in a buffer, so init() after + mMeshes.back()->setColor(GREEN); + mMeshes.back()->init(); + + mMeshes.push_back( + new MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS))); + mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 10.0f); + mMeshes.back()->setShaders(":/phong.vert", ":/phong.frag"); + mMeshes.back()->setColor(QVector3D(0.0f, 0.25f, 0.0f)); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + + mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), + mMeshes.back()->normals().size() + * sizeof(mMeshes.back()->normals()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + + mMeshes.back()->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f)); + mMeshes.back()->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f)); + + mMeshes.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f)); + mMeshes.back()->setUniform("uMaterial.ambientStrength", 1.0f); + mMeshes.back()->setUniform("uMaterial.diffuseStrength", 1.0f); + mMeshes.back()->setUniform("uMaterial.specularStrength", 1.0f); + mMeshes.back()->setUniform("uMaterial.shine", 64.0f); + mMeshes.back()->setUniform("uLight.ambient", QVector3D(0.25f, 0.2f, 0.075f)); + mMeshes.back()->setUniform("uLight.diffuse", QVector3D(0.75f, 0.6f, 0.22f)); + mMeshes.back()->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f)); + mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); + + mMeshes.back()->mProgram.release(); + + // + // Create simple shapes using MeshRenderer class and data in mesh.h + + mMeshes.push_back( + new MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(-5.0f, 0.0f, -2.0f); + + mMeshes.push_back( + new MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(-7.0f, 0.0f, -2.0f); + + mMeshes.push_back( + new MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(-9.0f, 0.0f, -2.0f); + mMeshes.back()->setDrawType(GL_LINE_LOOP); + + mMeshes.push_back( + new MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(-7.0f, 2.0f, -2.0f); + mMeshes.back()->mTransform.scale(0.25f); + + mMeshes.push_back( + new MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(-7.0f, -2.0f, -2.0f); + mMeshes.back()->mTransform.scale(0.25f); + mMeshes.back()->setDrawType(GL_LINE_LOOP); + // This function changes values we have allocated in a buffer, so init() after + mMeshes.back()->setColor(GREEN); + mMeshes.back()->init(); + + // + // Testing for normals, texture coordinates + + // RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS + mMeshes.push_back( + new MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS))); + mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 4.0f); + mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); + mMeshes.back()->init(); + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), + mMeshes.back()->normals().size() + * sizeof(mMeshes.back()->normals()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + + mMeshes.back()->mProgram.release(); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + + // RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS + mMeshes.push_back( + new MeshRenderer("rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS))); + mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 2.0f); + mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); + mMeshes.back()->init(); + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), + mMeshes.back()->normals().size() + * sizeof(mMeshes.back()->normals()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + + mMeshes.back()->mProgram.release(); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + + // Texturing a cube using texture coordinates and glDrawArrays + // + Texturing with UVs using glDrawElements requires QTK_DRAW_ELEMENTS_NORMALS + // + UVs required duplicating element position data from QTK_DRAW_ELEMENTS + // + This is because the same position must use different UV coordinates + mMeshes.push_back( + new MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS))); + mMeshes.back()->mTransform.setTranslation(-3.0f, 0.0f, -2.0f); + mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); + mMeshes.back()->setUniform("uTexture", 0); + mMeshes.back()->texture().bind(); + + mMeshes.back()->texture().release(); + + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.destroy(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), + mMeshes.back()->mShape.texCoords().size() + * sizeof(mMeshes.back()->mShape.texCoords()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 2, sizeof(QVector2D)); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + mMeshes.back()->mProgram.release(); + + // Test drawing a cube with texture coordinates using glDrawElements + mMeshes.push_back( + new MeshRenderer("uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS))); + mMeshes.back()->mTransform.setTranslation(-1.7f, 0.0f, -2.0f); + mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); + mMeshes.back()->init(); + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->mNBO.allocate(mMeshes.back()->texCoords().data(), + mMeshes.back()->texCoords().size() + * sizeof(mMeshes.back()->texCoords()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); + + mMeshes.back()->mProgram.setUniformValue("uTexture", 0); + mMeshes.back()->mProgram.release(); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + mMeshes.back()->mTransform.rotate(45.0f, 0.0f, 1.0f, 0.0f); + + // Texturing a cube using a cube map + // + Cube map texturing works with both QTK_DRAW_ARRAYS and QTK_DRAW_ELEMENTS + mMeshes.push_back( + new MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(-3.0f, 1.0f, -2.0f); + mMeshes.back()->mTransform.setRotation(45.0f, 0.0f, 1.0f, 0.0f); + mMeshes.back()->setShaders(":/texture-cubemap.vert", ":/texture-cubemap.frag"); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->setTexture(Texture::initCubeMap(":/crate.png")); + mMeshes.back()->setUniform("uTexture", 0); + + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.destroy(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), + mMeshes.back()->mShape.texCoords().size() + * sizeof(mMeshes.back()->mShape.texCoords()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 2, sizeof(QVector2D)); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + mMeshes.back()->mProgram.release(); + + // Create a cube with custom shaders + // + Apply RGB normals shader and spin the cube for a neat effect + mMeshes.push_back( + new MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS))); + mMeshes.back()->mTransform.setTranslation(5.0f, 2.0f, -2.0f); + mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); + mMeshes.back()->init(); + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), + mMeshes.back()->normals().size() + * sizeof(mMeshes.back()->normals()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + + mMeshes.back()->mProgram.release(); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + + // RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS + mMeshes.push_back( + new MeshRenderer("rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS))); + mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 2.0f); + mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), + mMeshes.back()->normals().size() + * sizeof(mMeshes.back()->normals()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + mMeshes.back()->mProgram.release(); + + // RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS + mMeshes.push_back( + new MeshRenderer("rgbTriangleElementsTest", + Triangle(QTK_DRAW_ELEMENTS_NORMALS))); + mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 4.0f); + mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag"); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(), + mMeshes.back()->normals().size() + * sizeof(mMeshes.back()->normals()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 3, sizeof(QVector3D)); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + mMeshes.back()->mProgram.release(); + + // Test drawing triangle with glDrawArrays with texture coordinates + mMeshes.push_back( + new MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS))); + mMeshes.back()->mTransform.setTranslation(-3.0f, 2.0f, -2.0f); + mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); + mMeshes.back()->setUniform("uTexture", 0); + mMeshes.back()->texture().bind(); + + mMeshes.back()->texture().release(); + + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.destroy(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), + mMeshes.back()->mShape.texCoords().size() + * sizeof(mMeshes.back()->mShape.texCoords()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 2, sizeof(QVector2D)); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + mMeshes.back()->mProgram.release(); + + // Test drawing triangle with glDrawElements with texture coordinates + mMeshes.push_back( + new MeshRenderer("testTriangleElementsUV", + Triangle(QTK_DRAW_ELEMENTS_NORMALS))); + mMeshes.back()->mTransform.setTranslation(-2.5f, 0.0f, -1.0f); + mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag"); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + + mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png")); + mMeshes.back()->setUniform("uTexture", 0); + mMeshes.back()->texture().bind(); + + mMeshes.back()->texture().release(); + + mMeshes.back()->mVAO.bind(); + mMeshes.back()->mNBO.destroy(); + mMeshes.back()->mNBO.create(); + mMeshes.back()->mNBO.bind(); + mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(), + mMeshes.back()->mShape.texCoords().size() + * sizeof(mMeshes.back()->mShape.texCoords()[0])); + mMeshes.back()->mProgram.enableAttributeArray(1); + mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, + 2, sizeof(QVector2D)); + mMeshes.back()->mNBO.release(); + mMeshes.back()->mVAO.release(); + mMeshes.back()->mProgram.release(); + + // + // Lighting cube examples + + // Example of a cube with no lighting applied + mMeshes.push_back( + new MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, -2.0f); + mMeshes.back()->setShaders(":/solid-perspective.vert", + ":/solid-perspective.frag"); + mMeshes.back()->init(); + mMeshes.back()->mProgram.bind(); + mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); + mMeshes.back()->mProgram.release(); + + // Create objects that represent light sources for lighting examples + mMeshes.push_back( + new MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(3.0f, 2.0f, -2.0f); + mMeshes.back()->mTransform.scale(0.25f); + + mMeshes.push_back( + new MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(9.0f, 2.0f, -2.0f); + mMeshes.back()->mTransform.scale(0.25f); + + mMeshes.push_back( + new MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS))); + mMeshes.back()->mTransform.setTranslation(11.0f, 2.0f, -2.0f); + mMeshes.back()->mTransform.scale(0.25f); +} + +void Scene::draw() +{ + mSkybox.draw(); + + for (auto & model : mModels) model->draw(); + + for (const auto &mesh : mMeshes) mesh->draw(); + + mTestPhong->mProgram.bind(); + mTestPhong->setUniform("uModelInverseTransposed", + mTestPhong->mTransform.toMatrix().normalMatrix()); + mTestPhong->setUniform( + "uLightPosition", + MeshRenderer::getInstance("phongLight")->mTransform.translation()); + mTestPhong->setUniform("uCameraPosition", + Scene::Camera().transform().translation()); + mTestPhong->mProgram.release(); + mTestPhong->draw(); + + mTestAmbient->mProgram.bind(); + mTestAmbient->setUniform("uCameraPosition", + Scene::Camera().transform().translation()); + mTestAmbient->mProgram.release(); + mTestAmbient->draw(); + + mTestDiffuse->mProgram.bind(); + mTestDiffuse->setUniform("uModelInverseTransposed", + mTestDiffuse->mTransform.toMatrix().normalMatrix()); + mTestDiffuse->setUniform( + "uLightPosition", + MeshRenderer::getInstance("diffuseLight")->mTransform.translation()); + mTestDiffuse->setUniform("uCameraPosition", Scene::Camera().transform().translation()); + mTestDiffuse->mProgram.release(); + mTestDiffuse->draw(); + + mTestSpecular->mProgram.bind(); + mTestSpecular->setUniform( + "uModelInverseTransposed", + mTestSpecular->mTransform.toMatrix().normalMatrix()); + mTestSpecular->setUniform( + "uLightPosition", + MeshRenderer::getInstance("specularLight")->mTransform.translation()); + mTestSpecular->setUniform("uCameraPosition", Scene::Camera().transform().translation()); + mTestSpecular->mProgram.release(); + mTestSpecular->draw(); +} + +void Scene::update() +{ + auto position = MeshRenderer::getInstance("alienTestLight")->mTransform.translation(); + Model::getInstance("alienTest")->setUniform( + "uLight.position", position); + Model::getInstance("alienTest")->setUniform( + "uCameraPosition", Scene::Camera().transform().translation()); + auto posMatrix = Model::getInstance("alienTest")->mTransform.toMatrix(); + Model::getInstance("alienTest")->setUniform( + "uMVP.normalMatrix", posMatrix.normalMatrix()); + Model::getInstance("alienTest")->setUniform( + "uMVP.model", posMatrix); + Model::getInstance("alienTest")->setUniform( + "uMVP.view", Scene::Camera().toMatrix()); + Model::getInstance("alienTest")->setUniform( + "uMVP.projection", Scene::Projection()); + Model::getInstance("alienTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f); + + position = MeshRenderer::getInstance("spartanTestLight")->mTransform.translation(); + Model::getInstance("spartanTest")->setUniform( + "uLight.position", position); + Model::getInstance("spartanTest")->setUniform( + "uCameraPosition", Scene::Camera().transform().translation()); + posMatrix = Model::getInstance("spartanTest")->mTransform.toMatrix(); + Model::getInstance("spartanTest")->setUniform( + "uMVP.normalMatrix", posMatrix.normalMatrix()); + Model::getInstance("spartanTest")->setUniform( + "uMVP.model", posMatrix); + Model::getInstance("spartanTest")->setUniform( + "uMVP.view", Scene::Camera().toMatrix()); + Model::getInstance("spartanTest")->setUniform( + "uMVP.projection", Scene::Projection()); + Model::getInstance("spartanTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f); + + + + MeshRenderer::getInstance("testPhong")->mTransform.rotate( + 0.75f, 1.0f, 0.5f, 0.0f); + MeshRenderer::getInstance("testPhong")->mProgram.bind(); + position = MeshRenderer::getInstance("testLight")->mTransform.translation(); + MeshRenderer::getInstance("testPhong")->setUniform( + "uLight.position", position); + MeshRenderer::getInstance("testPhong")->setUniform( + "uCameraPosition", Scene::Camera().transform().translation()); + posMatrix = MeshRenderer::getInstance("testPhong")->mTransform.toMatrix(); + MeshRenderer::getInstance("testPhong")->setUniform( + "uMVP.normalMatrix", posMatrix.normalMatrix()); + MeshRenderer::getInstance("testPhong")->setUniform( + "uMVP.model", posMatrix); + MeshRenderer::getInstance("testPhong")->setUniform( + "uMVP.view", Scene::Camera().toMatrix()); + MeshRenderer::getInstance("testPhong")->setUniform( + "uMVP.projection", Scene::Projection()); + MeshRenderer::getInstance("testPhong")->mProgram.release(); + + // Rotate lighting example cubes + mTestPhong->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); + MeshRenderer::getInstance("noLight")->mTransform.rotate( + 0.75f, 0.5f, 0.3f, 0.2f); + mTestAmbient->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); + mTestDiffuse->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); + mTestSpecular->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f); + + // Examples of various translations and rotations + + // Rotate in multiple directions simultaneously + MeshRenderer::getInstance("rgbNormalsCube")->mTransform.rotate( + 0.75f, 0.2f, 0.4f, 0.6f); + + // Pitch forward and roll sideways + MeshRenderer::getInstance("leftTriangle")->mTransform.rotate( + 0.75f, 1.0f, 0.0f, 0.0f); + MeshRenderer::getInstance("rightTriangle")->mTransform.rotate( + 0.75f, 0.0f, 0.0f, 1.0f); + + // Move between two positions over time + static float translateX = 0.025f; + float limit = -9.0f; // Origin position.x - 2.0f + float posX = + MeshRenderer::getInstance("topTriangle")->mTransform.translation().x(); + if (posX < limit || posX > limit + 4.0f) { + translateX = -translateX; + } + MeshRenderer::getInstance("topTriangle")->mTransform.translate( + translateX, 0.0f, 0.0f); + MeshRenderer::getInstance("bottomTriangle")->mTransform.translate( + -translateX, 0.0f, 0.0f); + // And lets rotate the triangles in two directions at once + MeshRenderer::getInstance("topTriangle")->mTransform.rotate( + 0.75f, 0.2f, 0.0f, 0.4f); + MeshRenderer::getInstance("bottomTriangle")->mTransform.rotate( + 0.75f, 0.0f, 0.2f, 0.4f); + // And make the bottom triangle green, instead of RGB + + // Rotate center cube in several directions simultaneously + // + Not subject to gimbal lock since we are using quaternions :) + MeshRenderer::getInstance("centerCube")->mTransform.rotate( + 0.75f, 0.2f, 0.4f, 0.6f); +} diff --git a/lib/scene.h b/lib/scene.h new file mode 100644 index 0000000..e4c6b0d --- /dev/null +++ b/lib/scene.h @@ -0,0 +1,45 @@ +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ## +## About: Classes for managing objects and data within a scene ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +##############################################################################*/ + +#ifndef QTK_SCENE_H +#define QTK_SCENE_H + +#include +#include + +#include + +class MeshRenderer; +class Model; + +class Scene { +public: + Scene(); + ~Scene(); + + void init(); + void draw(); + void update(); + + static Camera3D & Camera() { return mCamera;} + static QMatrix4x4 View() { return mCamera.toMatrix();} + static QMatrix4x4 & Projection() { return mProjection;} +private: + static Camera3D mCamera; + static QMatrix4x4 mProjection; + + Skybox mSkybox; + MeshRenderer * mTestPhong; + MeshRenderer * mTestSpecular; + MeshRenderer * mTestDiffuse; + MeshRenderer * mTestAmbient; + std::vector mMeshes; + std::vector mModels; +}; + +#endif // QTK_SCENE_H diff --git a/lib/skybox.cpp b/lib/skybox.cpp index b8b48fd..322a679 100644 --- a/lib/skybox.cpp +++ b/lib/skybox.cpp @@ -6,6 +6,7 @@ ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ +#include #include #include @@ -46,8 +47,8 @@ void Skybox::draw() mProgram.bind(); mCubeMap->bind(); - mProgram.setUniformValue("uProjectionMatrix", MainWidget::Projection()); - mProgram.setUniformValue("uViewMatrix", MainWidget::Camera().toMatrix()); + mProgram.setUniformValue("uProjectionMatrix", Scene::Projection()); + mProgram.setUniformValue("uViewMatrix", Scene::Camera().toMatrix()); mProgram.setUniformValue("uTexture", 0); glDrawElements(GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data()); diff --git a/lib/skybox.h b/lib/skybox.h index e91ecca..8a67a3d 100644 --- a/lib/skybox.h +++ b/lib/skybox.h @@ -15,7 +15,6 @@ #include #include -#include #include