From 3f849e19a45642b8be2fe899c65582aa11650f16 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 15 Feb 2015 12:03:31 +0100 Subject: [PATCH 1/8] Started refactoring examples and got DecodeOnGPUExample working. --- CMakeLists.txt | 2 +- examples/Basic/main.cpp | 28 ++++++++--- examples/DecodeOnGPU/main.cpp | 85 +++++++++++++++++++------------- examples/common/OpenGLWidget.cpp | 2 + examples/common/OpenGLWidget.h | 4 ++ 5 files changed, 78 insertions(+), 43 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05c35799..6194898e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,7 @@ IF(ENABLE_EXAMPLES AND Qt5OpenGL_FOUND) ADD_SUBDIRECTORY(examples/Paging) ADD_SUBDIRECTORY(examples/OpenGL) ADD_SUBDIRECTORY(examples/SmoothLOD) - #ADD_SUBDIRECTORY(examples/DecodeOnGPU) + ADD_SUBDIRECTORY(examples/DecodeOnGPU) ADD_SUBDIRECTORY(examples/Python) SET(BUILD_EXAMPLES ON) ELSE() diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index 3fba8964..f8207e4c 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -66,13 +66,18 @@ void createSphereInVolume(PagedVolume& volData, float fRadius) } } -int main(int argc, char *argv[]) +class BasicExample : public OpenGLWidget { - //Create and show the Qt OpenGL window - QApplication app(argc, argv); - OpenGLWidget openGLWidget(0); - openGLWidget.show(); +public: + BasicExample(QWidget *parent) + :OpenGLWidget(parent) + { + } + +protected: + void initialize() override + { //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); @@ -86,9 +91,18 @@ int main(int argc, char *argv[]) auto decodedMesh = decodeMesh(mesh); //Pass the surface to the OpenGL window - openGLWidget.addMesh(decodedMesh); + addMesh(decodedMesh); //openGLWidget.addMesh(mesh2); - openGLWidget.setViewableRegion(volData.getEnclosingRegion()); + setViewableRegion(volData.getEnclosingRegion()); + } +}; + +int main(int argc, char *argv[]) +{ + //Create and show the Qt OpenGL window + QApplication app(argc, argv); + BasicExample openGLWidget(0); + openGLWidget.show(); //Run the message pump. return app.exec(); diff --git a/examples/DecodeOnGPU/main.cpp b/examples/DecodeOnGPU/main.cpp index 52091119..0ce9a2ac 100644 --- a/examples/DecodeOnGPU/main.cpp +++ b/examples/DecodeOnGPU/main.cpp @@ -66,6 +66,54 @@ void createSphereInVolume(PagedVolume& volData, float fRadius) } } +class DecodeOnGPUExample : public OpenGLWidget +{ +public: + DecodeOnGPUExample(QWidget *parent) + :OpenGLWidget(parent) + { + + } + +protected: + void initialize() override + { + QSharedPointer shader(new QGLShaderProgram); + + if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/decode.vert")) + { + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/decode.frag")) + { + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + setShader(shader); + + //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); + + // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. + //auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion()); + auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion()); + + // The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to + // decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code. + //auto decodedMesh = decodeMesh(mesh); + + //Pass the surface to the OpenGL window + OpenGLMeshData meshData = buildOpenGLMeshData(mesh); + addMeshData(meshData); + + setViewableRegion(volData.getEnclosingRegion()); + } + +private: OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f) { // Convienient access to the vertices and indices @@ -120,48 +168,15 @@ OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVe return meshData; } +}; int main(int argc, char *argv[]) { //Create and show the Qt OpenGL window QApplication app(argc, argv); - OpenGLWidget openGLWidget(0); + DecodeOnGPUExample openGLWidget(0); openGLWidget.show(); - QSharedPointer shader(new QGLShaderProgram); - - if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/decode.vert")) - { - std::cerr << shader->log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - - if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/decode.frag")) - { - std::cerr << shader->log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - - openGLWidget.setShader(shader); - - //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); - - // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. - //auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion()); - auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion()); - - // The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to - // decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code. - //auto decodedMesh = decodeMesh(mesh); - - //Pass the surface to the OpenGL window - OpenGLMeshData meshData = buildOpenGLMeshData(mesh); - openGLWidget.addMeshData(meshData); - - openGLWidget.setViewableRegion(volData.getEnclosingRegion()); - //Run the message pump. return app.exec(); } \ No newline at end of file diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.cpp index 61d23c57..ce774e30 100644 --- a/examples/common/OpenGLWidget.cpp +++ b/examples/common/OpenGLWidget.cpp @@ -121,6 +121,8 @@ void OpenGLWidget::initializeGL() // Initial setup of camera. setupWorldToCameraMatrix(); + + initialize(); } void OpenGLWidget::resizeGL(int w, int h) diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h index 35472003..c411c8b6 100644 --- a/examples/common/OpenGLWidget.h +++ b/examples/common/OpenGLWidget.h @@ -136,6 +136,10 @@ protected: void resizeGL(int w, int h); void paintGL(); + virtual void initialize() + { + } + private: void setupWorldToCameraMatrix(); From 565aa21799a592558612e884acb36917fa46fadb Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 20 Feb 2015 11:23:17 +0100 Subject: [PATCH 2/8] Refactoring example code. --- examples/Basic/main.cpp | 23 +++-- examples/DecodeOnGPU/main.cpp | 87 +++++++++--------- examples/OpenGL/main.cpp | 160 ++++++++++++++++++---------------- examples/Paging/main.cpp | 85 ++++++++++-------- examples/SmoothLOD/main.cpp | 75 +++++++++------- 5 files changed, 232 insertions(+), 198 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index f8207e4c..ea93bb68 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -72,27 +72,26 @@ public: BasicExample(QWidget *parent) :OpenGLWidget(parent) { - } protected: void initialize() override { - //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); + //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); - // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. - auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion()); - //auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion()); + // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. + auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion()); + //auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion()); - // The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to - // decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code. - auto decodedMesh = decodeMesh(mesh); + // The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to + // decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code. + auto decodedMesh = decodeMesh(mesh); - //Pass the surface to the OpenGL window + //Pass the surface to the OpenGL window addMesh(decodedMesh); - //openGLWidget.addMesh(mesh2); + //openGLWidget.addMesh(mesh2); setViewableRegion(volData.getEnclosingRegion()); } }; diff --git a/examples/DecodeOnGPU/main.cpp b/examples/DecodeOnGPU/main.cpp index 0ce9a2ac..eff3a5a7 100644 --- a/examples/DecodeOnGPU/main.cpp +++ b/examples/DecodeOnGPU/main.cpp @@ -72,7 +72,6 @@ public: DecodeOnGPUExample(QWidget *parent) :OpenGLWidget(parent) { - } protected: @@ -114,60 +113,60 @@ protected: } private: -OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& 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(); + OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& 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; + // 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); + // 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(MarchingCubesVertex< uint8_t >), vecVertices.data(), GL_STATIC_DRAW); + // 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(MarchingCubesVertex< uint8_t >), 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(uint32_t), vecIndices.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(uint32_t), 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 - glVertexAttribIPointer(0, 3, GL_UNSIGNED_SHORT, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, encodedPosition))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type) + // 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 + glVertexAttribIPointer(0, 3, GL_UNSIGNED_SHORT, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, encodedPosition))); //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. - glVertexAttribIPointer(1, 1, GL_UNSIGNED_SHORT, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, encodedNormal))); + // 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. + glVertexAttribIPointer(1, 1, GL_UNSIGNED_SHORT, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, encodedNormal))); - // 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(uint8_t), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type) - glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, data))); + // 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(uint8_t), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type) + glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, data))); - // We're done uploading and can now unbind. - glBindVertexArray(0); + // 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; + // 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(PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >::IndexType) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; + // Set 16 or 32-bit index buffer size. + meshData.indexType = sizeof(PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >::IndexType) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; - return meshData; -} + return meshData; + } }; int main(int argc, char *argv[]) diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index 6e94c5b8..b9ee73a5 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -47,100 +47,110 @@ using namespace std; const int32_t g_uVolumeSideLength = 128; -int main(int argc, char *argv[]) +class OpenGLExample : public OpenGLWidget { - FilePager* pager = new FilePager("."); - PagedVolume volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(g_uVolumeSideLength - 1, g_uVolumeSideLength - 1, g_uVolumeSideLength - 1)), pager); - - //Make our volume contain a sphere in the center. - int32_t minPos = 0; - int32_t midPos = g_uVolumeSideLength / 2; - int32_t maxPos = g_uVolumeSideLength - 1; - - cout << "Creating sphere 1" << std::endl; - createSphereInVolume(volData, 60.0f, 5); - cout << "Creating sphere 2" << std::endl; - createSphereInVolume(volData, 50.0f, 4); - cout << "Creating sphere 3" << std::endl; - createSphereInVolume(volData, 40.0f, 3); - cout << "Creating sphere 4" << std::endl; - createSphereInVolume(volData, 30.0f, 2); - cout << "Creating sphere 5" << std::endl; - createSphereInVolume(volData, 20.0f, 1); - - cout << "Creating cubes" << std::endl; - createCubeInVolume(volData, Vector3DInt32(minPos, minPos, minPos), Vector3DInt32(midPos-1, midPos-1, midPos-1), 0); - createCubeInVolume(volData, Vector3DInt32(midPos+1, midPos+1, minPos), Vector3DInt32(maxPos, maxPos, midPos-1), 0); - createCubeInVolume(volData, Vector3DInt32(midPos+1, minPos, midPos+1), Vector3DInt32(maxPos, midPos-1, maxPos), 0); - createCubeInVolume(volData, Vector3DInt32(minPos, midPos+1, midPos+1), Vector3DInt32(midPos-1, maxPos, maxPos), 0); - - createCubeInVolume(volData, Vector3DInt32(1, midPos-10, midPos-10), Vector3DInt32(maxPos-1, midPos+10, midPos+10), MaterialDensityPair44::getMaxDensity()); - createCubeInVolume(volData, Vector3DInt32(midPos-10, 1, midPos-10), Vector3DInt32(midPos+10, maxPos-1, midPos+10), MaterialDensityPair44::getMaxDensity()); - createCubeInVolume(volData, Vector3DInt32(midPos-10, midPos-10 ,1), Vector3DInt32(midPos+10, midPos+10, maxPos-1), MaterialDensityPair44::getMaxDensity()); - - QApplication app(argc, argv); - - OpenGLWidget openGLWidget(0); - - - openGLWidget.show(); - - QSharedPointer shader(new QGLShaderProgram); - - if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/openglexample.vert")) +public: + OpenGLExample(QWidget *parent) + :OpenGLWidget(parent) { - std::cerr << shader->log().toStdString() << std::endl; - exit(EXIT_FAILURE); } - if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/openglexample.frag")) +protected: + void initialize() override { - std::cerr << shader->log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } + FilePager* pager = new FilePager("."); + PagedVolume volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(g_uVolumeSideLength - 1, g_uVolumeSideLength - 1, g_uVolumeSideLength - 1)), pager); - openGLWidget.setShader(shader); + //Make our volume contain a sphere in the center. + int32_t minPos = 0; + int32_t midPos = g_uVolumeSideLength / 2; + int32_t maxPos = g_uVolumeSideLength - 1; - QTime time; - time.start(); - //openGLWidget.setVolume(&volData); - cout << endl << "Time taken = " << time.elapsed() / 1000.0f << "s" << endl << endl; + cout << "Creating sphere 1" << std::endl; + createSphereInVolume(volData, 60.0f, 5); + cout << "Creating sphere 2" << std::endl; + createSphereInVolume(volData, 50.0f, 4); + cout << "Creating sphere 3" << std::endl; + createSphereInVolume(volData, 40.0f, 3); + cout << "Creating sphere 4" << std::endl; + createSphereInVolume(volData, 30.0f, 2); + cout << "Creating sphere 5" << std::endl; + createSphereInVolume(volData, 20.0f, 1); - const int32_t extractedRegionSize = 32; - int meshCounter = 0; + cout << "Creating cubes" << std::endl; + createCubeInVolume(volData, Vector3DInt32(minPos, minPos, minPos), Vector3DInt32(midPos - 1, midPos - 1, midPos - 1), 0); + createCubeInVolume(volData, Vector3DInt32(midPos + 1, midPos + 1, minPos), Vector3DInt32(maxPos, maxPos, midPos - 1), 0); + createCubeInVolume(volData, Vector3DInt32(midPos + 1, minPos, midPos + 1), Vector3DInt32(maxPos, midPos - 1, maxPos), 0); + createCubeInVolume(volData, Vector3DInt32(minPos, midPos + 1, midPos + 1), Vector3DInt32(midPos - 1, maxPos, maxPos), 0); - for (int32_t z = 0; z < volData.getDepth(); z += extractedRegionSize) - { - for (int32_t y = 0; y < volData.getHeight(); y += extractedRegionSize) + createCubeInVolume(volData, Vector3DInt32(1, midPos - 10, midPos - 10), Vector3DInt32(maxPos - 1, midPos + 10, midPos + 10), MaterialDensityPair44::getMaxDensity()); + createCubeInVolume(volData, Vector3DInt32(midPos - 10, 1, midPos - 10), Vector3DInt32(midPos + 10, maxPos - 1, midPos + 10), MaterialDensityPair44::getMaxDensity()); + createCubeInVolume(volData, Vector3DInt32(midPos - 10, midPos - 10, 1), Vector3DInt32(midPos + 10, midPos + 10, maxPos - 1), MaterialDensityPair44::getMaxDensity()); + + QSharedPointer shader(new QGLShaderProgram); + + if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/openglexample.vert")) { - for (int32_t x = 0; x < volData.getWidth(); x += extractedRegionSize) + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/openglexample.frag")) + { + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + setShader(shader); + + QTime time; + time.start(); + //openGLWidget.setVolume(&volData); + cout << endl << "Time taken = " << time.elapsed() / 1000.0f << "s" << endl << endl; + + const int32_t extractedRegionSize = 32; + int meshCounter = 0; + + for (int32_t z = 0; z < volData.getDepth(); z += extractedRegionSize) + { + for (int32_t y = 0; y < volData.getHeight(); y += extractedRegionSize) { - // Specify the region to extract based on a starting position and the desired region sze. - PolyVox::Region regToExtract(x, y, z, x + extractedRegionSize, y + extractedRegionSize, z + extractedRegionSize); + for (int32_t x = 0; x < volData.getWidth(); x += extractedRegionSize) + { + // Specify the region to extract based on a starting position and the desired region sze. + PolyVox::Region regToExtract(x, y, z, x + extractedRegionSize, y + extractedRegionSize, z + extractedRegionSize); - // If you uncomment this line you will be able to see that the volume is rendered as multiple seperate meshes. - //regToExtract.shrink(1); + // If you uncomment this line you will be able to see that the volume is rendered as multiple seperate meshes. + //regToExtract.shrink(1); - // Perform the extraction for this region of the volume - auto mesh = extractMarchingCubesMesh(&volData, regToExtract); + // Perform the extraction for this region of the volume + auto mesh = extractMarchingCubesMesh(&volData, regToExtract); - // The returned mesh needs to be decoded to be appropriate for GPU rendering. - auto decodedMesh = decodeMesh(mesh); + // The returned mesh needs to be decoded to be appropriate for GPU rendering. + auto decodedMesh = decodeMesh(mesh); - // Pass the surface to the OpenGL window. Note that we are also passing an offset in this multi-mesh example. This is because - // the surface extractors return a mesh with 'local space' positions to reduce storage requirements and precision problems. - openGLWidget.addMesh(decodedMesh, decodedMesh.getOffset()); + // Pass the surface to the OpenGL window. Note that we are also passing an offset in this multi-mesh example. This is because + // the surface extractors return a mesh with 'local space' positions to reduce storage requirements and precision problems. + addMesh(decodedMesh, decodedMesh.getOffset()); - meshCounter++; + meshCounter++; + } } } + + cout << "Rendering volume as " << meshCounter << " seperate meshes" << endl; + + setViewableRegion(volData.getEnclosingRegion()); } +}; - cout << "Rendering volume as " << meshCounter << " seperate meshes" << endl; - - - openGLWidget.setViewableRegion(volData.getEnclosingRegion()); - +int main(int argc, char *argv[]) +{ + //Create and show the Qt OpenGL window + QApplication app(argc, argv); + OpenGLExample openGLWidget(0); + openGLWidget.show(); + //Run the message pump. return app.exec(); -} +} diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 09b325d8..6b02e5e0 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -139,48 +139,61 @@ public: } }; +class PagingExample : public OpenGLWidget +{ +public: + PagingExample(QWidget *parent) + :OpenGLWidget(parent) + { + } + +protected: + void initialize() override + { + PerlinNoisePager* pager = new PerlinNoisePager(); + PagedVolume volData(PolyVox::Region::MaxRegion(), pager, 64); + volData.setMemoryUsageLimit(8 * 1024 * 1024); // 8Mb + + //createSphereInVolume(volData, 30); + //createPerlinTerrain(volData); + //createPerlinVolumeSlow(volData); + std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl; + //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; + PolyVox::Region reg(Vector3DInt32(-255, 0, 0), Vector3DInt32(255, 255, 255)); + std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; + volData.prefetch(reg); + std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl; + //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; + PolyVox::Region reg2(Vector3DInt32(0, 0, 0), Vector3DInt32(255, 255, 255)); + std::cout << "Flushing region: " << reg2.getLowerCorner() << " -> " << reg2.getUpperCorner() << std::endl; + volData.flush(reg2); + std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl; + //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; + std::cout << "Flushing entire volume" << std::endl; + volData.flushAll(); + std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl; + //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; + + //Extract the surface + auto mesh = extractCubicMesh(&volData, reg2); + std::cout << "#vertices: " << mesh.getNoOfVertices() << std::endl; + + auto decodedMesh = decodeMesh(mesh); + + //Pass the surface to the OpenGL window + addMesh(decodedMesh); + + setViewableRegion(reg2); + } +}; + int main(int argc, char *argv[]) { //Create and show the Qt OpenGL window QApplication app(argc, argv); - OpenGLWidget openGLWidget(0); + PagingExample openGLWidget(0); openGLWidget.show(); - PerlinNoisePager* pager = new PerlinNoisePager(); - PagedVolume volData(PolyVox::Region::MaxRegion(), pager, 64); - volData.setMemoryUsageLimit(8 * 1024 * 1024); // 8Mb - - //createSphereInVolume(volData, 30); - //createPerlinTerrain(volData); - //createPerlinVolumeSlow(volData); - std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; - //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; - PolyVox::Region reg(Vector3DInt32(-255,0,0), Vector3DInt32(255,255,255)); - std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; - volData.prefetch(reg); - std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; - //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; - PolyVox::Region reg2(Vector3DInt32(0,0,0), Vector3DInt32(255,255,255)); - std::cout << "Flushing region: " << reg2.getLowerCorner() << " -> " << reg2.getUpperCorner() << std::endl; - volData.flush(reg2); - std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; - //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; - std::cout << "Flushing entire volume" << std::endl; - volData.flushAll(); - std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; - //std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; - - //Extract the surface - auto mesh = extractCubicMesh(&volData, reg2); - std::cout << "#vertices: " << mesh.getNoOfVertices() << std::endl; - - auto decodedMesh = decodeMesh(mesh); - - //Pass the surface to the OpenGL window - openGLWidget.addMesh(decodedMesh); - - openGLWidget.setViewableRegion(reg2); - //Run the message pump. return app.exec(); } diff --git a/examples/SmoothLOD/main.cpp b/examples/SmoothLOD/main.cpp index b8c56f08..cc255d24 100644 --- a/examples/SmoothLOD/main.cpp +++ b/examples/SmoothLOD/main.cpp @@ -68,43 +68,56 @@ void createSphereInVolume(PagedVolume& volData, float fRadius) } } +class SmoothLODExample : public OpenGLWidget +{ +public: + SmoothLODExample(QWidget *parent) + :OpenGLWidget(parent) + { + } + +protected: + void initialize() override + { + //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, 28); + + //Smooth the data - should reimplement this using LowPassFilter + //smoothRegion(volData, volData.getEnclosingRegion()); + //smoothRegion(volData, volData.getEnclosingRegion()); + //smoothRegion(volData, volData.getEnclosingRegion()); + + RawVolume volDataLowLOD(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(15, 31, 31))); + + VolumeResampler< PagedVolume, RawVolume > volumeResampler(&volData, PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(31, 63, 63)), &volDataLowLOD, volDataLowLOD.getEnclosingRegion()); + volumeResampler.execute(); + + //Extract the surface + auto meshLowLOD = extractMarchingCubesMesh(&volDataLowLOD, volDataLowLOD.getEnclosingRegion()); + // The returned mesh needs to be decoded to be appropriate for GPU rendering. + auto decodedMeshLowLOD = decodeMesh(meshLowLOD); + + //Extract the surface + auto meshHighLOD = extractMarchingCubesMesh(&volData, PolyVox::Region(Vector3DInt32(30, 0, 0), Vector3DInt32(63, 63, 63))); + // The returned mesh needs to be decoded to be appropriate for GPU rendering. + auto decodedMeshHighLOD = decodeMesh(meshHighLOD); + + //Pass the surface to the OpenGL window + addMesh(decodedMeshHighLOD, Vector3DInt32(30, 0, 0)); + addMesh(decodedMeshLowLOD, Vector3DInt32(0, 0, 0), 63.0f / 31.0f); + + setViewableRegion(volData.getEnclosingRegion()); + } +}; + int main(int argc, char *argv[]) { //Create and show the Qt OpenGL window QApplication app(argc, argv); - OpenGLWidget openGLWidget(0); + SmoothLODExample openGLWidget(0); openGLWidget.show(); - //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, 28); - - //Smooth the data - should reimplement this using LowPassFilter - //smoothRegion(volData, volData.getEnclosingRegion()); - //smoothRegion(volData, volData.getEnclosingRegion()); - //smoothRegion(volData, volData.getEnclosingRegion()); - - RawVolume volDataLowLOD(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(15, 31, 31))); - - VolumeResampler< PagedVolume, RawVolume > volumeResampler(&volData, PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(31, 63, 63)), &volDataLowLOD, volDataLowLOD.getEnclosingRegion()); - volumeResampler.execute(); - - //Extract the surface - auto meshLowLOD = extractMarchingCubesMesh(&volDataLowLOD, volDataLowLOD.getEnclosingRegion()); - // The returned mesh needs to be decoded to be appropriate for GPU rendering. - auto decodedMeshLowLOD = decodeMesh(meshLowLOD); - - //Extract the surface - auto meshHighLOD = extractMarchingCubesMesh(&volData, PolyVox::Region(Vector3DInt32(30, 0, 0), Vector3DInt32(63, 63, 63))); - // The returned mesh needs to be decoded to be appropriate for GPU rendering. - auto decodedMeshHighLOD = decodeMesh(meshHighLOD); - - //Pass the surface to the OpenGL window - openGLWidget.addMesh(decodedMeshHighLOD, Vector3DInt32(30, 0, 0)); - openGLWidget.addMesh(decodedMeshLowLOD, Vector3DInt32(0, 0, 0), 63.0f / 31.0f); - - openGLWidget.setViewableRegion(volData.getEnclosingRegion()); - //Run the message pump. return app.exec(); } From 9c93c5fc36d9d34eaccb9aaf15c948fc3f425fca Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 20 Feb 2015 15:28:54 +0100 Subject: [PATCH 3/8] Switched examples to use FPS-style first person perspective camera. --- examples/Basic/main.cpp | 4 +- examples/DecodeOnGPU/main.cpp | 2 +- examples/OpenGL/main.cpp | 10 +-- examples/Paging/main.cpp | 2 +- examples/SmoothLOD/main.cpp | 2 +- examples/common/OpenGLWidget.cpp | 129 ++++++++++++++++++++++--------- examples/common/OpenGLWidget.h | 31 +++++--- 7 files changed, 124 insertions(+), 56 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index ea93bb68..9253ce30 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -91,8 +91,8 @@ protected: //Pass the surface to the OpenGL window addMesh(decodedMesh); - //openGLWidget.addMesh(mesh2); - setViewableRegion(volData.getEnclosingRegion()); + + setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/DecodeOnGPU/main.cpp b/examples/DecodeOnGPU/main.cpp index eff3a5a7..74329df8 100644 --- a/examples/DecodeOnGPU/main.cpp +++ b/examples/DecodeOnGPU/main.cpp @@ -109,7 +109,7 @@ protected: OpenGLMeshData meshData = buildOpenGLMeshData(mesh); addMeshData(meshData); - setViewableRegion(volData.getEnclosingRegion()); + setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } private: diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index b9ee73a5..94802c4b 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -78,10 +78,10 @@ protected: createSphereInVolume(volData, 20.0f, 1); cout << "Creating cubes" << std::endl; - createCubeInVolume(volData, Vector3DInt32(minPos, minPos, minPos), Vector3DInt32(midPos - 1, midPos - 1, midPos - 1), 0); - createCubeInVolume(volData, Vector3DInt32(midPos + 1, midPos + 1, minPos), Vector3DInt32(maxPos, maxPos, midPos - 1), 0); - createCubeInVolume(volData, Vector3DInt32(midPos + 1, minPos, midPos + 1), Vector3DInt32(maxPos, midPos - 1, maxPos), 0); - createCubeInVolume(volData, Vector3DInt32(minPos, midPos + 1, midPos + 1), Vector3DInt32(midPos - 1, maxPos, maxPos), 0); + createCubeInVolume(volData, Vector3DInt32(minPos, minPos, midPos + 1), Vector3DInt32(midPos - 1, midPos - 1, maxPos), 0); + createCubeInVolume(volData, Vector3DInt32(midPos + 1, midPos + 1, midPos + 1), Vector3DInt32(maxPos, maxPos, maxPos), 0); + createCubeInVolume(volData, Vector3DInt32(minPos, midPos + 1, minPos), Vector3DInt32(midPos - 1, maxPos, midPos - 1), 0); + createCubeInVolume(volData, Vector3DInt32(midPos + 1, minPos, minPos), Vector3DInt32(maxPos, midPos - 1, midPos - 1), 0); createCubeInVolume(volData, Vector3DInt32(1, midPos - 10, midPos - 10), Vector3DInt32(maxPos - 1, midPos + 10, midPos + 10), MaterialDensityPair44::getMaxDensity()); createCubeInVolume(volData, Vector3DInt32(midPos - 10, 1, midPos - 10), Vector3DInt32(midPos + 10, maxPos - 1, midPos + 10), MaterialDensityPair44::getMaxDensity()); @@ -140,7 +140,7 @@ protected: cout << "Rendering volume as " << meshCounter << " seperate meshes" << endl; - setViewableRegion(volData.getEnclosingRegion()); + setCameraTransform(QVector3D(150.0f, 150.0f, 150.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 6b02e5e0..8436d27e 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -183,7 +183,7 @@ protected: //Pass the surface to the OpenGL window addMesh(decodedMesh); - setViewableRegion(reg2); + setCameraTransform(QVector3D(300.0f, 300.0f, 300.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/SmoothLOD/main.cpp b/examples/SmoothLOD/main.cpp index cc255d24..34b3a511 100644 --- a/examples/SmoothLOD/main.cpp +++ b/examples/SmoothLOD/main.cpp @@ -107,7 +107,7 @@ protected: addMesh(decodedMeshHighLOD, Vector3DInt32(30, 0, 0)); addMesh(decodedMeshLowLOD, Vector3DInt32(0, 0, 0), 63.0f / 31.0f); - setViewableRegion(volData.getEnclosingRegion()); + setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.cpp index ce774e30..7f583237 100644 --- a/examples/common/OpenGLWidget.cpp +++ b/examples/common/OpenGLWidget.cpp @@ -3,6 +3,7 @@ #include #include #include +#include //#include using namespace PolyVox; @@ -13,9 +14,6 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// OpenGLWidget::OpenGLWidget(QWidget *parent) :QGLWidget(parent) - ,m_viewableRegion(PolyVox::Region(0, 0, 0, 255, 255, 255)) - ,m_xRotation(0) - ,m_yRotation(0) { } @@ -24,13 +22,11 @@ void OpenGLWidget::setShader(QSharedPointer shader) mShader = shader; } -void OpenGLWidget::setViewableRegion(PolyVox::Region viewableRegion) +void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw) { - m_viewableRegion = viewableRegion; - - // The user has specifed a new viewable region - // so we need to regenerate our camera matrix. - setupWorldToCameraMatrix(); + mCameraPosition = position; + mCameraYaw = yaw; + mCameraPitch = pitch; } void OpenGLWidget::mousePressEvent(QMouseEvent* event) @@ -45,15 +41,24 @@ void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) // Update the x and y rotations based on the mouse movement. m_CurrentMousePos = event->pos(); QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; - m_xRotation += diff.x(); - m_yRotation += diff.y(); + mCameraYaw -= diff.x() * mCameraRotateSpeed; + mCameraPitch -= diff.y() * mCameraRotateSpeed; m_LastFrameMousePos = m_CurrentMousePos; +} - // The camera rotation has changed so we need to regenerate the matrix. - setupWorldToCameraMatrix(); +void OpenGLWidget::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Escape) + { + close(); + } - // Re-render. - update(); + mPressedKeys.append(event->key()); +} + +void OpenGLWidget::keyReleaseEvent(QKeyEvent* event) +{ + mPressedKeys.removeAll(event->key()); } //////////////////////////////////////////////////////////////////////////////// @@ -119,10 +124,14 @@ void OpenGLWidget::initializeGL() exit(EXIT_FAILURE); } - // Initial setup of camera. - setupWorldToCameraMatrix(); - initialize(); + + // Start a timer to drive the main rendering loop. + QTimer* timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(0); + + mElapsedTimer.start(); } void OpenGLWidget::resizeGL(int w, int h) @@ -135,11 +144,75 @@ void OpenGLWidget::resizeGL(int w, int h) float zFar = 1000.0; cameraToClipMatrix.setToIdentity(); - cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); + //cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); + cameraToClipMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar); } void OpenGLWidget::paintGL() { + // Direction : Spherical coordinates to Cartesian coordinates conversion + QVector3D cameraForward( + cos(mCameraPitch) * sin(mCameraYaw), + sin(mCameraPitch), + cos(mCameraPitch) * cos(mCameraYaw) + ); + + // Right vector + QVector3D cameraRight( + sin(mCameraYaw - 3.14f / 2.0f), + 0, + cos(mCameraYaw - 3.14f / 2.0f) + ); + + // Up vector + QVector3D cameraUp = QVector3D::crossProduct(cameraRight, cameraForward); + + // Get the elapsed time since last frame and convert to seconds. + float deltaTime = mElapsedTimer.restart() / 1000.0f; + + // Move forward + if ((mPressedKeys.contains(Qt::Key_Up)) || (mPressedKeys.contains(Qt::Key_W))) + { + mCameraPosition += cameraForward * deltaTime * mCameraMoveSpeed; + } + // Move backward + if ((mPressedKeys.contains(Qt::Key_Down)) || (mPressedKeys.contains(Qt::Key_S))) + { + mCameraPosition -= cameraForward * deltaTime * mCameraMoveSpeed; + } + // Strafe right + if ((mPressedKeys.contains(Qt::Key_Right)) || (mPressedKeys.contains(Qt::Key_D))) + { + mCameraPosition += cameraRight * deltaTime * mCameraMoveSpeed; + } + // Strafe left + if ((mPressedKeys.contains(Qt::Key_Left)) || (mPressedKeys.contains(Qt::Key_A))) + { + 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( + mCameraPosition, // Camera is here + mCameraPosition + cameraForward, // and looks here : at the same position, plus "direction" + cameraUp // Head is up (set to 0,-1,0 to look upside-down) + ); + //Clear the screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -177,21 +250,3 @@ void OpenGLWidget::paintGL() std::cerr << "OpenGL Error: " << errCode << std::endl; } } - -//////////////////////////////////////////////////////////////////////////////// -// Private functions -//////////////////////////////////////////////////////////////////////////////// -void OpenGLWidget::setupWorldToCameraMatrix() -{ - QVector3D lowerCorner(m_viewableRegion.getLowerX(), m_viewableRegion.getLowerY(), m_viewableRegion.getLowerZ()); - QVector3D upperCorner(m_viewableRegion.getUpperX(), m_viewableRegion.getUpperY(), m_viewableRegion.getUpperZ()); - - QVector3D centerPoint = (lowerCorner + upperCorner) * 0.5; - float fDiagonalLength = (upperCorner - lowerCorner).length(); - - worldToCameraMatrix.setToIdentity(); - worldToCameraMatrix.translate(0, 0, -fDiagonalLength / 2.0f); //Move the camera back by the required amount - worldToCameraMatrix.rotate(m_xRotation, 0, 1, 0); //rotate around y-axis - worldToCameraMatrix.rotate(m_yRotation, 1, 0, 0); //rotate around x-axis - worldToCameraMatrix.translate(-centerPoint); //centre the model on the origin -} \ No newline at end of file diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h index c411c8b6..16362a40 100644 --- a/examples/common/OpenGLWidget.h +++ b/examples/common/OpenGLWidget.h @@ -28,6 +28,7 @@ distribution. #include +#include #include #include #include @@ -122,15 +123,20 @@ public: // this example framework is only meant to show a single volume at a time void setShader(QSharedPointer shader); - // The viewable region can be adjusted so that this example framework can be used for different volume sizes. - void setViewableRegion(PolyVox::Region viewableRegion); + void setCameraTransform(QVector3D position, float pitch, float yaw); // Mouse handling void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); + // Keyboard handling + void keyPressEvent(QKeyEvent* event); + void keyReleaseEvent(QKeyEvent* event); + protected: + const float PI = 3.14159265358979f; + // Qt OpenGL functions void initializeGL(); void resizeGL(int w, int h); @@ -141,9 +147,6 @@ protected: } private: - - void setupWorldToCameraMatrix(); - // Index/vertex buffer data std::vector mMeshData; @@ -157,10 +160,20 @@ private: QPoint m_LastFrameMousePos; QPoint m_CurrentMousePos; - // Camera setup - PolyVox::Region m_viewableRegion; - int m_xRotation; - int m_yRotation; + // Keyboard data + QList mPressedKeys; + + // For input handling and movement + float mCameraMoveSpeed = 50.0f; + float mCameraRotateSpeed = 0.005f; + + // Camera properties + QVector3D mCameraPosition = QVector3D(0, 0, -100); + float mCameraYaw = 0.0f; + float mCameraPitch = 0.0f; + float mCameraFOV = 60.0f; + + QElapsedTimer mElapsedTimer; }; #endif //__BasicExample_OpenGLWidget_H__ From 838407ba4fd36d50f04a7012f25d5a3c10e1ac1b Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 20 Feb 2015 16:20:09 +0100 Subject: [PATCH 4/8] Started splitting example framework into to two classes. One will be general purpose (for use in Cubiquity, etc), and the other will have PolyVox specific stuff. --- examples/Basic/CMakeLists.txt | 2 ++ examples/Basic/main.cpp | 6 ++--- examples/DecodeOnGPU/CMakeLists.txt | 2 ++ examples/DecodeOnGPU/main.cpp | 6 ++--- examples/OpenGL/CMakeLists.txt | 2 ++ examples/OpenGL/main.cpp | 6 ++--- examples/Paging/CMakeLists.txt | 2 ++ examples/Paging/main.cpp | 6 ++--- examples/SmoothLOD/CMakeLists.txt | 2 ++ examples/SmoothLOD/main.cpp | 6 ++--- examples/common/PolyVoxExample.cpp | 1 + examples/common/PolyVoxExample.h | 38 +++++++++++++++++++++++++++++ 12 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 examples/common/PolyVoxExample.cpp create mode 100644 examples/common/PolyVoxExample.h diff --git a/examples/Basic/CMakeLists.txt b/examples/Basic/CMakeLists.txt index 93fadf85..51156dc9 100644 --- a/examples/Basic/CMakeLists.txt +++ b/examples/Basic/CMakeLists.txt @@ -25,11 +25,13 @@ PROJECT(BasicExample) SET(SRC_FILES main.cpp ../common/OpenGLWidget.cpp + ../common/PolyVoxExample.cpp ) #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h + ../common/PolyVoxExample.h ) #"Sources" and "Headers" are the group names in Visual Studio. diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index 9253ce30..8214574e 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -21,7 +21,7 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ -#include "OpenGLWidget.h" +#include "PolyVoxExample.h" #include "PolyVox/CubicSurfaceExtractor.h" #include "PolyVox/MarchingCubesSurfaceExtractor.h" @@ -66,11 +66,11 @@ void createSphereInVolume(PagedVolume& volData, float fRadius) } } -class BasicExample : public OpenGLWidget +class BasicExample : public PolyVoxExample { public: BasicExample(QWidget *parent) - :OpenGLWidget(parent) + :PolyVoxExample(parent) { } diff --git a/examples/DecodeOnGPU/CMakeLists.txt b/examples/DecodeOnGPU/CMakeLists.txt index 7bbff8ba..063c2ffd 100644 --- a/examples/DecodeOnGPU/CMakeLists.txt +++ b/examples/DecodeOnGPU/CMakeLists.txt @@ -25,11 +25,13 @@ PROJECT(DecodeOnGPUExample) SET(SRC_FILES main.cpp ../common/OpenGLWidget.cpp + ../common/PolyVoxExample.cpp ) #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h + ../common/PolyVoxExample.h ) #"Sources" and "Headers" are the group names in Visual Studio. diff --git a/examples/DecodeOnGPU/main.cpp b/examples/DecodeOnGPU/main.cpp index 74329df8..393d37fa 100644 --- a/examples/DecodeOnGPU/main.cpp +++ b/examples/DecodeOnGPU/main.cpp @@ -21,7 +21,7 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ -#include "OpenGLWidget.h" +#include "PolyVoxExample.h" #include "PolyVox/CubicSurfaceExtractor.h" #include "PolyVox/MarchingCubesSurfaceExtractor.h" @@ -66,11 +66,11 @@ void createSphereInVolume(PagedVolume& volData, float fRadius) } } -class DecodeOnGPUExample : public OpenGLWidget +class DecodeOnGPUExample : public PolyVoxExample { public: DecodeOnGPUExample(QWidget *parent) - :OpenGLWidget(parent) + :PolyVoxExample(parent) { } diff --git a/examples/OpenGL/CMakeLists.txt b/examples/OpenGL/CMakeLists.txt index 1fab7c69..c63ee818 100644 --- a/examples/OpenGL/CMakeLists.txt +++ b/examples/OpenGL/CMakeLists.txt @@ -30,6 +30,7 @@ SET(SRC_FILES #OpenGLSupport.cpp #OpenGLVertexBufferObjectSupport.cpp ../common/OpenGLWidget.cpp + ../common/PolyVoxExample.cpp Shapes.cpp ) @@ -39,6 +40,7 @@ SET(INC_FILES #OpenGLSupport.h #OpenGLVertexBufferObjectSupport.h ../common/OpenGLWidget.h + ../common/PolyVoxExample.h Shapes.h ) diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index 94802c4b..ce0fbfa3 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -31,7 +31,7 @@ freely, subject to the following restrictions: #include "Shapes.h" -#include "OpenGLWidget.h" +#include "PolyVoxExample.h" #ifdef WIN32 #include // Standard Header For Most Programs @@ -47,11 +47,11 @@ using namespace std; const int32_t g_uVolumeSideLength = 128; -class OpenGLExample : public OpenGLWidget +class OpenGLExample : public PolyVoxExample { public: OpenGLExample(QWidget *parent) - :OpenGLWidget(parent) + :PolyVoxExample(parent) { } diff --git a/examples/Paging/CMakeLists.txt b/examples/Paging/CMakeLists.txt index a0c626ac..f5fffe89 100644 --- a/examples/Paging/CMakeLists.txt +++ b/examples/Paging/CMakeLists.txt @@ -26,12 +26,14 @@ SET(SRC_FILES main.cpp ../common/OpenGLWidget.cpp Perlin.cpp + ../common/PolyVoxExample.cpp ) #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h Perlin.h + ../common/PolyVoxExample.h ) #"Sources" and "Headers" are the group names in Visual Studio. diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 8436d27e..012fb9d0 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -21,7 +21,7 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ -#include "OpenGLWidget.h" +#include "PolyVoxExample.h" #include "Perlin.h" #include "PolyVox/MaterialDensityPair.h" @@ -139,11 +139,11 @@ public: } }; -class PagingExample : public OpenGLWidget +class PagingExample : public PolyVoxExample { public: PagingExample(QWidget *parent) - :OpenGLWidget(parent) + :PolyVoxExample(parent) { } diff --git a/examples/SmoothLOD/CMakeLists.txt b/examples/SmoothLOD/CMakeLists.txt index 9b1ef6fc..492662bb 100644 --- a/examples/SmoothLOD/CMakeLists.txt +++ b/examples/SmoothLOD/CMakeLists.txt @@ -25,11 +25,13 @@ PROJECT(SmoothLODExample) SET(SRC_FILES main.cpp ../common/OpenGLWidget.cpp + ../common/PolyVoxExample.cpp ) #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h + ../common/PolyVoxExample.h ) #"Sources" and "Headers" are the group names in Visual Studio. diff --git a/examples/SmoothLOD/main.cpp b/examples/SmoothLOD/main.cpp index 34b3a511..b6888334 100644 --- a/examples/SmoothLOD/main.cpp +++ b/examples/SmoothLOD/main.cpp @@ -21,7 +21,7 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ -#include "OpenGLWidget.h" +#include "PolyVoxExample.h" #include "PolyVox/Density.h" #include "PolyVox/MarchingCubesSurfaceExtractor.h" @@ -68,11 +68,11 @@ void createSphereInVolume(PagedVolume& volData, float fRadius) } } -class SmoothLODExample : public OpenGLWidget +class SmoothLODExample : public PolyVoxExample { public: SmoothLODExample(QWidget *parent) - :OpenGLWidget(parent) + :PolyVoxExample(parent) { } diff --git a/examples/common/PolyVoxExample.cpp b/examples/common/PolyVoxExample.cpp new file mode 100644 index 00000000..5dc86fd9 --- /dev/null +++ b/examples/common/PolyVoxExample.cpp @@ -0,0 +1 @@ +#include "PolyVoxExample.h" diff --git a/examples/common/PolyVoxExample.h b/examples/common/PolyVoxExample.h new file mode 100644 index 00000000..ee7231b2 --- /dev/null +++ b/examples/common/PolyVoxExample.h @@ -0,0 +1,38 @@ +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*******************************************************************************/ + +#ifndef __PolyVoxExample_H__ +#define __PolyVoxExample_H__ + +#include "OpenGLWidget.h" + +class PolyVoxExample : public OpenGLWidget +{ +public: + PolyVoxExample(QWidget *parent) + :OpenGLWidget(parent) + { + } +}; + +#endif //__PolyVoxExample_H__ \ No newline at end of file From 7262ca313e98b015a79b6e78169b6b663f35ae3f Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 20 Feb 2015 16:56:03 +0100 Subject: [PATCH 5/8] More work splitting example framework into two pieces. --- examples/Basic/main.cpp | 4 +- examples/DecodeOnGPU/main.cpp | 2 +- examples/OpenGL/main.cpp | 2 +- examples/Paging/main.cpp | 2 +- examples/SmoothLOD/main.cpp | 2 +- examples/common/OpenGLWidget.cpp | 79 +------------- examples/common/OpenGLWidget.h | 93 +---------------- examples/common/PolyVoxExample.cpp | 5 + examples/common/PolyVoxExample.h | 159 +++++++++++++++++++++++++++++ 9 files changed, 174 insertions(+), 174 deletions(-) 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 From 9547824f14c04efff4feb29f83bb97ed4e38e607 Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 24 Feb 2015 16:08:55 +0100 Subject: [PATCH 6/8] Renamed matrices. I quite like names such as 'modelToWorldMatrix' and 'cameraToClipMatrix' because they were very explicit about what the transform was doing. However OpenGL uses common terms such as 'model matrix' and 'projection matrix', so other people wlil be able to follow the code more easily if we stick to these conventions. --- examples/DecodeOnGPU/decode.vert | 12 ++++---- examples/OpenGL/openglexample.vert | 8 +++--- examples/Python/PythonExample.py | 44 +++++++++++++++--------------- examples/common/OpenGLWidget.cpp | 10 +++---- examples/common/OpenGLWidget.h | 4 +-- examples/common/PolyVoxExample.h | 12 ++++---- examples/common/example.vert | 12 ++++---- 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/examples/DecodeOnGPU/decode.vert b/examples/DecodeOnGPU/decode.vert index 1ca80d09..41aaf821 100644 --- a/examples/DecodeOnGPU/decode.vert +++ b/examples/DecodeOnGPU/decode.vert @@ -4,9 +4,9 @@ in uvec4 position; // This will be the position of the vertex in model-space in uint normal; // The usual matrices are provided -uniform mat4 cameraToClipMatrix; -uniform mat4 worldToCameraMatrix; -uniform mat4 modelToWorldMatrix; +uniform mat4 projectionMatrix; +uniform mat4 viewMatrix; +uniform mat4 modelMatrix; // This will be used by the fragment shader to calculate flat-shaded normals. This is an unconventional approach // but we use it in this example framework because not all surface extractor generate surface normals. @@ -40,7 +40,7 @@ void main() worldNormal.w = 1.0; // Standard sequence of OpenGL transformations. - worldPosition = modelToWorldMatrix * decodedPosition; - vec4 cameraPosition = worldToCameraMatrix * worldPosition; - gl_Position = cameraToClipMatrix * cameraPosition; + worldPosition = modelMatrix * decodedPosition; + vec4 cameraPosition = viewMatrix * worldPosition; + gl_Position = projectionMatrix * cameraPosition; } diff --git a/examples/OpenGL/openglexample.vert b/examples/OpenGL/openglexample.vert index 381fac12..ab87b187 100644 --- a/examples/OpenGL/openglexample.vert +++ b/examples/OpenGL/openglexample.vert @@ -4,9 +4,9 @@ in vec4 position; // This will be the position of the vertex in model-space in vec4 normal; // The normal data may not have been set in ivec2 material; -uniform mat4 cameraToClipMatrix; -uniform mat4 worldToCameraMatrix; -uniform mat4 modelToWorldMatrix; +uniform mat4 projectionMatrix; +uniform mat4 viewMatrix; +uniform mat4 modelMatrix; out vec4 worldPosition; //This is being passed to the fragment shader to calculate the normals out vec3 normalFromVS; @@ -15,7 +15,7 @@ flat out ivec2 materialFromVS; void main() { // Compute the usual OpenGL transformation to clip space. - gl_Position = cameraToClipMatrix * worldToCameraMatrix * modelToWorldMatrix * position; + gl_Position = projectionMatrix * viewMatrix * modelMatrix * position; // This example is demonstrating the marching cubes mesh, which does have per-vertex normals. We can // just pass them through, though real code might want to deal with transforming normals appropriatly. diff --git a/examples/Python/PythonExample.py b/examples/Python/PythonExample.py index 7c90297f..da9cea74 100755 --- a/examples/Python/PythonExample.py +++ b/examples/Python/PythonExample.py @@ -127,17 +127,17 @@ def run(): in vec4 position; in vec4 normal; - uniform mat4 cameraToClipMatrix; - uniform mat4 worldToCameraMatrix; - uniform mat4 modelToWorldMatrix; + uniform mat4 projectionMatrix; + uniform mat4 viewMatrix; + uniform mat4 modelMatrix; flat out float theColor; void main() { - vec4 temp = modelToWorldMatrix * position; - temp = worldToCameraMatrix * temp; - gl_Position = cameraToClipMatrix * temp; + vec4 temp = modelMatrix * position; + temp = viewMatrix * temp; + gl_Position = projectionMatrix * temp; theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1); } @@ -183,13 +183,13 @@ def run(): glDisableVertexAttribArray(0) #Now grab out transformation martix locations - modelToWorldMatrixUnif = glGetUniformLocation(shader, b"modelToWorldMatrix") - worldToCameraMatrixUnif = glGetUniformLocation(shader, b"worldToCameraMatrix") - cameraToClipMatrixUnif = glGetUniformLocation(shader, b"cameraToClipMatrix") + modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix") + viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix") + projectionMatrixUnif = glGetUniformLocation(shader, b"projectionMatrix") - modelToWorldMatrix = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') - worldToCameraMatrix = np.array([[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,-50.0],[0.0,0.0,0.0,1.0]], dtype='f') - cameraToClipMatrix = np.array([[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]], dtype='f') + modelMatrix = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') + viewMatrix = np.array([[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,-50.0],[0.0,0.0,0.0,1.0]], dtype='f') + projectionMatrix = np.array([[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]], dtype='f') #These next few lines just set up our camera frustum fovDeg = 45.0 @@ -198,16 +198,16 @@ def run(): zNear = 1.0 zFar = 1000.0 - cameraToClipMatrix[0][0] = frustumScale - cameraToClipMatrix[1][1] = frustumScale - cameraToClipMatrix[2][2] = (zFar + zNear) / (zNear - zFar) - cameraToClipMatrix[2][3] = -1.0 - cameraToClipMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) + projectionMatrix[0][0] = frustumScale + projectionMatrix[1][1] = frustumScale + projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar) + projectionMatrix[2][3] = -1.0 + projectionMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) - #worldToCameraMatrix and cameraToClipMatrix don't change ever so just set them once here + #viewMatrix and projectionMatrix don't change ever so just set them once here with shader: - glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_TRUE, cameraToClipMatrix) - glUniformMatrix4fv(worldToCameraMatrixUnif, 1, GL_TRUE, worldToCameraMatrix) + glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix) + glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix) #These are used to track the rotation of the volume LastFrameMousePos = (0,0) @@ -240,10 +240,10 @@ def run(): rotateAroundX = np.array([[1.0,0.0,0.0,0.0],[0.0,cos(radians(yRotation)),-sin(radians(yRotation)),0.0],[0.0,sin(radians(yRotation)),cos(radians(yRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') rotateAroundY = np.array([[cos(radians(xRotation)),0.0,sin(radians(xRotation)),0.0],[0.0,1.0,0.0,0.0],[-sin(radians(xRotation)),0.0,cos(radians(xRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') - modelToWorldMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) + modelMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) with shader: - glUniformMatrix4fv(modelToWorldMatrixUnif, 1, GL_TRUE, modelToWorldMatrix) + glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix) glBindVertexArray(vertexArrayObject) glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None) diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.cpp index 50056934..3eb24fb6 100644 --- a/examples/common/OpenGLWidget.cpp +++ b/examples/common/OpenGLWidget.cpp @@ -106,9 +106,9 @@ void OpenGLWidget::resizeGL(int w, int h) float zNear = 1.0; float zFar = 1000.0; - cameraToClipMatrix.setToIdentity(); - //cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); - cameraToClipMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar); + projectionMatrix.setToIdentity(); + //projectionMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); + projectionMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar); } void OpenGLWidget::paintGL() @@ -154,8 +154,8 @@ void OpenGLWidget::paintGL() mCameraPosition -= cameraRight * deltaTime * mCameraMoveSpeed; } - worldToCameraMatrix.setToIdentity(); - worldToCameraMatrix.lookAt( + viewMatrix.setToIdentity(); + viewMatrix.lookAt( mCameraPosition, // Camera is here mCameraPosition + cameraForward, // and looks here : at the same position, plus "direction" cameraUp // Head is up (set to 0,-1,0 to look upside-down) diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h index bd783849..8bbb3e1e 100644 --- a/examples/common/OpenGLWidget.h +++ b/examples/common/OpenGLWidget.h @@ -66,8 +66,8 @@ protected: protected: // Matrices - QMatrix4x4 worldToCameraMatrix; - QMatrix4x4 cameraToClipMatrix; + QMatrix4x4 viewMatrix; + QMatrix4x4 projectionMatrix; // Mouse data QPoint m_LastFrameMousePos; diff --git a/examples/common/PolyVoxExample.h b/examples/common/PolyVoxExample.h index cfbe39b9..b80fe56b 100644 --- a/examples/common/PolyVoxExample.h +++ b/examples/common/PolyVoxExample.h @@ -163,17 +163,17 @@ protected: mShader->bind(); // These two matrices are constant for all meshes. - mShader->setUniformValue("worldToCameraMatrix", worldToCameraMatrix); - mShader->setUniformValue("cameraToClipMatrix", cameraToClipMatrix); + mShader->setUniformValue("viewMatrix", viewMatrix); + mShader->setUniformValue("projectionMatrix", projectionMatrix); // 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); + QMatrix4x4 modelMatrix; + modelMatrix.translate(meshData.translation); + modelMatrix.scale(meshData.scale); + mShader->setUniformValue("modelMatrix", modelMatrix); // Bind the vertex array for the current mesh glBindVertexArray(meshData.vertexArrayObject); diff --git a/examples/common/example.vert b/examples/common/example.vert index 94d35f44..c0643e14 100644 --- a/examples/common/example.vert +++ b/examples/common/example.vert @@ -3,9 +3,9 @@ in vec4 position; // This will be the position of the vertex in model-space // The usual matrices are provided -uniform mat4 cameraToClipMatrix; -uniform mat4 worldToCameraMatrix; -uniform mat4 modelToWorldMatrix; +uniform mat4 projectionMatrix; +uniform mat4 viewMatrix; +uniform mat4 modelMatrix; // This will be used by the fragment shader to calculate flat-shaded normals. This is an unconventional approach // but we use it in this example framework because not all surface extractor generate surface normals. @@ -14,7 +14,7 @@ out vec4 worldPosition; void main() { // Standard sequence of OpenGL transformations. - worldPosition = modelToWorldMatrix * position; - vec4 cameraPosition = worldToCameraMatrix * worldPosition; - gl_Position = cameraToClipMatrix * cameraPosition; + worldPosition = modelMatrix * position; + vec4 cameraPosition = viewMatrix * worldPosition; + gl_Position = projectionMatrix * cameraPosition; } From d3b71a92b9d06c7a73ed5bf2f7aac524b44a2dd1 Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 24 Feb 2015 16:53:34 +0100 Subject: [PATCH 7/8] Tidying up code. --- examples/common/OpenGLWidget.cpp | 88 +++++++++++++++++--------------- examples/common/OpenGLWidget.h | 42 ++++++++------- examples/common/PolyVoxExample.h | 4 +- 3 files changed, 73 insertions(+), 61 deletions(-) diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.cpp index 3eb24fb6..2867d574 100644 --- a/examples/common/OpenGLWidget.cpp +++ b/examples/common/OpenGLWidget.cpp @@ -4,19 +4,28 @@ #include #include #include -//#include using namespace PolyVox; using namespace std; //////////////////////////////////////////////////////////////////////////////// -// Public functions +// Protected functions //////////////////////////////////////////////////////////////////////////////// OpenGLWidget::OpenGLWidget(QWidget *parent) :QGLWidget(parent) { } +const QMatrix4x4& OpenGLWidget::viewMatrix() +{ + return mViewMatrix; +} + +const QMatrix4x4& OpenGLWidget::projectionMatrix() +{ + return mProjectionMatrix; +} + void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw) { mCameraPosition = position; @@ -24,40 +33,8 @@ void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw mCameraPitch = pitch; } -void OpenGLWidget::mousePressEvent(QMouseEvent* event) -{ - // Initialise these variables which will be used when the mouse actually moves. - m_CurrentMousePos = event->pos(); - m_LastFrameMousePos = m_CurrentMousePos; -} - -void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) -{ - // Update the x and y rotations based on the mouse movement. - m_CurrentMousePos = event->pos(); - QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; - mCameraYaw -= diff.x() * mCameraRotateSpeed; - mCameraPitch -= diff.y() * mCameraRotateSpeed; - m_LastFrameMousePos = m_CurrentMousePos; -} - -void OpenGLWidget::keyPressEvent(QKeyEvent* event) -{ - if (event->key() == Qt::Key_Escape) - { - close(); - } - - mPressedKeys.append(event->key()); -} - -void OpenGLWidget::keyReleaseEvent(QKeyEvent* event) -{ - mPressedKeys.removeAll(event->key()); -} - //////////////////////////////////////////////////////////////////////////////// -// Protected functions +// Private functions //////////////////////////////////////////////////////////////////////////////// void OpenGLWidget::initializeGL() { @@ -106,9 +83,8 @@ void OpenGLWidget::resizeGL(int w, int h) float zNear = 1.0; float zFar = 1000.0; - projectionMatrix.setToIdentity(); - //projectionMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); - projectionMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar); + mProjectionMatrix.setToIdentity(); + mProjectionMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar); } void OpenGLWidget::paintGL() @@ -154,8 +130,8 @@ void OpenGLWidget::paintGL() mCameraPosition -= cameraRight * deltaTime * mCameraMoveSpeed; } - viewMatrix.setToIdentity(); - viewMatrix.lookAt( + mViewMatrix.setToIdentity(); + mViewMatrix.lookAt( mCameraPosition, // Camera is here mCameraPosition + cameraForward, // and looks here : at the same position, plus "direction" cameraUp // Head is up (set to 0,-1,0 to look upside-down) @@ -173,3 +149,35 @@ void OpenGLWidget::paintGL() std::cerr << "OpenGL Error: " << errCode << std::endl; } } + +void OpenGLWidget::mousePressEvent(QMouseEvent* event) +{ + // Initialise these variables which will be used when the mouse actually moves. + m_CurrentMousePos = event->pos(); + m_LastFrameMousePos = m_CurrentMousePos; +} + +void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) +{ + // Update the x and y rotations based on the mouse movement. + m_CurrentMousePos = event->pos(); + QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; + mCameraYaw -= diff.x() * mCameraRotateSpeed; + mCameraPitch -= diff.y() * mCameraRotateSpeed; + m_LastFrameMousePos = m_CurrentMousePos; +} + +void OpenGLWidget::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Escape) + { + close(); + } + + mPressedKeys.append(event->key()); +} + +void OpenGLWidget::keyReleaseEvent(QKeyEvent* event) +{ + mPressedKeys.removeAll(event->key()); +} \ No newline at end of file diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h index 8bbb3e1e..31d73244 100644 --- a/examples/common/OpenGLWidget.h +++ b/examples/common/OpenGLWidget.h @@ -34,17 +34,33 @@ distribution. #include #include -// 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. +// This is a very basic class for getting an OpenGL example up and running with Qt5. It simply displays +// an OpenGL widget and implements an FPS-style camera as well as other very basic functionality. User +// code can derive from this and override the provided virtual functions to implement functionality. class OpenGLWidget : public QGLWidget, protected QOpenGLFunctions_3_1 { -public: - // Constructor +protected: + // Protected constructor because this widget should not be created directly - it should only be subclassed. OpenGLWidget(QWidget *parent); + // Derived classes should override these to provide functionality. + virtual void initialize() {} + virtual void renderOneFrame() {} + + // Getters for properties defined by this widget. + const QMatrix4x4& viewMatrix(); + const QMatrix4x4& projectionMatrix(); + + // Setters for properties defined by this widget. void setCameraTransform(QVector3D position, float pitch, float yaw); +private: + + // Qt OpenGL functions + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); + // Mouse handling void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); @@ -53,21 +69,9 @@ public: void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); -protected: - - // Qt OpenGL functions - void initializeGL(); - void resizeGL(int w, int h); - void paintGL(); - - virtual void initialize() {} - virtual void renderOneFrame() {} - -protected: - // Matrices - QMatrix4x4 viewMatrix; - QMatrix4x4 projectionMatrix; + QMatrix4x4 mViewMatrix; + QMatrix4x4 mProjectionMatrix; // Mouse data QPoint m_LastFrameMousePos; diff --git a/examples/common/PolyVoxExample.h b/examples/common/PolyVoxExample.h index b80fe56b..2fcbadcb 100644 --- a/examples/common/PolyVoxExample.h +++ b/examples/common/PolyVoxExample.h @@ -163,8 +163,8 @@ protected: mShader->bind(); // These two matrices are constant for all meshes. - mShader->setUniformValue("viewMatrix", viewMatrix); - mShader->setUniformValue("projectionMatrix", projectionMatrix); + mShader->setUniformValue("viewMatrix", viewMatrix()); + mShader->setUniformValue("projectionMatrix", projectionMatrix()); // Iterate over each mesh which the user added to our list, and render it. for (OpenGLMeshData meshData : mMeshData) From e985dce075380228e9a519b140216708f79a7ed6 Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 24 Feb 2015 22:17:46 +0100 Subject: [PATCH 8/8] Templatized OpenGLWidget so users can specify the version of OpenGL to support. --- examples/Basic/CMakeLists.txt | 2 +- examples/DecodeOnGPU/CMakeLists.txt | 2 +- examples/OpenGL/CMakeLists.txt | 2 +- examples/Paging/CMakeLists.txt | 2 +- examples/SmoothLOD/CMakeLists.txt | 2 +- examples/common/OpenGLWidget.h | 6 +++- .../{OpenGLWidget.cpp => OpenGLWidget.inl} | 33 ++++++++++++------- examples/common/PolyVoxExample.h | 2 +- 8 files changed, 33 insertions(+), 18 deletions(-) rename examples/common/{OpenGLWidget.cpp => OpenGLWidget.inl} (78%) diff --git a/examples/Basic/CMakeLists.txt b/examples/Basic/CMakeLists.txt index 51156dc9..a7d74483 100644 --- a/examples/Basic/CMakeLists.txt +++ b/examples/Basic/CMakeLists.txt @@ -24,13 +24,13 @@ PROJECT(BasicExample) #Projects source files SET(SRC_FILES main.cpp - ../common/OpenGLWidget.cpp ../common/PolyVoxExample.cpp ) #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h + ../common/OpenGLWidget.inl ../common/PolyVoxExample.h ) diff --git a/examples/DecodeOnGPU/CMakeLists.txt b/examples/DecodeOnGPU/CMakeLists.txt index 063c2ffd..53fd6f94 100644 --- a/examples/DecodeOnGPU/CMakeLists.txt +++ b/examples/DecodeOnGPU/CMakeLists.txt @@ -24,13 +24,13 @@ PROJECT(DecodeOnGPUExample) #Projects source files SET(SRC_FILES main.cpp - ../common/OpenGLWidget.cpp ../common/PolyVoxExample.cpp ) #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h + ../common/OpenGLWidget.inl ../common/PolyVoxExample.h ) diff --git a/examples/OpenGL/CMakeLists.txt b/examples/OpenGL/CMakeLists.txt index c63ee818..994c2556 100644 --- a/examples/OpenGL/CMakeLists.txt +++ b/examples/OpenGL/CMakeLists.txt @@ -29,7 +29,6 @@ SET(SRC_FILES #OpenGLImmediateModeSupport.cpp #OpenGLSupport.cpp #OpenGLVertexBufferObjectSupport.cpp - ../common/OpenGLWidget.cpp ../common/PolyVoxExample.cpp Shapes.cpp ) @@ -40,6 +39,7 @@ SET(INC_FILES #OpenGLSupport.h #OpenGLVertexBufferObjectSupport.h ../common/OpenGLWidget.h + ../common/OpenGLWidget.inl ../common/PolyVoxExample.h Shapes.h ) diff --git a/examples/Paging/CMakeLists.txt b/examples/Paging/CMakeLists.txt index f5fffe89..060a4271 100644 --- a/examples/Paging/CMakeLists.txt +++ b/examples/Paging/CMakeLists.txt @@ -24,7 +24,6 @@ PROJECT(PagingExample) #Projects source files SET(SRC_FILES main.cpp - ../common/OpenGLWidget.cpp Perlin.cpp ../common/PolyVoxExample.cpp ) @@ -32,6 +31,7 @@ SET(SRC_FILES #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h + ../common/OpenGLWidget.inl Perlin.h ../common/PolyVoxExample.h ) diff --git a/examples/SmoothLOD/CMakeLists.txt b/examples/SmoothLOD/CMakeLists.txt index 492662bb..dbdad08a 100644 --- a/examples/SmoothLOD/CMakeLists.txt +++ b/examples/SmoothLOD/CMakeLists.txt @@ -24,13 +24,13 @@ PROJECT(SmoothLODExample) #Projects source files SET(SRC_FILES main.cpp - ../common/OpenGLWidget.cpp ../common/PolyVoxExample.cpp ) #Projects headers files SET(INC_FILES ../common/OpenGLWidget.h + ../common/OpenGLWidget.inl ../common/PolyVoxExample.h ) diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h index 31d73244..c2caadb1 100644 --- a/examples/common/OpenGLWidget.h +++ b/examples/common/OpenGLWidget.h @@ -37,7 +37,9 @@ distribution. // This is a very basic class for getting an OpenGL example up and running with Qt5. It simply displays // an OpenGL widget and implements an FPS-style camera as well as other very basic functionality. User // code can derive from this and override the provided virtual functions to implement functionality. -class OpenGLWidget : public QGLWidget, protected QOpenGLFunctions_3_1 +// The class is templatized so users can specify the OpenGL version via the appropriate QOpenGLFunctions. +template +class OpenGLWidget : public QGLWidget, protected QOpenGLFunctionsType { protected: // Protected constructor because this widget should not be created directly - it should only be subclassed. @@ -93,4 +95,6 @@ private: QElapsedTimer mElapsedTimer; }; +#include "OpenGLWidget.inl" + #endif //__BasicExample_OpenGLWidget_H__ diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.inl similarity index 78% rename from examples/common/OpenGLWidget.cpp rename to examples/common/OpenGLWidget.inl index 2867d574..2c7f1c78 100644 --- a/examples/common/OpenGLWidget.cpp +++ b/examples/common/OpenGLWidget.inl @@ -11,22 +11,26 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// // Protected functions //////////////////////////////////////////////////////////////////////////////// -OpenGLWidget::OpenGLWidget(QWidget *parent) +template +OpenGLWidget::OpenGLWidget(QWidget *parent) :QGLWidget(parent) { } -const QMatrix4x4& OpenGLWidget::viewMatrix() +template +const QMatrix4x4& OpenGLWidget::viewMatrix() { return mViewMatrix; } -const QMatrix4x4& OpenGLWidget::projectionMatrix() +template +const QMatrix4x4& OpenGLWidget::projectionMatrix() { return mProjectionMatrix; } -void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw) +template +void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw) { mCameraPosition = position; mCameraYaw = yaw; @@ -36,7 +40,8 @@ void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw //////////////////////////////////////////////////////////////////////////////// // Private functions //////////////////////////////////////////////////////////////////////////////// -void OpenGLWidget::initializeGL() +template +void OpenGLWidget::initializeGL() { if (!initializeOpenGLFunctions()) { @@ -74,7 +79,8 @@ void OpenGLWidget::initializeGL() mElapsedTimer.start(); } -void OpenGLWidget::resizeGL(int w, int h) +template +void OpenGLWidget::resizeGL(int w, int h) { //Setup the viewport glViewport(0, 0, w, h); @@ -87,7 +93,8 @@ void OpenGLWidget::resizeGL(int w, int h) mProjectionMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar); } -void OpenGLWidget::paintGL() +template +void OpenGLWidget::paintGL() { // Direction : Spherical coordinates to Cartesian coordinates conversion QVector3D cameraForward( @@ -150,14 +157,16 @@ void OpenGLWidget::paintGL() } } -void OpenGLWidget::mousePressEvent(QMouseEvent* event) +template +void OpenGLWidget::mousePressEvent(QMouseEvent* event) { // Initialise these variables which will be used when the mouse actually moves. m_CurrentMousePos = event->pos(); m_LastFrameMousePos = m_CurrentMousePos; } -void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) +template +void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) { // Update the x and y rotations based on the mouse movement. m_CurrentMousePos = event->pos(); @@ -167,7 +176,8 @@ void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) m_LastFrameMousePos = m_CurrentMousePos; } -void OpenGLWidget::keyPressEvent(QKeyEvent* event) +template +void OpenGLWidget::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Escape) { @@ -177,7 +187,8 @@ void OpenGLWidget::keyPressEvent(QKeyEvent* event) mPressedKeys.append(event->key()); } -void OpenGLWidget::keyReleaseEvent(QKeyEvent* event) +template +void OpenGLWidget::keyReleaseEvent(QKeyEvent* event) { mPressedKeys.removeAll(event->key()); } \ No newline at end of file diff --git a/examples/common/PolyVoxExample.h b/examples/common/PolyVoxExample.h index 2fcbadcb..65a77351 100644 --- a/examples/common/PolyVoxExample.h +++ b/examples/common/PolyVoxExample.h @@ -39,7 +39,7 @@ struct OpenGLMeshData float scale; }; -class PolyVoxExample : public OpenGLWidget +class PolyVoxExample : public OpenGLWidget { public: PolyVoxExample(QWidget *parent)