Merge branch 'feature/example-refactor' into develop
This commit is contained in:
commit
fbb7ff4728
@ -67,7 +67,7 @@ IF(ENABLE_EXAMPLES AND Qt5OpenGL_FOUND)
|
|||||||
ADD_SUBDIRECTORY(examples/Paging)
|
ADD_SUBDIRECTORY(examples/Paging)
|
||||||
ADD_SUBDIRECTORY(examples/OpenGL)
|
ADD_SUBDIRECTORY(examples/OpenGL)
|
||||||
ADD_SUBDIRECTORY(examples/SmoothLOD)
|
ADD_SUBDIRECTORY(examples/SmoothLOD)
|
||||||
#ADD_SUBDIRECTORY(examples/DecodeOnGPU)
|
ADD_SUBDIRECTORY(examples/DecodeOnGPU)
|
||||||
ADD_SUBDIRECTORY(examples/Python)
|
ADD_SUBDIRECTORY(examples/Python)
|
||||||
SET(BUILD_EXAMPLES ON)
|
SET(BUILD_EXAMPLES ON)
|
||||||
ELSE()
|
ELSE()
|
||||||
|
@ -24,12 +24,14 @@ PROJECT(BasicExample)
|
|||||||
#Projects source files
|
#Projects source files
|
||||||
SET(SRC_FILES
|
SET(SRC_FILES
|
||||||
main.cpp
|
main.cpp
|
||||||
../common/OpenGLWidget.cpp
|
../common/PolyVoxExample.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
#Projects headers files
|
#Projects headers files
|
||||||
SET(INC_FILES
|
SET(INC_FILES
|
||||||
../common/OpenGLWidget.h
|
../common/OpenGLWidget.h
|
||||||
|
../common/OpenGLWidget.inl
|
||||||
|
../common/PolyVoxExample.h
|
||||||
)
|
)
|
||||||
|
|
||||||
#"Sources" and "Headers" are the group names in Visual Studio.
|
#"Sources" and "Headers" are the group names in Visual Studio.
|
||||||
|
@ -21,7 +21,7 @@ freely, subject to the following restrictions:
|
|||||||
distribution.
|
distribution.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include "OpenGLWidget.h"
|
#include "PolyVoxExample.h"
|
||||||
|
|
||||||
#include "PolyVox/CubicSurfaceExtractor.h"
|
#include "PolyVox/CubicSurfaceExtractor.h"
|
||||||
#include "PolyVox/MarchingCubesSurfaceExtractor.h"
|
#include "PolyVox/MarchingCubesSurfaceExtractor.h"
|
||||||
@ -66,30 +66,43 @@ void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BasicExample : public PolyVoxExample
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BasicExample(QWidget *parent)
|
||||||
|
:PolyVoxExample(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initializeExample() override
|
||||||
|
{
|
||||||
|
// Create an empty volume and then place a sphere in it
|
||||||
|
PagedVolume<uint8_t> 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
|
||||||
|
addMesh(decodedMesh);
|
||||||
|
|
||||||
|
setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
//Create and show the Qt OpenGL window
|
//Create and show the Qt OpenGL window
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
OpenGLWidget openGLWidget(0);
|
BasicExample openGLWidget(0);
|
||||||
openGLWidget.show();
|
openGLWidget.show();
|
||||||
|
|
||||||
//Create an empty volume and then place a sphere in it
|
|
||||||
PagedVolume<uint8_t> 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
|
|
||||||
openGLWidget.addMesh(decodedMesh);
|
|
||||||
//openGLWidget.addMesh(mesh2);
|
|
||||||
openGLWidget.setViewableRegion(volData.getEnclosingRegion());
|
|
||||||
|
|
||||||
//Run the message pump.
|
//Run the message pump.
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
@ -24,12 +24,14 @@ PROJECT(DecodeOnGPUExample)
|
|||||||
#Projects source files
|
#Projects source files
|
||||||
SET(SRC_FILES
|
SET(SRC_FILES
|
||||||
main.cpp
|
main.cpp
|
||||||
../common/OpenGLWidget.cpp
|
../common/PolyVoxExample.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
#Projects headers files
|
#Projects headers files
|
||||||
SET(INC_FILES
|
SET(INC_FILES
|
||||||
../common/OpenGLWidget.h
|
../common/OpenGLWidget.h
|
||||||
|
../common/OpenGLWidget.inl
|
||||||
|
../common/PolyVoxExample.h
|
||||||
)
|
)
|
||||||
|
|
||||||
#"Sources" and "Headers" are the group names in Visual Studio.
|
#"Sources" and "Headers" are the group names in Visual Studio.
|
||||||
|
@ -4,9 +4,9 @@ in uvec4 position; // This will be the position of the vertex in model-space
|
|||||||
in uint normal;
|
in uint normal;
|
||||||
|
|
||||||
// The usual matrices are provided
|
// The usual matrices are provided
|
||||||
uniform mat4 cameraToClipMatrix;
|
uniform mat4 projectionMatrix;
|
||||||
uniform mat4 worldToCameraMatrix;
|
uniform mat4 viewMatrix;
|
||||||
uniform mat4 modelToWorldMatrix;
|
uniform mat4 modelMatrix;
|
||||||
|
|
||||||
// This will be used by the fragment shader to calculate flat-shaded normals. This is an unconventional approach
|
// 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.
|
// 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;
|
worldNormal.w = 1.0;
|
||||||
|
|
||||||
// Standard sequence of OpenGL transformations.
|
// Standard sequence of OpenGL transformations.
|
||||||
worldPosition = modelToWorldMatrix * decodedPosition;
|
worldPosition = modelMatrix * decodedPosition;
|
||||||
vec4 cameraPosition = worldToCameraMatrix * worldPosition;
|
vec4 cameraPosition = viewMatrix * worldPosition;
|
||||||
gl_Position = cameraToClipMatrix * cameraPosition;
|
gl_Position = projectionMatrix * cameraPosition;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ freely, subject to the following restrictions:
|
|||||||
distribution.
|
distribution.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include "OpenGLWidget.h"
|
#include "PolyVoxExample.h"
|
||||||
|
|
||||||
#include "PolyVox/CubicSurfaceExtractor.h"
|
#include "PolyVox/CubicSurfaceExtractor.h"
|
||||||
#include "PolyVox/MarchingCubesSurfaceExtractor.h"
|
#include "PolyVox/MarchingCubesSurfaceExtractor.h"
|
||||||
@ -66,102 +66,116 @@ void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f)
|
class DecodeOnGPUExample : public PolyVoxExample
|
||||||
{
|
{
|
||||||
// Convienient access to the vertices and indices
|
public:
|
||||||
const auto& vecIndices = surfaceMesh.getIndices();
|
DecodeOnGPUExample(QWidget *parent)
|
||||||
const auto& vecVertices = surfaceMesh.getVertices();
|
:PolyVoxExample(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// This struct holds the OpenGL properties (buffer handles, etc) which will be used
|
protected:
|
||||||
// to render our mesh. We copy the data from the PolyVox mesh into this structure.
|
void initializeExample() override
|
||||||
OpenGLMeshData meshData;
|
{
|
||||||
|
QSharedPointer<QGLShaderProgram> shader(new QGLShaderProgram);
|
||||||
|
|
||||||
// Create the VAO for the mesh
|
if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/decode.vert"))
|
||||||
glGenVertexArrays(1, &(meshData.vertexArrayObject));
|
{
|
||||||
glBindVertexArray(meshData.vertexArrayObject);
|
std::cerr << shader->log().toStdString() << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// The GL_ARRAY_BUFFER will contain the list of vertex positions
|
if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/decode.frag"))
|
||||||
glGenBuffers(1, &(meshData.vertexBuffer));
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer);
|
std::cerr << shader->log().toStdString() << std::endl;
|
||||||
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(MarchingCubesVertex< uint8_t >), vecVertices.data(), GL_STATIC_DRAW);
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// and GL_ELEMENT_ARRAY_BUFFER will contain the indices
|
setShader(shader);
|
||||||
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
|
//Create an empty volume and then place a sphere in it
|
||||||
glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions
|
PagedVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
|
||||||
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)
|
createSphereInVolume(volData, 30);
|
||||||
|
|
||||||
// Some surface extractors also generate normals, so tell OpenGL how these are laid out. If a surface extractor
|
// Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see.
|
||||||
// does not generate normals then nonsense values are written into the buffer here and sghould be ignored by the
|
//auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion());
|
||||||
// shader. This is mostly just to simplify this example code - in a real application you will know whether your
|
auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion());
|
||||||
// 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
|
// The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to
|
||||||
// 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.
|
// 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.
|
||||||
glEnableVertexAttribArray(2); //We're talking about shader attribute '2'
|
//auto decodedMesh = decodeMesh(mesh);
|
||||||
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.
|
//Pass the surface to the OpenGL window
|
||||||
glBindVertexArray(0);
|
OpenGLMeshData meshData = buildOpenGLMeshData(mesh);
|
||||||
|
addMeshData(meshData);
|
||||||
|
|
||||||
// A few additional properties can be copied across for use during rendering.
|
setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f));
|
||||||
meshData.noOfIndices = vecIndices.size();
|
}
|
||||||
meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ());
|
|
||||||
meshData.scale = scale;
|
|
||||||
|
|
||||||
// Set 16 or 32-bit index buffer size.
|
private:
|
||||||
meshData.indexType = sizeof(PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >::IndexType) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
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();
|
||||||
|
|
||||||
return 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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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)));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
return meshData;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
//Create and show the Qt OpenGL window
|
//Create and show the Qt OpenGL window
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
OpenGLWidget openGLWidget(0);
|
DecodeOnGPUExample openGLWidget(0);
|
||||||
openGLWidget.show();
|
openGLWidget.show();
|
||||||
|
|
||||||
QSharedPointer<QGLShaderProgram> 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<uint8_t> 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.
|
//Run the message pump.
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
@ -29,7 +29,7 @@ SET(SRC_FILES
|
|||||||
#OpenGLImmediateModeSupport.cpp
|
#OpenGLImmediateModeSupport.cpp
|
||||||
#OpenGLSupport.cpp
|
#OpenGLSupport.cpp
|
||||||
#OpenGLVertexBufferObjectSupport.cpp
|
#OpenGLVertexBufferObjectSupport.cpp
|
||||||
../common/OpenGLWidget.cpp
|
../common/PolyVoxExample.cpp
|
||||||
Shapes.cpp
|
Shapes.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,6 +39,8 @@ SET(INC_FILES
|
|||||||
#OpenGLSupport.h
|
#OpenGLSupport.h
|
||||||
#OpenGLVertexBufferObjectSupport.h
|
#OpenGLVertexBufferObjectSupport.h
|
||||||
../common/OpenGLWidget.h
|
../common/OpenGLWidget.h
|
||||||
|
../common/OpenGLWidget.inl
|
||||||
|
../common/PolyVoxExample.h
|
||||||
Shapes.h
|
Shapes.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ freely, subject to the following restrictions:
|
|||||||
|
|
||||||
#include "Shapes.h"
|
#include "Shapes.h"
|
||||||
|
|
||||||
#include "OpenGLWidget.h"
|
#include "PolyVoxExample.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <windows.h> // Standard Header For Most Programs
|
#include <windows.h> // Standard Header For Most Programs
|
||||||
@ -47,100 +47,110 @@ using namespace std;
|
|||||||
|
|
||||||
const int32_t g_uVolumeSideLength = 128;
|
const int32_t g_uVolumeSideLength = 128;
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
class OpenGLExample : public PolyVoxExample
|
||||||
{
|
{
|
||||||
FilePager<MaterialDensityPair88>* pager = new FilePager<MaterialDensityPair88>(".");
|
public:
|
||||||
PagedVolume<MaterialDensityPair88> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(g_uVolumeSideLength - 1, g_uVolumeSideLength - 1, g_uVolumeSideLength - 1)), pager);
|
OpenGLExample(QWidget *parent)
|
||||||
|
:PolyVoxExample(parent)
|
||||||
//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<QGLShaderProgram> shader(new QGLShaderProgram);
|
|
||||||
|
|
||||||
if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/openglexample.vert"))
|
|
||||||
{
|
{
|
||||||
std::cerr << shader->log().toStdString() << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/openglexample.frag"))
|
protected:
|
||||||
|
void initializeExample() override
|
||||||
{
|
{
|
||||||
std::cerr << shader->log().toStdString() << std::endl;
|
FilePager<MaterialDensityPair88>* pager = new FilePager<MaterialDensityPair88>(".");
|
||||||
exit(EXIT_FAILURE);
|
PagedVolume<MaterialDensityPair88> 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;
|
cout << "Creating sphere 1" << std::endl;
|
||||||
time.start();
|
createSphereInVolume(volData, 60.0f, 5);
|
||||||
//openGLWidget.setVolume(&volData);
|
cout << "Creating sphere 2" << std::endl;
|
||||||
cout << endl << "Time taken = " << time.elapsed() / 1000.0f << "s" << endl << 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;
|
cout << "Creating cubes" << std::endl;
|
||||||
int meshCounter = 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);
|
||||||
|
|
||||||
for (int32_t z = 0; z < volData.getDepth(); z += 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());
|
||||||
for (int32_t y = 0; y < volData.getHeight(); y += extractedRegionSize)
|
createCubeInVolume(volData, Vector3DInt32(midPos - 10, midPos - 10, 1), Vector3DInt32(midPos + 10, midPos + 10, maxPos - 1), MaterialDensityPair44::getMaxDensity());
|
||||||
|
|
||||||
|
QSharedPointer<QGLShaderProgram> 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.
|
for (int32_t x = 0; x < volData.getWidth(); x += extractedRegionSize)
|
||||||
PolyVox::Region regToExtract(x, y, z, x + extractedRegionSize, y + extractedRegionSize, z + 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.
|
// If you uncomment this line you will be able to see that the volume is rendered as multiple seperate meshes.
|
||||||
//regToExtract.shrink(1);
|
//regToExtract.shrink(1);
|
||||||
|
|
||||||
// Perform the extraction for this region of the volume
|
// Perform the extraction for this region of the volume
|
||||||
auto mesh = extractMarchingCubesMesh(&volData, regToExtract);
|
auto mesh = extractMarchingCubesMesh(&volData, regToExtract);
|
||||||
|
|
||||||
// The returned mesh needs to be decoded to be appropriate for GPU rendering.
|
// The returned mesh needs to be decoded to be appropriate for GPU rendering.
|
||||||
auto decodedMesh = decodeMesh(mesh);
|
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
|
// 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.
|
// the surface extractors return a mesh with 'local space' positions to reduce storage requirements and precision problems.
|
||||||
openGLWidget.addMesh(decodedMesh, decodedMesh.getOffset());
|
addMesh(decodedMesh, decodedMesh.getOffset());
|
||||||
|
|
||||||
meshCounter++;
|
meshCounter++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cout << "Rendering volume as " << meshCounter << " seperate meshes" << endl;
|
||||||
|
|
||||||
|
setCameraTransform(QVector3D(150.0f, 150.0f, 150.0f), -(PI / 4.0f), PI + (PI / 4.0f));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
cout << "Rendering volume as " << meshCounter << " seperate meshes" << endl;
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
//Create and show the Qt OpenGL window
|
||||||
openGLWidget.setViewableRegion(volData.getEnclosingRegion());
|
QApplication app(argc, argv);
|
||||||
|
OpenGLExample openGLWidget(0);
|
||||||
|
openGLWidget.show();
|
||||||
|
|
||||||
|
//Run the message pump.
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
@ -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 vec4 normal; // The normal data may not have been set
|
||||||
in ivec2 material;
|
in ivec2 material;
|
||||||
|
|
||||||
uniform mat4 cameraToClipMatrix;
|
uniform mat4 projectionMatrix;
|
||||||
uniform mat4 worldToCameraMatrix;
|
uniform mat4 viewMatrix;
|
||||||
uniform mat4 modelToWorldMatrix;
|
uniform mat4 modelMatrix;
|
||||||
|
|
||||||
out vec4 worldPosition; //This is being passed to the fragment shader to calculate the normals
|
out vec4 worldPosition; //This is being passed to the fragment shader to calculate the normals
|
||||||
out vec3 normalFromVS;
|
out vec3 normalFromVS;
|
||||||
@ -15,7 +15,7 @@ flat out ivec2 materialFromVS;
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// Compute the usual OpenGL transformation to clip space.
|
// 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
|
// 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.
|
// just pass them through, though real code might want to deal with transforming normals appropriatly.
|
||||||
|
@ -24,14 +24,16 @@ PROJECT(PagingExample)
|
|||||||
#Projects source files
|
#Projects source files
|
||||||
SET(SRC_FILES
|
SET(SRC_FILES
|
||||||
main.cpp
|
main.cpp
|
||||||
../common/OpenGLWidget.cpp
|
|
||||||
Perlin.cpp
|
Perlin.cpp
|
||||||
|
../common/PolyVoxExample.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
#Projects headers files
|
#Projects headers files
|
||||||
SET(INC_FILES
|
SET(INC_FILES
|
||||||
../common/OpenGLWidget.h
|
../common/OpenGLWidget.h
|
||||||
|
../common/OpenGLWidget.inl
|
||||||
Perlin.h
|
Perlin.h
|
||||||
|
../common/PolyVoxExample.h
|
||||||
)
|
)
|
||||||
|
|
||||||
#"Sources" and "Headers" are the group names in Visual Studio.
|
#"Sources" and "Headers" are the group names in Visual Studio.
|
||||||
|
@ -21,7 +21,7 @@ freely, subject to the following restrictions:
|
|||||||
distribution.
|
distribution.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include "OpenGLWidget.h"
|
#include "PolyVoxExample.h"
|
||||||
#include "Perlin.h"
|
#include "Perlin.h"
|
||||||
|
|
||||||
#include "PolyVox/MaterialDensityPair.h"
|
#include "PolyVox/MaterialDensityPair.h"
|
||||||
@ -139,48 +139,61 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PagingExample : public PolyVoxExample
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PagingExample(QWidget *parent)
|
||||||
|
:PolyVoxExample(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initializeExample() override
|
||||||
|
{
|
||||||
|
PerlinNoisePager* pager = new PerlinNoisePager();
|
||||||
|
PagedVolume<MaterialDensityPair44> 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);
|
||||||
|
|
||||||
|
setCameraTransform(QVector3D(300.0f, 300.0f, 300.0f), -(PI / 4.0f), PI + (PI / 4.0f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
//Create and show the Qt OpenGL window
|
//Create and show the Qt OpenGL window
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
OpenGLWidget openGLWidget(0);
|
PagingExample openGLWidget(0);
|
||||||
openGLWidget.show();
|
openGLWidget.show();
|
||||||
|
|
||||||
PerlinNoisePager* pager = new PerlinNoisePager();
|
|
||||||
PagedVolume<MaterialDensityPair44> 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.
|
//Run the message pump.
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
@ -127,17 +127,17 @@ def run():
|
|||||||
in vec4 position;
|
in vec4 position;
|
||||||
in vec4 normal;
|
in vec4 normal;
|
||||||
|
|
||||||
uniform mat4 cameraToClipMatrix;
|
uniform mat4 projectionMatrix;
|
||||||
uniform mat4 worldToCameraMatrix;
|
uniform mat4 viewMatrix;
|
||||||
uniform mat4 modelToWorldMatrix;
|
uniform mat4 modelMatrix;
|
||||||
|
|
||||||
flat out float theColor;
|
flat out float theColor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 temp = modelToWorldMatrix * position;
|
vec4 temp = modelMatrix * position;
|
||||||
temp = worldToCameraMatrix * temp;
|
temp = viewMatrix * temp;
|
||||||
gl_Position = cameraToClipMatrix * temp;
|
gl_Position = projectionMatrix * temp;
|
||||||
|
|
||||||
theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1);
|
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)
|
glDisableVertexAttribArray(0)
|
||||||
|
|
||||||
#Now grab out transformation martix locations
|
#Now grab out transformation martix locations
|
||||||
modelToWorldMatrixUnif = glGetUniformLocation(shader, b"modelToWorldMatrix")
|
modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix")
|
||||||
worldToCameraMatrixUnif = glGetUniformLocation(shader, b"worldToCameraMatrix")
|
viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix")
|
||||||
cameraToClipMatrixUnif = glGetUniformLocation(shader, b"cameraToClipMatrix")
|
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')
|
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')
|
||||||
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')
|
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')
|
||||||
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')
|
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
|
#These next few lines just set up our camera frustum
|
||||||
fovDeg = 45.0
|
fovDeg = 45.0
|
||||||
@ -198,16 +198,16 @@ def run():
|
|||||||
zNear = 1.0
|
zNear = 1.0
|
||||||
zFar = 1000.0
|
zFar = 1000.0
|
||||||
|
|
||||||
cameraToClipMatrix[0][0] = frustumScale
|
projectionMatrix[0][0] = frustumScale
|
||||||
cameraToClipMatrix[1][1] = frustumScale
|
projectionMatrix[1][1] = frustumScale
|
||||||
cameraToClipMatrix[2][2] = (zFar + zNear) / (zNear - zFar)
|
projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar)
|
||||||
cameraToClipMatrix[2][3] = -1.0
|
projectionMatrix[2][3] = -1.0
|
||||||
cameraToClipMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar)
|
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:
|
with shader:
|
||||||
glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_TRUE, cameraToClipMatrix)
|
glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix)
|
||||||
glUniformMatrix4fv(worldToCameraMatrixUnif, 1, GL_TRUE, worldToCameraMatrix)
|
glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix)
|
||||||
|
|
||||||
#These are used to track the rotation of the volume
|
#These are used to track the rotation of the volume
|
||||||
LastFrameMousePos = (0,0)
|
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')
|
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')
|
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:
|
with shader:
|
||||||
glUniformMatrix4fv(modelToWorldMatrixUnif, 1, GL_TRUE, modelToWorldMatrix)
|
glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix)
|
||||||
glBindVertexArray(vertexArrayObject)
|
glBindVertexArray(vertexArrayObject)
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
|
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
|
||||||
|
@ -24,12 +24,14 @@ PROJECT(SmoothLODExample)
|
|||||||
#Projects source files
|
#Projects source files
|
||||||
SET(SRC_FILES
|
SET(SRC_FILES
|
||||||
main.cpp
|
main.cpp
|
||||||
../common/OpenGLWidget.cpp
|
../common/PolyVoxExample.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
#Projects headers files
|
#Projects headers files
|
||||||
SET(INC_FILES
|
SET(INC_FILES
|
||||||
../common/OpenGLWidget.h
|
../common/OpenGLWidget.h
|
||||||
|
../common/OpenGLWidget.inl
|
||||||
|
../common/PolyVoxExample.h
|
||||||
)
|
)
|
||||||
|
|
||||||
#"Sources" and "Headers" are the group names in Visual Studio.
|
#"Sources" and "Headers" are the group names in Visual Studio.
|
||||||
|
@ -21,7 +21,7 @@ freely, subject to the following restrictions:
|
|||||||
distribution.
|
distribution.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include "OpenGLWidget.h"
|
#include "PolyVoxExample.h"
|
||||||
|
|
||||||
#include "PolyVox/Density.h"
|
#include "PolyVox/Density.h"
|
||||||
#include "PolyVox/MarchingCubesSurfaceExtractor.h"
|
#include "PolyVox/MarchingCubesSurfaceExtractor.h"
|
||||||
@ -68,43 +68,56 @@ void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SmoothLODExample : public PolyVoxExample
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SmoothLODExample(QWidget *parent)
|
||||||
|
:PolyVoxExample(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initializeExample() override
|
||||||
|
{
|
||||||
|
//Create an empty volume and then place a sphere in it
|
||||||
|
PagedVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
|
||||||
|
createSphereInVolume(volData, 28);
|
||||||
|
|
||||||
|
//Smooth the data - should reimplement this using LowPassFilter
|
||||||
|
//smoothRegion<PagedVolume, Density8>(volData, volData.getEnclosingRegion());
|
||||||
|
//smoothRegion<PagedVolume, Density8>(volData, volData.getEnclosingRegion());
|
||||||
|
//smoothRegion<PagedVolume, Density8>(volData, volData.getEnclosingRegion());
|
||||||
|
|
||||||
|
RawVolume<uint8_t> volDataLowLOD(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(15, 31, 31)));
|
||||||
|
|
||||||
|
VolumeResampler< PagedVolume<uint8_t>, RawVolume<uint8_t> > 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);
|
||||||
|
|
||||||
|
setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
//Create and show the Qt OpenGL window
|
//Create and show the Qt OpenGL window
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
OpenGLWidget openGLWidget(0);
|
SmoothLODExample openGLWidget(0);
|
||||||
openGLWidget.show();
|
openGLWidget.show();
|
||||||
|
|
||||||
//Create an empty volume and then place a sphere in it
|
|
||||||
PagedVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
|
|
||||||
createSphereInVolume(volData, 28);
|
|
||||||
|
|
||||||
//Smooth the data - should reimplement this using LowPassFilter
|
|
||||||
//smoothRegion<PagedVolume, Density8>(volData, volData.getEnclosingRegion());
|
|
||||||
//smoothRegion<PagedVolume, Density8>(volData, volData.getEnclosingRegion());
|
|
||||||
//smoothRegion<PagedVolume, Density8>(volData, volData.getEnclosingRegion());
|
|
||||||
|
|
||||||
RawVolume<uint8_t> volDataLowLOD(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(15, 31, 31)));
|
|
||||||
|
|
||||||
VolumeResampler< PagedVolume<uint8_t>, RawVolume<uint8_t> > 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.
|
//Run the message pump.
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
#include "OpenGLWidget.h"
|
|
||||||
|
|
||||||
#include <QMouseEvent>
|
|
||||||
#include <QMatrix4x4>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
//#include <QtMath>
|
|
||||||
|
|
||||||
using namespace PolyVox;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public functions
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
OpenGLWidget::OpenGLWidget(QWidget *parent)
|
|
||||||
:QGLWidget(parent)
|
|
||||||
,m_viewableRegion(PolyVox::Region(0, 0, 0, 255, 255, 255))
|
|
||||||
,m_xRotation(0)
|
|
||||||
,m_yRotation(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWidget::setShader(QSharedPointer<QGLShaderProgram> shader)
|
|
||||||
{
|
|
||||||
mShader = shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWidget::setViewableRegion(PolyVox::Region viewableRegion)
|
|
||||||
{
|
|
||||||
m_viewableRegion = viewableRegion;
|
|
||||||
|
|
||||||
// The user has specifed a new viewable region
|
|
||||||
// so we need to regenerate our camera matrix.
|
|
||||||
setupWorldToCameraMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
m_xRotation += diff.x();
|
|
||||||
m_yRotation += diff.y();
|
|
||||||
m_LastFrameMousePos = m_CurrentMousePos;
|
|
||||||
|
|
||||||
// The camera rotation has changed so we need to regenerate the matrix.
|
|
||||||
setupWorldToCameraMatrix();
|
|
||||||
|
|
||||||
// Re-render.
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Protected functions
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void OpenGLWidget::initializeGL()
|
|
||||||
{
|
|
||||||
if (!initializeOpenGLFunctions())
|
|
||||||
{
|
|
||||||
std::cerr << "Could not initialize OpenGL functions" << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Print out some information about the OpenGL implementation.
|
|
||||||
std::cout << "OpenGL Implementation Details:" << std::endl;
|
|
||||||
if(glGetString(GL_VENDOR))
|
|
||||||
std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
|
|
||||||
if(glGetString(GL_RENDERER))
|
|
||||||
std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
|
|
||||||
if(glGetString(GL_VERSION))
|
|
||||||
std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl;
|
|
||||||
if(glGetString(GL_SHADING_LANGUAGE_VERSION))
|
|
||||||
std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
|
|
||||||
|
|
||||||
//Set up the clear colour
|
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
||||||
glClearDepth(1.0f);
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
|
||||||
glDepthRange(0.0, 1.0);
|
|
||||||
|
|
||||||
mShader = QSharedPointer<QGLShaderProgram>(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial setup of camera.
|
|
||||||
setupWorldToCameraMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWidget::resizeGL(int w, int h)
|
|
||||||
{
|
|
||||||
//Setup the viewport
|
|
||||||
glViewport(0, 0, w, h);
|
|
||||||
|
|
||||||
auto aspectRatio = w / (float)h;
|
|
||||||
float zNear = 1.0;
|
|
||||||
float zFar = 1000.0;
|
|
||||||
|
|
||||||
cameraToClipMatrix.setToIdentity();
|
|
||||||
cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
// Check for errors.
|
|
||||||
GLenum errCode = glGetError();
|
|
||||||
if(errCode != GL_NO_ERROR)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
@ -28,135 +28,73 @@ distribution.
|
|||||||
|
|
||||||
#include <QOpenGLFunctions_3_1>
|
#include <QOpenGLFunctions_3_1>
|
||||||
|
|
||||||
|
#include <QElapsedTimer>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
#include <QGLShaderProgram>
|
#include <QGLShaderProgram>
|
||||||
#include <QOpenGLVertexArrayObject>
|
#include <QOpenGLVertexArrayObject>
|
||||||
#include <QOpenGLBuffer>
|
#include <QOpenGLBuffer>
|
||||||
|
|
||||||
// This structure holds all the data required
|
// This is a very basic class for getting an OpenGL example up and running with Qt5. It simply displays
|
||||||
// to render one of our meshes through OpenGL.
|
// an OpenGL widget and implements an FPS-style camera as well as other very basic functionality. User
|
||||||
struct OpenGLMeshData
|
// code can derive from this and override the provided virtual functions to implement functionality.
|
||||||
|
// The class is templatized so users can specify the OpenGL version via the appropriate QOpenGLFunctions.
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
class OpenGLWidget : public QGLWidget, protected QOpenGLFunctionsType
|
||||||
{
|
{
|
||||||
GLuint noOfIndices;
|
protected:
|
||||||
GLenum indexType;
|
// Protected constructor because this widget should not be created directly - it should only be subclassed.
|
||||||
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.
|
|
||||||
class OpenGLWidget : public QGLWidget, protected QOpenGLFunctions_3_1
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Constructor
|
|
||||||
OpenGLWidget(QWidget *parent);
|
OpenGLWidget(QWidget *parent);
|
||||||
|
|
||||||
// Convert a PolyVox mesh to OpenGL index/vertex buffers. Inlined because it's templatised.
|
// Derived classes should override these to provide functionality.
|
||||||
template <typename MeshType>
|
virtual void initialize() {}
|
||||||
void addMesh(const MeshType& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f)
|
virtual void renderOneFrame() {}
|
||||||
{
|
|
||||||
// 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
|
// Getters for properties defined by this widget.
|
||||||
// to render our mesh. We copy the data from the PolyVox mesh into this structure.
|
const QMatrix4x4& viewMatrix();
|
||||||
OpenGLMeshData meshData;
|
const QMatrix4x4& projectionMatrix();
|
||||||
|
|
||||||
// Create the VAO for the mesh
|
// Setters for properties defined by this widget.
|
||||||
glGenVertexArrays(1, &(meshData.vertexArrayObject));
|
void setCameraTransform(QVector3D position, float pitch, float yaw);
|
||||||
glBindVertexArray(meshData.vertexArrayObject);
|
|
||||||
|
|
||||||
// The GL_ARRAY_BUFFER will contain the list of vertex positions
|
private:
|
||||||
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<QGLShaderProgram> shader);
|
|
||||||
|
|
||||||
// The viewable region can be adjusted so that this example framework can be used for different volume sizes.
|
|
||||||
void setViewableRegion(PolyVox::Region viewableRegion);
|
|
||||||
|
|
||||||
// Mouse handling
|
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
|
||||||
void mousePressEvent(QMouseEvent* event);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// Qt OpenGL functions
|
// Qt OpenGL functions
|
||||||
void initializeGL();
|
void initializeGL();
|
||||||
void resizeGL(int w, int h);
|
void resizeGL(int w, int h);
|
||||||
void paintGL();
|
void paintGL();
|
||||||
|
|
||||||
private:
|
// Mouse handling
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
|
||||||
void setupWorldToCameraMatrix();
|
// Keyboard handling
|
||||||
|
void keyPressEvent(QKeyEvent* event);
|
||||||
// Index/vertex buffer data
|
void keyReleaseEvent(QKeyEvent* event);
|
||||||
std::vector<OpenGLMeshData> mMeshData;
|
|
||||||
|
|
||||||
QSharedPointer<QGLShaderProgram> mShader;
|
|
||||||
|
|
||||||
// Matrices
|
// Matrices
|
||||||
QMatrix4x4 worldToCameraMatrix;
|
QMatrix4x4 mViewMatrix;
|
||||||
QMatrix4x4 cameraToClipMatrix;
|
QMatrix4x4 mProjectionMatrix;
|
||||||
|
|
||||||
// Mouse data
|
// Mouse data
|
||||||
QPoint m_LastFrameMousePos;
|
QPoint m_LastFrameMousePos;
|
||||||
QPoint m_CurrentMousePos;
|
QPoint m_CurrentMousePos;
|
||||||
|
|
||||||
// Camera setup
|
// Keyboard data
|
||||||
PolyVox::Region m_viewableRegion;
|
QList<int> mPressedKeys;
|
||||||
int m_xRotation;
|
|
||||||
int m_yRotation;
|
// 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "OpenGLWidget.inl"
|
||||||
|
|
||||||
#endif //__BasicExample_OpenGLWidget_H__
|
#endif //__BasicExample_OpenGLWidget_H__
|
||||||
|
194
examples/common/OpenGLWidget.inl
Normal file
194
examples/common/OpenGLWidget.inl
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#include "OpenGLWidget.h"
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
using namespace PolyVox;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Protected functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
OpenGLWidget<QOpenGLFunctionsType>::OpenGLWidget(QWidget *parent)
|
||||||
|
:QGLWidget(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
const QMatrix4x4& OpenGLWidget<QOpenGLFunctionsType>::viewMatrix()
|
||||||
|
{
|
||||||
|
return mViewMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
const QMatrix4x4& OpenGLWidget<QOpenGLFunctionsType>::projectionMatrix()
|
||||||
|
{
|
||||||
|
return mProjectionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::setCameraTransform(QVector3D position, float pitch, float yaw)
|
||||||
|
{
|
||||||
|
mCameraPosition = position;
|
||||||
|
mCameraYaw = yaw;
|
||||||
|
mCameraPitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::initializeGL()
|
||||||
|
{
|
||||||
|
if (!initializeOpenGLFunctions())
|
||||||
|
{
|
||||||
|
std::cerr << "Could not initialize OpenGL functions" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Print out some information about the OpenGL implementation.
|
||||||
|
std::cout << "OpenGL Implementation Details:" << std::endl;
|
||||||
|
if(glGetString(GL_VENDOR))
|
||||||
|
std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
|
||||||
|
if(glGetString(GL_RENDERER))
|
||||||
|
std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
|
||||||
|
if(glGetString(GL_VERSION))
|
||||||
|
std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl;
|
||||||
|
if(glGetString(GL_SHADING_LANGUAGE_VERSION))
|
||||||
|
std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
|
||||||
|
|
||||||
|
//Set up the clear colour
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
glClearDepth(1.0f);
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glDepthRange(0.0, 1.0);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::resizeGL(int w, int h)
|
||||||
|
{
|
||||||
|
//Setup the viewport
|
||||||
|
glViewport(0, 0, w, h);
|
||||||
|
|
||||||
|
auto aspectRatio = w / (float)h;
|
||||||
|
float zNear = 1.0;
|
||||||
|
float zFar = 1000.0;
|
||||||
|
|
||||||
|
mProjectionMatrix.setToIdentity();
|
||||||
|
mProjectionMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
|
//Clear the screen
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
renderOneFrame();
|
||||||
|
|
||||||
|
// Check for errors.
|
||||||
|
GLenum errCode = glGetError();
|
||||||
|
if(errCode != GL_NO_ERROR)
|
||||||
|
{
|
||||||
|
std::cerr << "OpenGL Error: " << errCode << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
// Initialise these variables which will be used when the mouse actually moves.
|
||||||
|
m_CurrentMousePos = event->pos();
|
||||||
|
m_LastFrameMousePos = m_CurrentMousePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::keyPressEvent(QKeyEvent* event)
|
||||||
|
{
|
||||||
|
if (event->key() == Qt::Key_Escape)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
mPressedKeys.append(event->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename QOpenGLFunctionsType>
|
||||||
|
void OpenGLWidget<QOpenGLFunctionsType>::keyReleaseEvent(QKeyEvent* event)
|
||||||
|
{
|
||||||
|
mPressedKeys.removeAll(event->key());
|
||||||
|
}
|
6
examples/common/PolyVoxExample.cpp
Normal file
6
examples/common/PolyVoxExample.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "PolyVoxExample.h"
|
||||||
|
|
||||||
|
void PolyVoxExample::setShader(QSharedPointer<QGLShaderProgram> shader)
|
||||||
|
{
|
||||||
|
mShader = shader;
|
||||||
|
}
|
197
examples/common/PolyVoxExample.h
Normal file
197
examples/common/PolyVoxExample.h
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
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"
|
||||||
|
|
||||||
|
// 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<QOpenGLFunctions_3_1>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PolyVoxExample(QWidget *parent)
|
||||||
|
: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<QGLShaderProgram> shader);
|
||||||
|
|
||||||
|
// Convert a PolyVox mesh to OpenGL index/vertex buffers. Inlined because it's templatised.
|
||||||
|
template <typename MeshType>
|
||||||
|
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<QGLShaderProgram>(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("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 modelMatrix;
|
||||||
|
modelMatrix.translate(meshData.translation);
|
||||||
|
modelMatrix.scale(meshData.scale);
|
||||||
|
mShader->setUniformValue("modelMatrix", modelMatrix);
|
||||||
|
|
||||||
|
// 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<OpenGLMeshData> mMeshData;
|
||||||
|
|
||||||
|
QSharedPointer<QGLShaderProgram> mShader;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__PolyVoxExample_H__
|
@ -3,9 +3,9 @@
|
|||||||
in vec4 position; // This will be the position of the vertex in model-space
|
in vec4 position; // This will be the position of the vertex in model-space
|
||||||
|
|
||||||
// The usual matrices are provided
|
// The usual matrices are provided
|
||||||
uniform mat4 cameraToClipMatrix;
|
uniform mat4 projectionMatrix;
|
||||||
uniform mat4 worldToCameraMatrix;
|
uniform mat4 viewMatrix;
|
||||||
uniform mat4 modelToWorldMatrix;
|
uniform mat4 modelMatrix;
|
||||||
|
|
||||||
// This will be used by the fragment shader to calculate flat-shaded normals. This is an unconventional approach
|
// 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.
|
// 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()
|
void main()
|
||||||
{
|
{
|
||||||
// Standard sequence of OpenGL transformations.
|
// Standard sequence of OpenGL transformations.
|
||||||
worldPosition = modelToWorldMatrix * position;
|
worldPosition = modelMatrix * position;
|
||||||
vec4 cameraPosition = worldToCameraMatrix * worldPosition;
|
vec4 cameraPosition = viewMatrix * worldPosition;
|
||||||
gl_Position = cameraToClipMatrix * cameraPosition;
|
gl_Position = projectionMatrix * cameraPosition;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user