diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index 8214574e..2627cd7b 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -75,9 +75,9 @@ public: } protected: - void initialize() override + void initializeExample() override { - //Create an empty volume and then place a sphere in it + // Create an empty volume and then place a sphere in it PagedVolume volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63))); createSphereInVolume(volData, 30); diff --git a/examples/DecodeOnGPU/main.cpp b/examples/DecodeOnGPU/main.cpp index 393d37fa..158bcfec 100644 --- a/examples/DecodeOnGPU/main.cpp +++ b/examples/DecodeOnGPU/main.cpp @@ -75,7 +75,7 @@ public: } protected: - void initialize() override + void initializeExample() override { QSharedPointer shader(new QGLShaderProgram); diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index ce0fbfa3..e39249f0 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -56,7 +56,7 @@ public: } protected: - void initialize() override + void initializeExample() override { FilePager* pager = new FilePager("."); PagedVolume volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(g_uVolumeSideLength - 1, g_uVolumeSideLength - 1, g_uVolumeSideLength - 1)), pager); diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 012fb9d0..415a466d 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -148,7 +148,7 @@ public: } protected: - void initialize() override + void initializeExample() override { PerlinNoisePager* pager = new PerlinNoisePager(); PagedVolume volData(PolyVox::Region::MaxRegion(), pager, 64); diff --git a/examples/SmoothLOD/main.cpp b/examples/SmoothLOD/main.cpp index b6888334..57cfcd90 100644 --- a/examples/SmoothLOD/main.cpp +++ b/examples/SmoothLOD/main.cpp @@ -77,7 +77,7 @@ public: } protected: - void initialize() override + void initializeExample() override { //Create an empty volume and then place a sphere in it PagedVolume volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63))); diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.cpp index 7f583237..50056934 100644 --- a/examples/common/OpenGLWidget.cpp +++ b/examples/common/OpenGLWidget.cpp @@ -17,11 +17,6 @@ OpenGLWidget::OpenGLWidget(QWidget *parent) { } -void OpenGLWidget::setShader(QSharedPointer shader) -{ - mShader = shader; -} - void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw) { mCameraPosition = position; @@ -92,38 +87,6 @@ void OpenGLWidget::initializeGL() glDepthFunc(GL_LEQUAL); glDepthRange(0.0, 1.0); - mShader = QSharedPointer(new QGLShaderProgram); - - // This is basically a simple fallback vertex shader which does the most basic rendering possible. - // PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired. - if (!mShader->addShaderFromSourceFile(QGLShader::Vertex, ":/example.vert")) - { - std::cerr << mShader->log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - - // This is basically a simple fallback fragment shader which does the most basic rendering possible. - // PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired. - if (!mShader->addShaderFromSourceFile(QGLShader::Fragment, ":/example.frag")) - { - std::cerr << mShader->log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - - // Bind the position semantic - this is defined in the vertex shader above. - mShader->bindAttributeLocation("position", 0); - - // Bind the other semantics. Note that these don't actually exist in our example shader above! However, other - // example shaders may choose to provide them and having the binding code here does not seem to cause any problems. - mShader->bindAttributeLocation("normal", 1); - mShader->bindAttributeLocation("material", 2); - - if (!mShader->link()) - { - std::cerr << mShader->log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - initialize(); // Start a timer to drive the main rendering loop. @@ -190,21 +153,6 @@ void OpenGLWidget::paintGL() { mCameraPosition -= cameraRight * deltaTime * mCameraMoveSpeed; } - // Move backward - /*if ((glfwGetKey(mWindow, GLFW_KEY_DOWN) == GLFW_PRESS) || (glfwGetKey(mWindow, GLFW_KEY_S) == GLFW_PRESS)) - { - mCameraPosition -= cameraForward * deltaTime * mCameraMoveSpeed; - } - // Strafe right - if ((glfwGetKey(mWindow, GLFW_KEY_RIGHT) == GLFW_PRESS) || (glfwGetKey(mWindow, GLFW_KEY_D) == GLFW_PRESS)) - { - mCameraPosition += cameraRight * deltaTime * mCameraMoveSpeed; - } - // Strafe left - if ((glfwGetKey(mWindow, GLFW_KEY_LEFT) == GLFW_PRESS) || (glfwGetKey(mWindow, GLFW_KEY_A) == GLFW_PRESS)) - { - mCameraPosition -= cameraRight * deltaTime * mCameraMoveSpeed; - }*/ worldToCameraMatrix.setToIdentity(); worldToCameraMatrix.lookAt( @@ -216,32 +164,7 @@ void OpenGLWidget::paintGL() //Clear the screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Our example framework only uses a single shader for the scene (for all meshes). - mShader->bind(); - - // These two matrices are constant for all meshes. - mShader->setUniformValue("worldToCameraMatrix", worldToCameraMatrix); - mShader->setUniformValue("cameraToClipMatrix", cameraToClipMatrix); - - // Iterate over each mesh which the user added to our list, and render it. - for (OpenGLMeshData meshData : mMeshData) - { - //Set up the model matrrix based on provided translation and scale. - QMatrix4x4 modelToWorldMatrix; - modelToWorldMatrix.translate(meshData.translation); - modelToWorldMatrix.scale(meshData.scale); - mShader->setUniformValue("modelToWorldMatrix", modelToWorldMatrix); - - // Bind the vertex array for the current mesh - glBindVertexArray(meshData.vertexArrayObject); - // Draw the mesh - glDrawElements(GL_TRIANGLES, meshData.noOfIndices, meshData.indexType, 0); - // Unbind the vertex array. - glBindVertexArray(0); - } - - // We're done with the shader for this frame. - mShader->release(); + renderOneFrame(); // Check for errors. GLenum errCode = glGetError(); diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h index 16362a40..bd783849 100644 --- a/examples/common/OpenGLWidget.h +++ b/examples/common/OpenGLWidget.h @@ -34,19 +34,6 @@ distribution. #include #include -// This structure holds all the data required -// to render one of our meshes through OpenGL. -struct OpenGLMeshData -{ - GLuint noOfIndices; - GLenum indexType; - GLuint indexBuffer; - GLuint vertexBuffer; - GLuint vertexArrayObject; - QVector3D translation; - float scale; -}; - // Our OpenGLWidget is used by all the examples to render the extracted meshes. It is // fairly specific to our needs (you probably won't want to use it in your own project) // but should provide a useful illustration of how PolyVox meshes can be rendered. @@ -56,73 +43,6 @@ public: // Constructor OpenGLWidget(QWidget *parent); - // Convert a PolyVox mesh to OpenGL index/vertex buffers. Inlined because it's templatised. - template - void addMesh(const MeshType& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f) - { - // Convienient access to the vertices and indices - const auto& vecIndices = surfaceMesh.getIndices(); - const auto& vecVertices = surfaceMesh.getVertices(); - - // This struct holds the OpenGL properties (buffer handles, etc) which will be used - // to render our mesh. We copy the data from the PolyVox mesh into this structure. - OpenGLMeshData meshData; - - // Create the VAO for the mesh - glGenVertexArrays(1, &(meshData.vertexArrayObject)); - glBindVertexArray(meshData.vertexArrayObject); - - // The GL_ARRAY_BUFFER will contain the list of vertex positions - glGenBuffers(1, &(meshData.vertexBuffer)); - glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer); - glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(typename MeshType::VertexType), vecVertices.data(), GL_STATIC_DRAW); - - // and GL_ELEMENT_ARRAY_BUFFER will contain the indices - glGenBuffers(1, &(meshData.indexBuffer)); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(typename MeshType::IndexType), vecIndices.data(), GL_STATIC_DRAW); - - // Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out - glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, position))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type) - - // Some surface extractors also generate normals, so tell OpenGL how these are laid out. If a surface extractor - // does not generate normals then nonsense values are written into the buffer here and sghould be ignored by the - // shader. This is mostly just to simplify this example code - in a real application you will know whether your - // chosen surface extractor generates normals and can skip uploading them if not. - glEnableVertexAttribArray(1); // Attrib '1' is the vertex normals. - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, normal))); - - // Finally a surface extractor will probably output additional data. This is highly application dependant. For this example code - // we're just uploading it as a set of bytes which we can read individually, but real code will want to do something specialised here. - glEnableVertexAttribArray(2); //We're talking about shader attribute '2' - GLint size = (std::min)(sizeof(typename MeshType::VertexType::DataType), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type) - glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, data))); - - // We're done uploading and can now unbind. - glBindVertexArray(0); - - // A few additional properties can be copied across for use during rendering. - meshData.noOfIndices = vecIndices.size(); - meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ()); - meshData.scale = scale; - - // Set 16 or 32-bit index buffer size. - meshData.indexType = sizeof(typename MeshType::IndexType) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; - - // Now add the mesh to the list of meshes to render. - addMeshData(meshData); - } - - void addMeshData(OpenGLMeshData meshData) - { - mMeshData.push_back(meshData); - } - - // For our purposes we use a single shader for the whole volume, and - // this example framework is only meant to show a single volume at a time - void setShader(QSharedPointer shader); - void setCameraTransform(QVector3D position, float pitch, float yaw); // Mouse handling @@ -135,22 +55,15 @@ public: protected: - const float PI = 3.14159265358979f; - // Qt OpenGL functions void initializeGL(); void resizeGL(int w, int h); void paintGL(); - virtual void initialize() - { - } + virtual void initialize() {} + virtual void renderOneFrame() {} -private: - // Index/vertex buffer data - std::vector mMeshData; - - QSharedPointer mShader; +protected: // Matrices QMatrix4x4 worldToCameraMatrix; diff --git a/examples/common/PolyVoxExample.cpp b/examples/common/PolyVoxExample.cpp index 5dc86fd9..064d5b64 100644 --- a/examples/common/PolyVoxExample.cpp +++ b/examples/common/PolyVoxExample.cpp @@ -1 +1,6 @@ #include "PolyVoxExample.h" + +void PolyVoxExample::setShader(QSharedPointer shader) +{ + mShader = shader; +} \ No newline at end of file diff --git a/examples/common/PolyVoxExample.h b/examples/common/PolyVoxExample.h index ee7231b2..cfbe39b9 100644 --- a/examples/common/PolyVoxExample.h +++ b/examples/common/PolyVoxExample.h @@ -26,6 +26,19 @@ distribution. #include "OpenGLWidget.h" +// This structure holds all the data required +// to render one of our meshes through OpenGL. +struct OpenGLMeshData +{ + GLuint noOfIndices; + GLenum indexType; + GLuint indexBuffer; + GLuint vertexBuffer; + GLuint vertexArrayObject; + QVector3D translation; + float scale; +}; + class PolyVoxExample : public OpenGLWidget { public: @@ -33,6 +46,152 @@ public: :OpenGLWidget(parent) { } + + // For our purposes we use a single shader for the whole volume, and + // this example framework is only meant to show a single volume at a time + void setShader(QSharedPointer shader); + + // Convert a PolyVox mesh to OpenGL index/vertex buffers. Inlined because it's templatised. + template + void addMesh(const MeshType& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f) + { + // Convienient access to the vertices and indices + const auto& vecIndices = surfaceMesh.getIndices(); + const auto& vecVertices = surfaceMesh.getVertices(); + + // This struct holds the OpenGL properties (buffer handles, etc) which will be used + // to render our mesh. We copy the data from the PolyVox mesh into this structure. + OpenGLMeshData meshData; + + // Create the VAO for the mesh + glGenVertexArrays(1, &(meshData.vertexArrayObject)); + glBindVertexArray(meshData.vertexArrayObject); + + // The GL_ARRAY_BUFFER will contain the list of vertex positions + glGenBuffers(1, &(meshData.vertexBuffer)); + glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(typename MeshType::VertexType), vecVertices.data(), GL_STATIC_DRAW); + + // and GL_ELEMENT_ARRAY_BUFFER will contain the indices + glGenBuffers(1, &(meshData.indexBuffer)); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(typename MeshType::IndexType), vecIndices.data(), GL_STATIC_DRAW); + + // Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out + glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, position))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type) + + // Some surface extractors also generate normals, so tell OpenGL how these are laid out. If a surface extractor + // does not generate normals then nonsense values are written into the buffer here and sghould be ignored by the + // shader. This is mostly just to simplify this example code - in a real application you will know whether your + // chosen surface extractor generates normals and can skip uploading them if not. + glEnableVertexAttribArray(1); // Attrib '1' is the vertex normals. + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, normal))); + + // Finally a surface extractor will probably output additional data. This is highly application dependant. For this example code + // we're just uploading it as a set of bytes which we can read individually, but real code will want to do something specialised here. + glEnableVertexAttribArray(2); //We're talking about shader attribute '2' + GLint size = (std::min)(sizeof(typename MeshType::VertexType::DataType), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type) + glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, data))); + + // We're done uploading and can now unbind. + glBindVertexArray(0); + + // A few additional properties can be copied across for use during rendering. + meshData.noOfIndices = vecIndices.size(); + meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ()); + meshData.scale = scale; + + // Set 16 or 32-bit index buffer size. + meshData.indexType = sizeof(typename MeshType::IndexType) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; + + // Now add the mesh to the list of meshes to render. + addMeshData(meshData); + } + + void addMeshData(OpenGLMeshData meshData) + { + mMeshData.push_back(meshData); + } + +protected: + const float PI = 3.14159265358979f; + + virtual void initializeExample() {}; + + void initialize() override + { + mShader = QSharedPointer(new QGLShaderProgram); + + // This is basically a simple fallback vertex shader which does the most basic rendering possible. + // PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired. + if (!mShader->addShaderFromSourceFile(QGLShader::Vertex, ":/example.vert")) + { + std::cerr << mShader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + // This is basically a simple fallback fragment shader which does the most basic rendering possible. + // PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired. + if (!mShader->addShaderFromSourceFile(QGLShader::Fragment, ":/example.frag")) + { + std::cerr << mShader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + // Bind the position semantic - this is defined in the vertex shader above. + mShader->bindAttributeLocation("position", 0); + + // Bind the other semantics. Note that these don't actually exist in our example shader above! However, other + // example shaders may choose to provide them and having the binding code here does not seem to cause any problems. + mShader->bindAttributeLocation("normal", 1); + mShader->bindAttributeLocation("material", 2); + + if (!mShader->link()) + { + std::cerr << mShader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + // Now do any initialization for the specific example. + initializeExample(); + } + + void renderOneFrame() override + { + // Our example framework only uses a single shader for the scene (for all meshes). + mShader->bind(); + + // These two matrices are constant for all meshes. + mShader->setUniformValue("worldToCameraMatrix", worldToCameraMatrix); + mShader->setUniformValue("cameraToClipMatrix", cameraToClipMatrix); + + // Iterate over each mesh which the user added to our list, and render it. + for (OpenGLMeshData meshData : mMeshData) + { + //Set up the model matrrix based on provided translation and scale. + QMatrix4x4 modelToWorldMatrix; + modelToWorldMatrix.translate(meshData.translation); + modelToWorldMatrix.scale(meshData.scale); + mShader->setUniformValue("modelToWorldMatrix", modelToWorldMatrix); + + // Bind the vertex array for the current mesh + glBindVertexArray(meshData.vertexArrayObject); + // Draw the mesh + glDrawElements(GL_TRIANGLES, meshData.noOfIndices, meshData.indexType, 0); + // Unbind the vertex array. + glBindVertexArray(0); + } + + // We're done with the shader for this frame. + mShader->release(); + } + +private: + // Index/vertex buffer data + std::vector mMeshData; + + QSharedPointer mShader; }; #endif //__PolyVoxExample_H__ \ No newline at end of file