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), |