use glm::unProject to implement screenToModelCoordinates

Thu, 27 Feb 2020 11:56:41 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Thu, 27 Feb 2020 11:56:41 +0200
changeset 57
5c0005f63319
parent 56
fad4a5dd8dee
child 58
b7841cd31fb7

use glm::unProject to implement screenToModelCoordinates

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
src/ui/canvas.h file | annotate | diff | comparison | revisions
--- a/src/gl/partrenderer.cpp	Wed Feb 26 22:26:05 2020 +0200
+++ b/src/gl/partrenderer.cpp	Thu Feb 27 11:56:41 2020 +0200
@@ -71,6 +71,7 @@
 
 void PartRenderer::resizeGL(int width, int height)
 {
+	this->viewportVector = {0, 0, width, height};
 	glViewport(0, 0, width, height);
 	this->projectionMatrix = glm::perspective(
 		glm::radians(45.0f),
@@ -96,25 +97,11 @@
 	throw std::runtime_error{"Bad vbo class passed to getGlTypeForVboClass"};
 }
 
-#include <QPainter>
 void PartRenderer::paintGL()
 {
 	glEnable(GL_DEPTH_TEST);
 	glShadeModel(GL_SMOOTH);
 	this->renderScene();
-	QPainter painter{this};
-	painter.setPen(Qt::white);
-	painter.setBrush(Qt::red);
-	for (float x : {1, -1})
-	{
-		for (float y : {1, -1})
-		{
-			for (float z : {1, -1})
-			{
-				painter.drawEllipse(this->modelToScreenCoordinates({x, y, z}), 10, 10);
-			}
-		}
-	}
 }
 
 void PartRenderer::renderScene()
@@ -301,12 +288,8 @@
 
 std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point)
 {
-	glm::vec3 pp = {point.x(), this->height() - point.y(), 1};
-	glm::mat4 matrix;
-	matrix = this->projectionMatrix * this->viewMatrix * glm::mat4_cast(this->modelQuaternion);
-	matrix = glm::transpose(glm::inverse(matrix));
-	auto p1 = matrix * glm::vec4{pp.x, pp.y, 0, 1};
-	auto p2 = matrix * glm::vec4{pp.x, pp.y, 1, 1};
+	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);
 }
@@ -321,6 +304,15 @@
 	return toQPointF(pp);
 }
 
+glm::vec3 PartRenderer::unproject(const glm::vec3& win)
+{
+	return glm::unProject(
+		glm::vec3{win.x, this->height() - win.y, win.z},
+		this->viewMatrix * glm::mat4_cast(this->modelQuaternion),
+		this->projectionMatrix,
+		viewportVector);
+}
+
 ldraw::Id PartRenderer::pick(const QPoint& where)
 {
 	const gl::RenderStyle oldRenderStyle = this->renderPreferences.style;
--- a/src/gl/partrenderer.h	Wed Feb 26 22:26:05 2020 +0200
+++ b/src/gl/partrenderer.h	Thu Feb 27 11:56:41 2020 +0200
@@ -24,6 +24,7 @@
 	~PartRenderer() override;
 	void setRenderPreferences(const gl::RenderPreferences& newPreferences);
 	static glm::vec3 viewport(const glm::vec3& point, float width, float height);
+	static glm::vec3 antiviewport(const glm::vec3& point, float width, float height);
 protected:
 	ldraw::Id pick(const QPoint& where);
 	void initializeGL() override;
@@ -39,6 +40,7 @@
 	ldraw::Id highlighted = ldraw::NULL_ID;
 	std::optional<glm::vec3> screenToModelCoordinates(const QPoint& point);
 	QPointF modelToScreenCoordinates(const glm::vec3& point);
+	glm::vec3 unproject(const glm::vec3& win);
 private:
 	void setFragmentStyle(gl::FragmentStyle fragStyle);
 	void renderAllArrays();
@@ -50,6 +52,7 @@
 	gl::RenderPreferences renderPreferences;
 	glm::mat4 projectionMatrix;
 	glm::mat4 viewMatrix;
+	glm::vec4 viewportVector;
 	glm::quat modelQuaternion;
 	std::optional<GridProgram> gridProgram;
 	static constexpr double MIN_ZOOM = 0.0;
--- a/src/ui/canvas.cpp	Wed Feb 26 22:26:05 2020 +0200
+++ b/src/ui/canvas.cpp	Thu Feb 27 11:56:41 2020 +0200
@@ -1,4 +1,5 @@
 #include <QMouseEvent>
+#include <QPainter>
 #include "canvas.h"
 
 Canvas::Canvas(
@@ -22,24 +23,26 @@
 
 void Canvas::mouseMoveEvent(QMouseEvent* event)
 {
-#if 0
-	std::optional<glm::vec3> p = this->cameraToGrid(event->pos());
-	if (p.has_value())
+	const ldraw::Id id = this->pick(event->pos());
+	this->highlighted = id;
+	this->totalMouseMove += (event->pos() - this->lastMousePosition).manhattanLength();
+	this->lastMousePosition = event->pos();
+	this->worldPosition = this->screenToModelCoordinates(this->lastMousePosition);
+	if (this->worldPosition.has_value())
 	{
-		this->newStatusText("Position: (%1, %2, %3)"_q.arg(p->x).arg(p->y).arg(p->z));
+		this->worldPosition = glm::round(*this->worldPosition);
+	}
+	if (this->worldPosition.has_value())
+	{
+		this->newStatusText("Position: (%1, %2, %3)"_q
+			.arg(this->worldPosition->x)
+			.arg(this->worldPosition->y)
+			.arg(this->worldPosition->z));
 	}
 	else
 	{
 		this->newStatusText("Position: <none>"_q);
 	}
-#else
-	const QPointF originAtCamera = this->modelToScreenCoordinates({1, 1, 1});
-	this->newStatusText("{1,1,1} is at (%1, %2), cursor at (%3, %4)"_q.arg(originAtCamera.x()).arg(originAtCamera.y()).arg(event->pos().x()).arg(event->pos().y()));
-#endif
-	const ldraw::Id id = this->pick(event->pos());
-	this->highlighted = id;
-	this->totalMouseMove += (event->pos() - this->lastMousePosition).manhattanLength();
-	this->lastMousePosition = event->pos();
 	PartRenderer::mouseMoveEvent(event);
 }
 
@@ -68,3 +71,16 @@
 	}
 	PartRenderer::mouseReleaseEvent(event);
 }
+
+void Canvas::paintGL()
+{
+	PartRenderer::paintGL();
+	if (this->worldPosition.has_value())
+	{
+		QPainter painter{this};
+		painter.setRenderHint(QPainter::Antialiasing);
+		painter.setPen(Qt::black);
+		painter.setBrush(Qt::green);
+		painter.drawEllipse(this->modelToScreenCoordinates(*this->worldPosition), 10, 10);
+	}
+}
--- a/src/ui/canvas.h	Wed Feb 26 22:26:05 2020 +0200
+++ b/src/ui/canvas.h	Thu Feb 27 11:56:41 2020 +0200
@@ -16,11 +16,13 @@
 	void mouseMoveEvent(QMouseEvent* event) override;
 	void mousePressEvent(QMouseEvent* event) override;
 	void mouseReleaseEvent(QMouseEvent* event) override;
+	void paintGL() override;
 signals:
 	void newStatusText(const QString& newStatusText);
 	void selectionChanged(const QSet<ldraw::Id>& newSelection);
 private:
 	QPoint lastMousePosition;
+	std::optional<glm::vec3> worldPosition;
 	int totalMouseMove = 0;
 	QSet<ldraw::Id> selection;
 };

mercurial