use glm::project instead of figuring out the conversion manually...

Thu, 27 Feb 2020 12:23:42 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Thu, 27 Feb 2020 12:23:42 +0200
changeset 58
b7841cd31fb7
parent 57
5c0005f63319
child 59
60650929dc82

use glm::project instead of figuring out the conversion manually...

src/geometry.cpp file | annotate | diff | comparison | revisions
src/geometry.h file | annotate | diff | comparison | revisions
src/gl/partrenderer.cpp file | annotate | diff | comparison | revisions
src/gl/partrenderer.h file | annotate | diff | comparison | revisions
src/ui/canvas.cpp file | annotate | diff | comparison | revisions
--- a/src/geometry.cpp	Thu Feb 27 11:56:41 2020 +0200
+++ b/src/geometry.cpp	Thu Feb 27 12:23:42 2020 +0200
@@ -17,10 +17,10 @@
  * @param plane
  * @return point of intersection. Does not return a value if the line is in parallel to the plane.
  */
-std::optional<glm::vec3> geom::linePlaneIntersection(const geom::Line& line, const geom::Plane& plane)
+std::optional<glm::vec3> geom::linePlaneIntersection(const geom::Line& line, const geom::Plane& plane, const float epsilon)
 {
 	const float denominator = glm::dot(line.direction, plane.normal);
-	if (std::abs(denominator) < 1e-8f)
+	if (std::abs(denominator) < epsilon)
 	{
 		return {};
 	}
--- a/src/geometry.h	Thu Feb 27 11:56:41 2020 +0200
+++ b/src/geometry.h	Thu Feb 27 12:23:42 2020 +0200
@@ -30,5 +30,5 @@
 	Line lineFromPoints(const glm::vec3& point_1, const glm::vec3 point_2);
 	Plane planeFromTriangle(const Triangle& triangle);
 	glm::vec3 normalVector(const Triangle& triangle);
-	std::optional<glm::vec3> linePlaneIntersection(const Line& line, const Plane& plane);
+	std::optional<glm::vec3> linePlaneIntersection(const Line& line, const Plane& plane, const float epsilon = 1e-6);
 }
--- 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(
--- a/src/gl/partrenderer.h	Thu Feb 27 11:56:41 2020 +0200
+++ b/src/gl/partrenderer.h	Thu Feb 27 12:23:42 2020 +0200
@@ -38,7 +38,7 @@
 	const ldraw::ColorTable& colorTable;
 	gl::Compiler* const compiler;
 	ldraw::Id highlighted = ldraw::NULL_ID;
-	std::optional<glm::vec3> screenToModelCoordinates(const QPoint& point);
+	std::optional<glm::vec3> screenToModelCoordinates(const QPoint& point, const geom::Plane& plane);
 	QPointF modelToScreenCoordinates(const glm::vec3& point);
 	glm::vec3 unproject(const glm::vec3& win);
 private:
--- a/src/ui/canvas.cpp	Thu Feb 27 11:56:41 2020 +0200
+++ b/src/ui/canvas.cpp	Thu Feb 27 12:23:42 2020 +0200
@@ -27,7 +27,7 @@
 	this->highlighted = id;
 	this->totalMouseMove += (event->pos() - this->lastMousePosition).manhattanLength();
 	this->lastMousePosition = event->pos();
-	this->worldPosition = this->screenToModelCoordinates(this->lastMousePosition);
+	this->worldPosition = this->screenToModelCoordinates(this->lastMousePosition, geom::XY);
 	if (this->worldPosition.has_value())
 	{
 		this->worldPosition = glm::round(*this->worldPosition);

mercurial