| 279 * the camera, no value is returned. |
279 * the camera, no value is returned. |
| 280 * @param point 2D window co-ordinates to convert. |
280 * @param point 2D window co-ordinates to convert. |
| 281 * @param plane Plane to raycast against |
281 * @param plane Plane to raycast against |
| 282 * @return world co-ordinates, or no value if the point is behind the camera. |
282 * @return world co-ordinates, or no value if the point is behind the camera. |
| 283 */ |
283 */ |
| 284 std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point, const geom::Plane& plane) |
284 std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point, const geom::Plane& plane) const |
| 285 { |
285 { |
| 286 const glm::vec3 p1 = this->unproject({point.x(), point.y(), 0}); |
286 const geom::Line line = this->cameraLine(point); |
| 287 const glm::vec3 p2 = this->unproject({point.x(), point.y(), 1}); |
|
| 288 const geom::Line line = geom::lineFromPoints(p1, p2); |
|
| 289 std::optional<glm::vec3> result; |
287 std::optional<glm::vec3> result; |
| 290 result = geom::linePlaneIntersection(line, plane, 0.01f); |
288 result = geom::linePlaneIntersection(line, plane, 0.01f); |
| 291 // If the point lies behind the camera, do not return a result. |
289 // If the point lies behind the camera, do not return a result. |
| 292 if (result.has_value() and glm::dot(line.direction, *result - p1) < 0) |
290 if (result.has_value() and glm::dot(line.direction, *result - line.anchor) < 0) |
| 293 { |
291 { |
| 294 result.reset(); |
292 result.reset(); |
| 295 } |
293 } |
| 296 return result; |
294 return result; |
| 297 } |
295 } |
| 299 /** |
297 /** |
| 300 * @brief Converts the specified point to 2D window coordinates, with Y-coordinate inverted for Qt |
298 * @brief Converts the specified point to 2D window coordinates, with Y-coordinate inverted for Qt |
| 301 * @param point Point to unproject |
299 * @param point Point to unproject |
| 302 * @return screen coordinates |
300 * @return screen coordinates |
| 303 */ |
301 */ |
| 304 QPointF PartRenderer::modelToScreenCoordinates(const glm::vec3& point) |
302 QPointF PartRenderer::modelToScreenCoordinates(const glm::vec3& point) const |
| 305 { |
303 { |
| 306 const glm::vec3 projected = glm::project( |
304 const glm::vec3 projected = glm::project( |
| 307 point, |
305 point, |
| 308 this->viewMatrix * glm::mat4_cast(this->modelQuaternion), |
306 this->viewMatrix * glm::mat4_cast(this->modelQuaternion), |
| 309 this->projectionMatrix, |
307 this->projectionMatrix, |
| 310 this->viewportVector); |
308 this->viewportVector); |
| 311 return toQPointF(glm::vec2{projected.x, this->height() - projected.y}); |
309 return toQPointF(glm::vec2{projected.x, this->height() - projected.y}); |
| 312 } |
310 } |
| 313 |
311 |
| |
312 geom::Line PartRenderer::cameraLine(const QPoint& point) const |
| |
313 { |
| |
314 const glm::vec3 p1 = this->unproject({point.x(), point.y(), 0}); |
| |
315 const glm::vec3 p2 = this->unproject({point.x(), point.y(), 1}); |
| |
316 return geom::lineFromPoints(p1, p2); |
| |
317 } |
| |
318 |
| 314 /** |
319 /** |
| 315 * @brief Unprojects the specified window coordinates to model coordinates |
320 * @brief Unprojects the specified window coordinates to model coordinates |
| 316 * @param win Window coordinates to project. Z-coordinate indicates depth |
321 * @param win Window coordinates to project. Z-coordinate indicates depth |
| 317 * @return model coordinates |
322 * @return model coordinates |
| 318 */ |
323 */ |
| 319 glm::vec3 PartRenderer::unproject(const glm::vec3& win) |
324 glm::vec3 PartRenderer::unproject(const glm::vec3& win) const |
| 320 { |
325 { |
| 321 return glm::unProject( |
326 return glm::unProject( |
| 322 glm::vec3{win.x, this->height() - win.y, win.z}, |
327 glm::vec3{win.x, this->height() - win.y, win.z}, |
| 323 this->viewMatrix * glm::mat4_cast(this->modelQuaternion), |
328 this->viewMatrix * glm::mat4_cast(this->modelQuaternion), |
| 324 this->projectionMatrix, |
329 this->projectionMatrix, |