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
)
add_definitions(-DGLEW_STATIC)
#"Sources" and "Headers" are the group names in Visual Studio.
#They may have other uses too...
SOURCE_GROUP("Sources" FILES ${SRC_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)
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})
#Build
@ -50,7 +46,7 @@ ADD_EXECUTABLE(BasicExample ${SRC_FILES})
IF(MSVC)
SET_TARGET_PROPERTIES(BasicExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127")
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")
#Install - Only install the example in Windows

View File

@ -1,6 +1,8 @@
#include "OpenGLWidget.h"
#include <QMouseEvent>
#include <QMatrix4x4>
#include <QtMath>
using namespace PolyVox;
using namespace std;
@ -9,126 +11,179 @@ OpenGLWidget::OpenGLWidget(QWidget *parent)
:QGLWidget(parent)
,m_xRotation(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
const vector<uint32_t>& vecIndices = surfaceMesh.getIndices();
const vector<PositionMaterialNormal>& vecVertices = surfaceMesh.getVertices();
const auto& vecIndices = surfaceMesh.getIndices();
const auto& vecVertices = surfaceMesh.getVertices();
//Build an OpenGL index buffer
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
const GLvoid* pIndices = static_cast<const GLvoid*>(&(vecIndices[0]));
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW);
//Create the VAO for the mesh
gl->glGenVertexArrays(1, &vertexArrayObject);
gl->glBindVertexArray(vertexArrayObject);
//Build an OpenGL vertex buffer
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
const GLvoid* pVertices = static_cast<const GLvoid*>(&(vecVertices[0]));
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(PositionMaterialNormal), pVertices, GL_STATIC_DRAW);
//The GL_ARRAY_BUFFER will contain the list of vertex positions
gl->glGenBuffers(1, &vertexBuffer);
gl->glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
gl->glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(PositionMaterial), vecVertices.data(), GL_STATIC_DRAW);
m_uBeginIndex = 0;
m_uEndIndex = vecIndices.size();
//and GL_ELEMENT_ARRAY_BUFFER will contain the indices
gl->glGenBuffers(1, &indexBuffer);
gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), vecIndices.data(), GL_STATIC_DRAW);
//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()
{
//We need GLEW to access recent OpenGL functionality
std::cout << "Initialising GLEW...";
GLenum result = glewInit();
if (result == GLEW_OK)
//'gl' will give us access to all the OpenGL functions
gl = context()->contextHandle()->versionFunctions<QOpenGLFunctions_3_1>();
if(!gl)
{
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::cout << "failed" << std::endl;
std::cout << "Initialising GLEW failed with the following error: " << glewGetErrorString(result) << std::endl;
std::cerr << "Could not initialise 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;
if(gl->glGetString(GL_VENDOR))
std::cout << "\tGL_VENDOR: " << gl->glGetString(GL_VENDOR) << std::endl;
if(gl->glGetString(GL_RENDERER))
std::cout << "\tGL_RENDERER: " << gl->glGetString(GL_RENDERER) << std::endl;
if(gl->glGetString(GL_VERSION))
std::cout << "\tGL_VERSION: " << gl->glGetString(GL_VERSION) << std::endl;
if(gl->glGetString(GL_SHADING_LANGUAGE_VERSION))
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)
//Set up the clear colour
gl->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl->glClearDepth(1.0f);
gl->glEnable(GL_CULL_FACE);
gl->glEnable(GL_DEPTH_TEST);
gl->glDepthMask(GL_TRUE);
gl->glDepthFunc(GL_LEQUAL);
gl->glDepthRange(0.0, 1.0);
if(!shader.addShaderFromSourceCode(QOpenGLShader::Vertex, R"(
#version 140
in vec4 position; //This will be the position of the vertex in model-space
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()
{
std::cout << "Error: You need OpenGL version 1.5 to run this example." << std::endl;
worldPosition = modelToWorldMatrix * position;
vec4 cameraPosition = worldToCameraMatrix * worldPosition;
gl_Position = cameraToClipMatrix * cameraPosition;
}
)"))
{
std::cerr << shader.log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
//Set up the clear colour
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
if(!shader.addShaderFromSourceCode(QOpenGLShader::Fragment, R"(
#version 130
//Enable the depth buffer
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
in vec4 worldPosition; //Passed in from the vertex shader
//Anable smooth lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glShadeModel(GL_SMOOTH);
out vec4 outputColor;
//We'll be rendering with index/vertex arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
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)
{
//Setup the viewport
glViewport(0, 0, w, h);
gl->glViewport(0, 0, w, h);
//Set up the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float frustumSize = 32.0f; //Half the volume size
float aspect = static_cast<float>(width()) / static_cast<float>(height());
glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 1.0, 1000);
auto aspectRatio = w / (float)h;
float zNear = 1.0;
float zFar = 1000.0;
QMatrix4x4 cameraToClipMatrix{};
cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar);
shader.bind();
shader.setUniformValue("cameraToClipMatrix", cameraToClipMatrix);
shader.release();
}
void OpenGLWidget::paintGL()
{
//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
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
//Bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
shader.bind();
//Bind the vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexPointer(3, GL_FLOAT, sizeof(PositionMaterialNormal), 0);
glNormalPointer(GL_FLOAT, sizeof(PositionMaterialNormal), (GLvoid*)12);
shader.setUniformValue("modelToWorldMatrix", modelToWorldMatrix); //Update to the latest camera matrix
glDrawRangeElements(GL_TRIANGLES, m_uBeginIndex, m_uEndIndex-1, m_uEndIndex - m_uBeginIndex, GL_UNSIGNED_INT, 0);
gl->glBindVertexArray(vertexArrayObject);
GLenum errCode = glGetError();
gl->glDrawElements(GL_TRIANGLES, noOfIndices, GL_UNSIGNED_INT, 0);
gl->glBindVertexArray(0);
shader.release();
GLenum errCode = gl->glGetError();
if(errCode != GL_NO_ERROR)
{
//What has replaced getErrorString() in the latest OpenGL?
std::cout << "OpenGL Error: " << errCode << std::endl;
std::cerr << "OpenGL Error: " << errCode << std::endl;
}
}

View File

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

View File

@ -23,7 +23,7 @@ freely, subject to the following restrictions:
#include "OpenGLWidget.h"
#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h"
#include "PolyVoxCore/CubicSurfaceExtractor.h"
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/SimpleVolume.h"
@ -78,10 +78,10 @@ int main(int argc, char *argv[])
createSphereInVolume(volData, 30);
//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.
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);
//Execute the surface extractor.