| 284 glm::vec3 PartRenderer::viewport(const glm::vec3& point) |
284 glm::vec3 PartRenderer::viewport(const glm::vec3& point) |
| 285 { |
285 { |
| 286 return viewport(point, this->width(), this->height()); |
286 return viewport(point, this->width(), this->height()); |
| 287 } |
287 } |
| 288 |
288 |
| 289 std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point) |
289 /** |
| |
290 * @brief Converts the specified on the screen into the 3D world. The point is unprojected twice into 3D and the |
| |
291 * intersection of the resulting line with the specified plane is returned. If the intersection point lies behind |
| |
292 * the camera, no value is returned. |
| |
293 * @param point 2D window co-ordinates to convert. |
| |
294 * @param plane Plane to raycast against |
| |
295 * @return world co-ordinates, or no value if the point is behind the camera. |
| |
296 */ |
| |
297 std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point, const geom::Plane& plane) |
| 290 { |
298 { |
| 291 auto p1 = this->unproject({point.x(), point.y(), 0}); |
299 auto p1 = this->unproject({point.x(), point.y(), 0}); |
| 292 auto p2 = this->unproject({point.x(), point.y(), 1}); |
300 auto p2 = this->unproject({point.x(), point.y(), 1}); |
| 293 geom::Line line = geom::lineFromPoints(p1, p2); |
301 geom::Line line = geom::lineFromPoints(p1, p2); |
| 294 return geom::linePlaneIntersection(line, geom::XY); |
302 std::optional<glm::vec3> result; |
| 295 } |
303 // If the dot product between the line direction and plane normal is negative, the point |
| 296 |
304 // of intersection lies behind the camera. |
| |
305 if (glm::dot(line.direction, plane.normal) > 0) |
| |
306 { |
| |
307 result = geom::linePlaneIntersection(line, plane, 0.01); |
| |
308 } |
| |
309 return result; |
| |
310 } |
| |
311 |
| |
312 /** |
| |
313 * @brief Converts the specified point to 2D window coordinates, with Y-coordinate inverted for Qt |
| |
314 * @param point Point to unproject |
| |
315 * @return screen coordinates |
| |
316 */ |
| 297 QPointF PartRenderer::modelToScreenCoordinates(const glm::vec3& point) |
317 QPointF PartRenderer::modelToScreenCoordinates(const glm::vec3& point) |
| 298 { |
318 { |
| 299 glm::vec4 p = {point, 1}; |
319 const glm::vec3 projected = glm::project( |
| 300 p = glm::mat4_cast(this->modelQuaternion) * p; |
320 point, |
| 301 p = this->viewMatrix * p; |
321 this->viewMatrix * glm::mat4_cast(this->modelQuaternion), |
| 302 p = this->projectionMatrix * p; |
322 this->projectionMatrix, |
| 303 glm::vec2 pp = this->viewport({p.x / p.w, p.y / p.w, 1}); |
323 this->viewportVector); |
| 304 return toQPointF(pp); |
324 return {projected.x, this->height() - projected.y}; |
| 305 } |
325 } |
| 306 |
326 |
| |
327 /** |
| |
328 * @brief Unprojects the specified window coordinates to model coordinates |
| |
329 * @param win Window coordinates to project. Z-coordinate indicates depth |
| |
330 * @return model coordinates |
| |
331 */ |
| 307 glm::vec3 PartRenderer::unproject(const glm::vec3& win) |
332 glm::vec3 PartRenderer::unproject(const glm::vec3& win) |
| 308 { |
333 { |
| 309 return glm::unProject( |
334 return glm::unProject( |
| 310 glm::vec3{win.x, this->height() - win.y, win.z}, |
335 glm::vec3{win.x, this->height() - win.y, win.z}, |
| 311 this->viewMatrix * glm::mat4_cast(this->modelQuaternion), |
336 this->viewMatrix * glm::mat4_cast(this->modelQuaternion), |