Update the BasicExample to use OpenGL 3

The example now uses OpenGL 3 features like Vertex Array Objects and uses
no immediate mode stuff. Qt5 is used for some features like matrices and
shaders.

There is now no dependency on GLEW either.
This commit is contained in:
Matt Williams 2014-03-19 21:26:04 +00:00
parent 868fbb84a0
commit ac16dfd325
4 changed files with 158 additions and 102 deletions

View File

@ -32,17 +32,13 @@ SET(INC_FILES
OpenGLWidget.h OpenGLWidget.h
) )
add_definitions(-DGLEW_STATIC)
#"Sources" and "Headers" are the group names in Visual Studio. #"Sources" and "Headers" are the group names in Visual Studio.
#They may have other uses too... #They may have other uses too...
SOURCE_GROUP("Sources" FILES ${SRC_FILES}) SOURCE_GROUP("Sources" FILES ${SRC_FILES})
SOURCE_GROUP("Headers" FILES ${INC_FILES}) SOURCE_GROUP("Headers" FILES ${INC_FILES})
FIND_PACKAGE(OpenGL REQUIRED)
#Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location) #Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${GLEW_SOURCE_DIR}) INCLUDE_DIRECTORIES(${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include)
LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR}) LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR})
#Build #Build
@ -50,7 +46,7 @@ ADD_EXECUTABLE(BasicExample ${SRC_FILES})
IF(MSVC) IF(MSVC)
SET_TARGET_PROPERTIES(BasicExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127") SET_TARGET_PROPERTIES(BasicExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127")
ENDIF(MSVC) ENDIF(MSVC)
TARGET_LINK_LIBRARIES(BasicExample glew Qt5::OpenGL ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore) TARGET_LINK_LIBRARIES(BasicExample Qt5::OpenGL PolyVoxCore)
SET_PROPERTY(TARGET BasicExample PROPERTY FOLDER "Examples") SET_PROPERTY(TARGET BasicExample PROPERTY FOLDER "Examples")
#Install - Only install the example in Windows #Install - Only install the example in Windows

View File

