--- a/src/gl/partrenderer.cpp Thu Jan 23 00:29:10 2020 +0200 +++ b/src/gl/partrenderer.cpp Sun Jan 26 00:55:36 2020 +0200 @@ -48,8 +48,9 @@ this->compiler->build(this->model, this->documents); this->initializeLighting(); this->initialized = true; - this->rotation = QQuaternion::fromAxisAndAngle({1, 0, 0}, 30); - this->rotation *= QQuaternion::fromAxisAndAngle({0, 1, 0}, 330); + this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{1, 0, 0}); + this->modelQuaternion *= glm::angleAxis(glm::radians(330.0f), glm::vec3{0, 1, 0}); + this->updateViewMatrix(); glLineWidth(2.0); this->update(); } @@ -74,10 +75,10 @@ { glViewport(0, 0, width, height); this->projectionMatrix = glm::perspective( - glm::radians(90.0f), + glm::radians(45.0f), static_cast<float>(width) / static_cast<float>(height), 0.1f, - 100.f); + 10000.f); } static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass) @@ -127,7 +128,7 @@ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break; } - this->compiler->setUniformMatrix("CameraTransformation", this->projectionMatrix * this->viewMatrix); + this->compiler->setUniformMatrix("CameraTransformation", this->projectionMatrix * this->viewMatrix * glm::mat4_cast(this->modelQuaternion)); // Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering. renderVao(gl::ArrayClass::Triangles); renderVao(gl::ArrayClass::Quads); @@ -135,6 +136,13 @@ glDisable(GL_POLYGON_OFFSET_FILL); } +void PartRenderer::updateViewMatrix() +{ + // I'm not quite sure why using the exponent function on the zoom factor causes linear zoom behavior + const double z = 2 * std::exp(this->zoom) * (1 + this->compiler->modelDistance()); + this->viewMatrix = glm::lookAt(glm::vec3{0, 0, z}, {0, 0, 0}, {0, -1, 0}); +} + void PartRenderer::renderVao(const gl::ArrayClass arrayClass) { this->compiler->bindVertexArray(arrayClass); @@ -168,20 +176,29 @@ const QPointF move = pointToPointF(event->pos()) - this->lastMousePosition; if (left and not move.isNull()) { - // FIXME: find a more elegant way to do this - const QQuaternion versor = QQuaternion::fromAxisAndAngle( - QVector3D{static_cast<float>(-move.y()), static_cast<float>(move.x()), 0.0f}, - 0.6f * static_cast<float>(std::hypot(move.x(), move.y())) - ); - this->rotation = versor * this->rotation; - QVector3D cameraPosition = this->rotation.rotatedVector({0, 0, static_cast<float>(2 + 2 * this->compiler->modelDistance())}); - glm::vec3 cameraPosition_glm = {cameraPosition.x(), cameraPosition.y(), cameraPosition.z()}; - this->viewMatrix = glm::lookAt(cameraPosition_glm, {0, 0, 0}, {0, -1, 0}); + // q_x is the rotation of the brick along the vertical y-axis, because turning the + // vertical axis causes horizontal (=x) rotation. Likewise q_y is the rotation of the + // brick along the horizontal x-axis, which causes vertical rotation. + const auto scalar = 0.006f; + const float move_x = static_cast<float>(move.x()); + const float move_y = static_cast<float>(move.y()); + const glm::quat q_x = glm::angleAxis(scalar * move_x, glm::vec3{0, -1, 0}); + const glm::quat q_y = glm::angleAxis(scalar * move_y, glm::vec3{-1, 0, 0}); + this->modelQuaternion = q_x * q_y * this->modelQuaternion; this->update(); } this->lastMousePosition = pointToPointF(event->pos()); } +void PartRenderer::wheelEvent(QWheelEvent* event) +{ + static constexpr double WHEEL_STEP = 1 / 1000.0; + const double move = (-event->angleDelta().y()) * WHEEL_STEP; + this->zoom = std::clamp(this->zoom + move, MIN_ZOOM, MAX_ZOOM); + this->updateViewMatrix(); + this->update(); +} + void PartRenderer::setRenderStyle(const gl::RenderStyle newStyle) { this->renderStyle = newStyle;