--- a/src/gl/partrenderer.cpp Thu Feb 27 11:56:41 2020 +0200 +++ b/src/gl/partrenderer.cpp Thu Feb 27 12:23:42 2020 +0200 @@ -286,24 +286,49 @@ return viewport(point, this->width(), this->height()); } -std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point) +/** + * @brief Converts the specified on the screen into the 3D world. The point is unprojected twice into 3D and the + * intersection of the resulting line with the specified plane is returned. If the intersection point lies behind + * the camera, no value is returned. + * @param point 2D window co-ordinates to convert. + * @param plane Plane to raycast against + * @return world co-ordinates, or no value if the point is behind the camera. + */ +std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point, const geom::Plane& plane) { auto p1 = this->unproject({point.x(), point.y(), 0}); auto p2 = this->unproject({point.x(), point.y(), 1}); geom::Line line = geom::lineFromPoints(p1, p2); - return geom::linePlaneIntersection(line, geom::XY); + std::optional<glm::vec3> result; + // If the dot product between the line direction and plane normal is negative, the point + // of intersection lies behind the camera. + if (glm::dot(line.direction, plane.normal) > 0) + { + result = geom::linePlaneIntersection(line, plane, 0.01); + } + return result; } +/** + * @brief Converts the specified point to 2D window coordinates, with Y-coordinate inverted for Qt + * @param point Point to unproject + * @return screen coordinates + */ QPointF PartRenderer::modelToScreenCoordinates(const glm::vec3& point) { - glm::vec4 p = {point, 1}; - p = glm::mat4_cast(this->modelQuaternion) * p; - p = this->viewMatrix * p; - p = this->projectionMatrix * p; - glm::vec2 pp = this->viewport({p.x / p.w, p.y / p.w, 1}); - return toQPointF(pp); + const glm::vec3 projected = glm::project( + point, + this->viewMatrix * glm::mat4_cast(this->modelQuaternion), + this->projectionMatrix, + this->viewportVector); + return {projected.x, this->height() - projected.y}; } +/** + * @brief Unprojects the specified window coordinates to model coordinates + * @param win Window coordinates to project. Z-coordinate indicates depth + * @return model coordinates + */ glm::vec3 PartRenderer::unproject(const glm::vec3& win) { return glm::unProject(