@ -1,6 +1,8 @@
#include "OpenGLWidget.h" #include "OpenGLWidget.h"
#include <QMouseEvent> #include <QMouseEvent>
#include <QMatrix4x4>
#include <QtMath>
using namespace PolyVox; using namespace PolyVox;
using namespace std; using namespace std;
@ -9,126 +11,179 @@ OpenGLWidget::OpenGLWidget(QWidget *parent)
:QGLWidget(parent) :QGLWidget(parent)
,m_xRotation(0) ,m_xRotation(0)
,m_yRotation(0) ,m_yRotation(0)
,gl(nullptr)
{ {
} }
void OpenGLWidget::setSurfaceMeshToRender(const PolyVox::SurfaceMesh<PositionMaterialNormal>& surfaceMesh) void OpenGLWidget::setSurfaceMeshToRender(const PolyVox::SurfaceMesh<PositionMaterial>& surfaceMesh)
{ {
//Convienient access to the vertices and indices //Convienient access to the vertices and indices
const vector<uint32_t>& vecIndices = surfaceMesh.getIndices(); const auto& vecIndices = surfaceMesh.getIndices();
const vector<PositionMaterialNormal>& vecVertices = surfaceMesh.getVertices(); const auto& vecVertices = surfaceMesh.getVertices();
//Build an OpenGL index buffer //Create the VAO for the mesh
glGenBuffers(1, &indexBuffer); gl->glGenVertexArrays(1, &vertexArrayObject);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); gl->glBindVertexArray(vertexArrayObject);
const GLvoid* pIndices = static_cast<const GLvoid*>(&(vecIndices[0]));
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW); //The GL_ARRAY_BUFFER will contain the list of vertex positions
gl->glGenBuffers(1, &vertexBuffer);
//Build an OpenGL vertex buffer gl->glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glGenBuffers(1, &vertexBuffer); gl->glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(PositionMaterial), vecVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
const GLvoid* pVertices = static_cast<const GLvoid*>(&(vecVertices[0])); //and GL_ELEMENT_ARRAY_BUFFER will contain the indices
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(PositionMaterialNormal), pVertices, GL_STATIC_DRAW); gl->glGenBuffers(1, &indexBuffer);
gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
m_uBeginIndex = 0; gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), vecIndices.data(), GL_STATIC_DRAW);
m_uEndIndex = vecIndices.size();
//We need to tell OpenGL how to understand the format of the vertex data
gl->glEnableVertexAttribArray(0); //We're talking about shader attribute '0'
gl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(PositionMaterial), 0); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type)
gl->glBindVertexArray(0);
noOfIndices = vecIndices.size(); //Save this for the call to glDrawElements later
} }
void OpenGLWidget::initializeGL() void OpenGLWidget::initializeGL()
{ {
//We need GLEW to access recent OpenGL functionality //'gl' will give us access to all the OpenGL functions
std::cout << "Initialising GLEW..."; gl = context()->contextHandle()->versionFunctions<QOpenGLFunctions_3_1>();
GLenum result = glewInit(); if(!gl)
if (result == GLEW_OK)
{ {
std::cout << "success" << std::endl; std::cerr << "Could not obtain required OpenGL context version" << std::endl;
exit(EXIT_FAILURE);
} }
else if(!gl->initializeOpenGLFunctions())
{ {
/* Problem: glewInit failed, something is seriously wrong. */ std::cerr << "Could not initialise OpenGL functions" << std::endl;
std::cout << "failed" << std::endl;
std::cout << "Initialising GLEW failed with the following error: " << glewGetErrorString(result) << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
//Print out some information about the OpenGL implementation. //Print out some information about the OpenGL implementation.
std::cout << "OpenGL Implementation Details:" << std::endl; std::cout << "OpenGL Implementation Details:" << std::endl;
if(glGetString(GL_VENDOR)) if(gl->glGetString(GL_VENDOR))
std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl; std::cout << "\tGL_VENDOR: " << gl->glGetString(GL_VENDOR) << std::endl;
if(glGetString(GL_RENDERER)) if(gl->glGetString(GL_RENDERER))
std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl; std::cout << "\tGL_RENDERER: " << gl->glGetString(GL_RENDERER) << std::endl;
if(glGetString(GL_VERSION)) if(gl->glGetString(GL_VERSION))
std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl; std::cout << "\tGL_VERSION: " << gl->glGetString(GL_VERSION) << std::endl;
if(glGetString(GL_SHADING_LANGUAGE_VERSION)) if(gl->glGetString(GL_SHADING_LANGUAGE_VERSION))
std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << gl->glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
//Check our version of OpenGL is recent enough.
//We need at least 1.5 for vertex buffer objects,
if (!GLEW_VERSION_1_5)
{
std::cout << "Error: You need OpenGL version 1.5 to run this example." << std::endl;
exit(EXIT_FAILURE);
}
//Set up the clear colour //Set up the clear colour
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f); gl->glClearDepth(1.0f);
//Enable the depth buffer gl->glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); gl->glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); gl->glDepthMask(GL_TRUE);
gl->glDepthFunc(GL_LEQUAL);
//Anable smooth lighting gl->glDepthRange(0.0, 1.0);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0); if(!shader.addShaderFromSourceCode(QOpenGLShader::Vertex, R"(
glShadeModel(GL_SMOOTH); #version 140
//We'll be rendering with index/vertex arrays in vec4 position; //This will be the position of the vertex in model-space
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY); uniform mat4 cameraToClipMatrix;
uniform mat4 worldToCameraMatrix;
uniform mat4 modelToWorldMatrix;
out vec4 worldPosition; //This is being passed to the fragment shader to calculate the normals
void main()
{
worldPosition = modelToWorldMatrix * position;
vec4 cameraPosition = worldToCameraMatrix * worldPosition;
gl_Position = cameraToClipMatrix * cameraPosition;
}
)"))
{
std::cerr << shader.log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
if(!shader.addShaderFromSourceCode(QOpenGLShader::Fragment, R"(
#version 130
in vec4 worldPosition; //Passed in from the vertex shader
out vec4 outputColor;
void main()
{
vec3 normal = normalize(cross(dFdy(worldPosition.xyz), dFdx(worldPosition.xyz)));
float color = clamp(abs(dot(normalize(normal.xyz), vec3(0.9,0.1,0.5))), 0, 1);
outputColor = vec4(1.0, 0.5, color, 1.0);
}
)"))
{
std::cerr << shader.log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
shader.bindAttributeLocation("position", 0);
if(!shader.link())
{
std::cerr << shader.log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
shader.bind();
QMatrix4x4 worldToCameraMatrix{};
worldToCameraMatrix.translate(0, 0, -50); //Move the camera back by 50 units
shader.setUniformValue("worldToCameraMatrix", worldToCameraMatrix);
shader.release();
} }
void OpenGLWidget::resizeGL(int w, int h) void OpenGLWidget::resizeGL(int w, int h)
{ {
//Setup the viewport //Setup the viewport
glViewport(0, 0, w, h); gl->glViewport(0, 0, w, h);
//Set up the projection matrix auto aspectRatio = w / (float)h;
glMatrixMode(GL_PROJECTION); float zNear = 1.0;
glLoadIdentity(); float zFar = 1000.0;
float frustumSize = 32.0f; //Half the volume size
float aspect = static_cast<float>(width()) / static_cast<float>(height()); QMatrix4x4 cameraToClipMatrix{};
glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 1.0, 1000); cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar);
shader.bind();
shader.setUniformValue("cameraToClipMatrix", cameraToClipMatrix);
shader.release();
} }
void OpenGLWidget::paintGL() void OpenGLWidget::paintGL()
{ {
//Clear the screen //Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Set up the viewing transformation
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-100.0f); //Centre volume and move back
glRotatef(-m_xRotation, 0.0f, 1.0f, 0.0f);
glRotatef(-m_yRotation, 1.0f, 0.0f, 0.0f);
glTranslatef(-32.0f,-32.0f,-32.0f); //Centre volume and move back
//Bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
//Bind the vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexPointer(3, GL_FLOAT, sizeof(PositionMaterialNormal), 0);
glNormalPointer(GL_FLOAT, sizeof(PositionMaterialNormal), (GLvoid*)12);
glDrawRangeElements(GL_TRIANGLES, m_uBeginIndex, m_uEndIndex-1, m_uEndIndex - m_uBeginIndex, GL_UNSIGNED_INT, 0);
GLenum errCode = glGetError(); QMatrix4x4 modelToWorldMatrix{};
modelToWorldMatrix.rotate(m_xRotation, 0, 1, 0); //rotate around y-axis
modelToWorldMatrix.rotate(m_yRotation, 1, 0, 0); //rotate around x-axis
modelToWorldMatrix.translate(-32, -32, -32); //centre the model on the origin
shader.bind();
shader.setUniformValue("modelToWorldMatrix", modelToWorldMatrix); //Update to the latest camera matrix
gl->glBindVertexArray(vertexArrayObject);
gl->glDrawElements(GL_TRIANGLES, noOfIndices, GL_UNSIGNED_INT, 0);
gl->glBindVertexArray(0);
shader.release();
GLenum errCode = gl->glGetError();
if(errCode != GL_NO_ERROR) if(errCode != GL_NO_ERROR)
{ {
//What has replaced getErrorString() in the latest OpenGL? std::cerr << "OpenGL Error: " << errCode << std::endl;
std::cout << "OpenGL Error: " << errCode << std::endl;
} }
} }

