From 9c93c5fc36d9d34eaccb9aaf15c948fc3f425fca Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 20 Feb 2015 15:28:54 +0100 Subject: [PATCH] Switched examples to use FPS-style first person perspective camera. --- examples/Basic/main.cpp | 4 +- examples/DecodeOnGPU/main.cpp | 2 +- examples/OpenGL/main.cpp | 10 +-- examples/Paging/main.cpp | 2 +- examples/SmoothLOD/main.cpp | 2 +- examples/common/OpenGLWidget.cpp | 129 ++++++++++++++++++++++--------- examples/common/OpenGLWidget.h | 31 +++++--- 7 files changed, 124 insertions(+), 56 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index ea93bb68..9253ce30 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -91,8 +91,8 @@ protected: //Pass the surface to the OpenGL window addMesh(decodedMesh); - //openGLWidget.addMesh(mesh2); - setViewableRegion(volData.getEnclosingRegion()); + + setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/DecodeOnGPU/main.cpp b/examples/DecodeOnGPU/main.cpp index eff3a5a7..74329df8 100644 --- a/examples/DecodeOnGPU/main.cpp +++ b/examples/DecodeOnGPU/main.cpp @@ -109,7 +109,7 @@ protected: OpenGLMeshData meshData = buildOpenGLMeshData(mesh); addMeshData(meshData); - setViewableRegion(volData.getEnclosingRegion()); + setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } private: diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index b9ee73a5..94802c4b 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -78,10 +78,10 @@ protected: createSphereInVolume(volData, 20.0f, 1); cout << "Creating cubes" << std::endl; - createCubeInVolume(volData, Vector3DInt32(minPos, minPos, minPos), Vector3DInt32(midPos - 1, midPos - 1, midPos - 1), 0); - createCubeInVolume(volData, Vector3DInt32(midPos + 1, midPos + 1, minPos), Vector3DInt32(maxPos, maxPos, midPos - 1), 0); - createCubeInVolume(volData, Vector3DInt32(midPos + 1, minPos, midPos + 1), Vector3DInt32(maxPos, midPos - 1, maxPos), 0); - createCubeInVolume(volData, Vector3DInt32(minPos, midPos + 1, midPos + 1), Vector3DInt32(midPos - 1, maxPos, maxPos), 0); + createCubeInVolume(volData, Vector3DInt32(minPos, minPos, midPos + 1), Vector3DInt32(midPos - 1, midPos - 1, maxPos), 0); + createCubeInVolume(volData, Vector3DInt32(midPos + 1, midPos + 1, midPos + 1), Vector3DInt32(maxPos, maxPos, maxPos), 0); + createCubeInVolume(volData, Vector3DInt32(minPos, midPos + 1, minPos), Vector3DInt32(midPos - 1, maxPos, midPos - 1), 0); + createCubeInVolume(volData, Vector3DInt32(midPos + 1, minPos, minPos), Vector3DInt32(maxPos, midPos - 1, midPos - 1), 0); createCubeInVolume(volData, Vector3DInt32(1, midPos - 10, midPos - 10), Vector3DInt32(maxPos - 1, midPos + 10, midPos + 10), MaterialDensityPair44::getMaxDensity()); createCubeInVolume(volData, Vector3DInt32(midPos - 10, 1, midPos - 10), Vector3DInt32(midPos + 10, maxPos - 1, midPos + 10), MaterialDensityPair44::getMaxDensity()); @@ -140,7 +140,7 @@ protected: cout << "Rendering volume as " << meshCounter << " seperate meshes" << endl; - setViewableRegion(volData.getEnclosingRegion()); + setCameraTransform(QVector3D(150.0f, 150.0f, 150.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 6b02e5e0..8436d27e 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -183,7 +183,7 @@ protected: //Pass the surface to the OpenGL window addMesh(decodedMesh); - setViewableRegion(reg2); + setCameraTransform(QVector3D(300.0f, 300.0f, 300.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/SmoothLOD/main.cpp b/examples/SmoothLOD/main.cpp index cc255d24..34b3a511 100644 --- a/examples/SmoothLOD/main.cpp +++ b/examples/SmoothLOD/main.cpp @@ -107,7 +107,7 @@ protected: addMesh(decodedMeshHighLOD, Vector3DInt32(30, 0, 0)); addMesh(decodedMeshLowLOD, Vector3DInt32(0, 0, 0), 63.0f / 31.0f); - setViewableRegion(volData.getEnclosingRegion()); + setCameraTransform(QVector3D(100.0f, 100.0f, 100.0f), -(PI / 4.0f), PI + (PI / 4.0f)); } }; diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.cpp index ce774e30..7f583237 100644 --- a/examples/common/OpenGLWidget.cpp +++ b/examples/common/OpenGLWidget.cpp @@ -3,6 +3,7 @@ #include #include #include +#include //#include using namespace PolyVox; @@ -13,9 +14,6 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// OpenGLWidget::OpenGLWidget(QWidget *parent) :QGLWidget(parent) - ,m_viewableRegion(PolyVox::Region(0, 0, 0, 255, 255, 255)) - ,m_xRotation(0) - ,m_yRotation(0) { } @@ -24,13 +22,11 @@ void OpenGLWidget::setShader(QSharedPointer shader) mShader = shader; } -void OpenGLWidget::setViewableRegion(PolyVox::Region viewableRegion) +void OpenGLWidget::setCameraTransform(QVector3D position, float pitch, float yaw) { - m_viewableRegion = viewableRegion; - - // The user has specifed a new viewable region - // so we need to regenerate our camera matrix. - setupWorldToCameraMatrix(); + mCameraPosition = position; + mCameraYaw = yaw; + mCameraPitch = pitch; } void OpenGLWidget::mousePressEvent(QMouseEvent* event) @@ -45,15 +41,24 @@ void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) // Update the x and y rotations based on the mouse movement. m_CurrentMousePos = event->pos(); QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; - m_xRotation += diff.x(); - m_yRotation += diff.y(); + mCameraYaw -= diff.x() * mCameraRotateSpeed; + mCameraPitch -= diff.y() * mCameraRotateSpeed; m_LastFrameMousePos = m_CurrentMousePos; +} - // The camera rotation has changed so we need to regenerate the matrix. - setupWorldToCameraMatrix(); +void OpenGLWidget::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Escape) + { + close(); + } - // Re-render. - update(); + mPressedKeys.append(event->key()); +} + +void OpenGLWidget::keyReleaseEvent(QKeyEvent* event) +{ + mPressedKeys.removeAll(event->key()); } //////////////////////////////////////////////////////////////////////////////// @@ -119,10 +124,14 @@ void OpenGLWidget::initializeGL() exit(EXIT_FAILURE); } - // Initial setup of camera. - setupWorldToCameraMatrix(); - initialize(); + + // Start a timer to drive the main rendering loop. + QTimer* timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(0); + + mElapsedTimer.start(); } void OpenGLWidget::resizeGL(int w, int h) @@ -135,11 +144,75 @@ void OpenGLWidget::resizeGL(int w, int h) float zFar = 1000.0; cameraToClipMatrix.setToIdentity(); - cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); + //cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); + cameraToClipMatrix.perspective(mCameraFOV, aspectRatio, zNear, zFar); } void OpenGLWidget::paintGL() { + // Direction : Spherical coordinates to Cartesian coordinates conversion + QVector3D cameraForward( + cos(mCameraPitch) * sin(mCameraYaw), + sin(mCameraPitch), + cos(mCameraPitch) * cos(mCameraYaw) + ); + + // Right vector + QVector3D cameraRight( + sin(mCameraYaw - 3.14f / 2.0f), + 0, + cos(mCameraYaw - 3.14f / 2.0f) + ); + + // Up vector + QVector3D cameraUp = QVector3D::crossProduct(cameraRight, cameraForward); + + // Get the elapsed time since last frame and convert to seconds. + float deltaTime = mElapsedTimer.restart() / 1000.0f; + + // Move forward + if ((mPressedKeys.contains(Qt::Key_Up)) || (mPressedKeys.contains(Qt::Key_W))) + { + mCameraPosition += cameraForward * deltaTime * mCameraMoveSpeed; + } + // Move backward + if ((mPressedKeys.contains(Qt::Key_Down)) || (mPressedKeys.contains(Qt::Key_S))) + { + mCameraPosition -= cameraForward * deltaTime * mCameraMoveSpeed; + } + // Strafe right + if ((mPressedKeys.contains(Qt::Key_Right)) || (mPressedKeys.contains(Qt::Key_D))) + { + mCameraPosition += cameraRight * deltaTime * mCameraMoveSpeed; + } + // Strafe left + if ((mPressedKeys.contains(Qt::Key_Left)) || (mPressedKeys.contains(Qt::Key_A))) + { + mCameraPosition -= cameraRight * deltaTime * mCameraMoveSpeed; + } + // Move backward + /*if ((glfwGetKey(mWindow, GLFW_KEY_DOWN) == GLFW_PRESS) || (glfwGetKey(mWindow, GLFW_KEY_S) == GLFW_PRESS)) + { + mCameraPosition -= cameraForward * deltaTime * mCameraMoveSpeed; + } + // Strafe right + if ((glfwGetKey(mWindow, GLFW_KEY_RIGHT) == GLFW_PRESS) || (glfwGetKey(mWindow, GLFW_KEY_D) == GLFW_PRESS)) + { + mCameraPosition += cameraRight * deltaTime * mCameraMoveSpeed; + } + // Strafe left + if ((glfwGetKey(mWindow, GLFW_KEY_LEFT) == GLFW_PRESS) || (glfwGetKey(mWindow, GLFW_KEY_A) == GLFW_PRESS)) + { + mCameraPosition -= cameraRight * deltaTime * mCameraMoveSpeed; + }*/ + + worldToCameraMatrix.setToIdentity(); + worldToCameraMatrix.lookAt( + mCameraPosition, // Camera is here + mCameraPosition + cameraForward, // and looks here : at the same position, plus "direction" + cameraUp // Head is up (set to 0,-1,0 to look upside-down) + ); + //Clear the screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -177,21 +250,3 @@ void OpenGLWidget::paintGL() std::cerr << "OpenGL Error: " << errCode << std::endl; } } - -//////////////////////////////////////////////////////////////////////////////// -// Private functions -//////////////////////////////////////////////////////////////////////////////// -void OpenGLWidget::setupWorldToCameraMatrix() -{ - QVector3D lowerCorner(m_viewableRegion.getLowerX(), m_viewableRegion.getLowerY(), m_viewableRegion.getLowerZ()); - QVector3D upperCorner(m_viewableRegion.getUpperX(), m_viewableRegion.getUpperY(), m_viewableRegion.getUpperZ()); - - QVector3D centerPoint = (lowerCorner + upperCorner) * 0.5; - float fDiagonalLength = (upperCorner - lowerCorner).length(); - - worldToCameraMatrix.setToIdentity(); - worldToCameraMatrix.translate(0, 0, -fDiagonalLength / 2.0f); //Move the camera back by the required amount - worldToCameraMatrix.rotate(m_xRotation, 0, 1, 0); //rotate around y-axis - worldToCameraMatrix.rotate(m_yRotation, 1, 0, 0); //rotate around x-axis - worldToCameraMatrix.translate(-centerPoint); //centre the model on the origin -} \ No newline at end of file diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h index c411c8b6..16362a40 100644 --- a/examples/common/OpenGLWidget.h +++ b/examples/common/OpenGLWidget.h @@ -28,6 +28,7 @@ distribution. #include +#include #include #include #include @@ -122,15 +123,20 @@ public: // this example framework is only meant to show a single volume at a time void setShader(QSharedPointer shader); - // The viewable region can be adjusted so that this example framework can be used for different volume sizes. - void setViewableRegion(PolyVox::Region viewableRegion); + void setCameraTransform(QVector3D position, float pitch, float yaw); // Mouse handling void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); + // Keyboard handling + void keyPressEvent(QKeyEvent* event); + void keyReleaseEvent(QKeyEvent* event); + protected: + const float PI = 3.14159265358979f; + // Qt OpenGL functions void initializeGL(); void resizeGL(int w, int h); @@ -141,9 +147,6 @@ protected: } private: - - void setupWorldToCameraMatrix(); - // Index/vertex buffer data std::vector mMeshData; @@ -157,10 +160,20 @@ private: QPoint m_LastFrameMousePos; QPoint m_CurrentMousePos; - // Camera setup - PolyVox::Region m_viewableRegion; - int m_xRotation; - int m_yRotation; + // Keyboard data + QList mPressedKeys; + + // For input handling and movement + float mCameraMoveSpeed = 50.0f; + float mCameraRotateSpeed = 0.005f; + + // Camera properties + QVector3D mCameraPosition = QVector3D(0, 0, -100); + float mCameraYaw = 0.0f; + float mCameraPitch = 0.0f; + float mCameraFOV = 60.0f; + + QElapsedTimer mElapsedTimer; }; #endif //__BasicExample_OpenGLWidget_H__