View File

@ -26,9 +26,12 @@ distribution.
#include "PolyVoxCore/SurfaceMesh.h" #include "PolyVoxCore/SurfaceMesh.h"
#include "glew/glew.h" #include <QOpenGLFunctions_3_1>
#include <QGLWidget> #include <QGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
class OpenGLWidget : public QGLWidget class OpenGLWidget : public QGLWidget
{ {
@ -40,8 +43,8 @@ public:
void mouseMoveEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event);
//Convert a SrfaceMesh to OpenGL index/vertex buffers //Convert a SurfaceMesh to OpenGL index/vertex buffers
void setSurfaceMeshToRender(const PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal>& surfaceMesh); void setSurfaceMeshToRender(const PolyVox::SurfaceMesh<PolyVox::PositionMaterial>& surfaceMesh);
protected: protected:
//Qt OpenGL functions //Qt OpenGL functions
@ -51,11 +54,13 @@ protected:
private: private:
//Index/vertex buffer data //Index/vertex buffer data
GLuint m_uBeginIndex;
GLuint m_uEndIndex;
GLuint noOfIndices; GLuint noOfIndices;
GLuint indexBuffer; GLuint indexBuffer;
GLuint vertexBuffer; GLuint vertexBuffer;
GLuint vertexArrayObject;
QOpenGLShaderProgram shader;
QOpenGLFunctions_3_1* gl;
//Mouse data //Mouse data
QPoint m_LastFrameMousePos; QPoint m_LastFrameMousePos;

View File

@ -23,7 +23,7 @@ freely, subject to the following restrictions:
#include "OpenGLWidget.h" #include "OpenGLWidget.h"
#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h" #include "PolyVoxCore/CubicSurfaceExtractor.h"
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" #include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
#include "PolyVoxCore/SurfaceMesh.h" #include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/SimpleVolume.h" #include "PolyVoxCore/SimpleVolume.h"
@ -78,10 +78,10 @@ int main(int argc, char *argv[])
createSphereInVolume(volData, 30); createSphereInVolume(volData, 30);
//A mesh object to hold the result of surface extraction //A mesh object to hold the result of surface extraction
SurfaceMesh<PositionMaterialNormal> mesh; SurfaceMesh<PositionMaterial> mesh;
//Create a surface extractor. Comment out one of the following two lines to decide which type gets created. //Create a surface extractor. Comment out one of the following two lines to decide which type gets created.
CubicSurfaceExtractorWithNormals< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); CubicSurfaceExtractor< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);
//MarchingCubesSurfaceExtractor< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); //MarchingCubesSurfaceExtractor< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);
//Execute the surface extractor. //Execute the surface extractor.