fix(editor): dragging objects now snaps them
This commit is contained in:
parent
575d5a9ea6
commit
ded68f9693
2 changed files with 20 additions and 10 deletions
|
@ -12,6 +12,7 @@
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
#include <glm/trigonometric.hpp>
|
#include <glm/trigonometric.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <numbers>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <reactphysics3d/collision/RaycastInfo.h>
|
#include <reactphysics3d/collision/RaycastInfo.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -140,6 +141,7 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
||||||
|
|
||||||
if (!rayHit) return;
|
if (!rayHit) return;
|
||||||
|
|
||||||
|
glm::vec3 partSize = partFromBody(rayHit->body)->size;
|
||||||
Data::Vector3 vec = rayHit->worldPoint;
|
Data::Vector3 vec = rayHit->worldPoint;
|
||||||
Data::CFrame targetFrame = partFromBody(rayHit->body)->cframe;
|
Data::CFrame targetFrame = partFromBody(rayHit->body)->cframe;
|
||||||
Data::Vector3 surfaceNormal = targetFrame.Inverse().Rotation() * rayHit->worldNormal;
|
Data::Vector3 surfaceNormal = targetFrame.Inverse().Rotation() * rayHit->worldNormal;
|
||||||
|
@ -149,6 +151,14 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
||||||
|
|
||||||
// Snap axis
|
// Snap axis
|
||||||
localFrame = snapCFrame(localFrame);
|
localFrame = snapCFrame(localFrame);
|
||||||
|
|
||||||
|
// Snap to studs
|
||||||
|
Data::Vector3 inverseSurfaceNormal = Data::Vector3::ONE - surfaceNormal.Abs();
|
||||||
|
glm::vec3 inverseNormalPartSize = (Data::Vector3)(partSize + 1.f) * inverseSurfaceNormal / 2.f;
|
||||||
|
if (snappingFactor() > 0)
|
||||||
|
localFrame = localFrame.Rotation() + glm::round(glm::vec3(localFrame.Position() * inverseSurfaceNormal - inverseNormalPartSize) / snappingFactor()) * snappingFactor() + inverseNormalPartSize
|
||||||
|
+ localFrame.Position() * surfaceNormal.Abs();
|
||||||
|
|
||||||
Data::CFrame newFrame = targetFrame * localFrame;
|
Data::CFrame newFrame = targetFrame * localFrame;
|
||||||
|
|
||||||
// Unsink the object
|
// Unsink the object
|
||||||
|
@ -236,13 +246,8 @@ void MainGLWidget::handleLinearTransform(QMouseEvent* evt) {
|
||||||
|
|
||||||
// Also implemented based on Godot: [c7ea8614](godot/editor/plugins/canvas_item_editor_plugin.cpp#L1490)
|
// Also implemented based on Godot: [c7ea8614](godot/editor/plugins/canvas_item_editor_plugin.cpp#L1490)
|
||||||
glm::vec2 startPoint;
|
glm::vec2 startPoint;
|
||||||
QPoint _lastPoint;
|
Data::CFrame initialFrame = Data::CFrame::IDENTITY;
|
||||||
void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) {
|
void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) {
|
||||||
QPoint lastPoint = _lastPoint;
|
|
||||||
_lastPoint = evt->pos();
|
|
||||||
|
|
||||||
glm::vec2 startPoint(lastPoint.x(), lastPoint.y());
|
|
||||||
|
|
||||||
if (!isMouseDragging || !draggingHandle || !editorToolHandles->adornee || !editorToolHandles->active) return;
|
if (!isMouseDragging || !draggingHandle || !editorToolHandles->adornee || !editorToolHandles->active) return;
|
||||||
|
|
||||||
glm::vec2 destPoint = glm::vec2(evt->pos().x(), evt->pos().y());
|
glm::vec2 destPoint = glm::vec2(evt->pos().x(), evt->pos().y());
|
||||||
|
@ -253,7 +258,7 @@ void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) {
|
||||||
glm::mat4 view = camera.getLookAt();
|
glm::mat4 view = camera.getLookAt();
|
||||||
|
|
||||||
// The rotated part's origin projected onto the screen
|
// The rotated part's origin projected onto the screen
|
||||||
glm::vec4 partCenterRaw = projection * view * glm::vec4((glm::vec3)part->cframe.Position(), 1.f);
|
glm::vec4 partCenterRaw = projection * view * glm::vec4((glm::vec3)initialFrame.Position(), 1.f);
|
||||||
partCenterRaw /= partCenterRaw.w;
|
partCenterRaw /= partCenterRaw.w;
|
||||||
glm::vec2 partCenter = glm::vec2(partCenterRaw.x*0.5f + 0.5f, 1-(partCenterRaw.y*0.5f+0.5f));
|
glm::vec2 partCenter = glm::vec2(partCenterRaw.x*0.5f + 0.5f, 1-(partCenterRaw.y*0.5f+0.5f));
|
||||||
partCenter *= glm::vec2(width(), height());
|
partCenter *= glm::vec2(width(), height());
|
||||||
|
@ -262,17 +267,21 @@ void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) {
|
||||||
glm::vec2 initVec = glm::normalize(startPoint - (glm::vec2)partCenter);
|
glm::vec2 initVec = glm::normalize(startPoint - (glm::vec2)partCenter);
|
||||||
glm::vec2 destVec = glm::normalize(destPoint - (glm::vec2)partCenter);
|
glm::vec2 destVec = glm::normalize(destPoint - (glm::vec2)partCenter);
|
||||||
float angle = atan2f(initVec.x * destVec.y - initVec.y * destVec.x, initVec.x * destVec.x + initVec.y * destVec.y);
|
float angle = atan2f(initVec.x * destVec.y - initVec.y * destVec.x, initVec.x * destVec.x + initVec.y * destVec.y);
|
||||||
|
|
||||||
|
// Snap the angle
|
||||||
|
if (snappingFactor() > 0)
|
||||||
|
angle = roundf(angle * 4 / std::numbers::pi / snappingFactor()) / 4 * std::numbers::pi * snappingFactor();
|
||||||
|
|
||||||
// Checks if the rotation axis is facing towards, or away from the camera
|
// Checks if the rotation axis is facing towards, or away from the camera
|
||||||
// If it pointing away from the camera, then we need to invert the angle change
|
// If it pointing away from the camera, then we need to invert the angle change
|
||||||
glm::vec4 rotationAxis = projection * view * glm::vec4((glm::vec3)(part->cframe * glm::abs(draggingHandle->normal)), 1.f);
|
glm::vec4 rotationAxis = projection * view * glm::vec4((glm::vec3)(initialFrame * glm::abs(draggingHandle->normal)), 1.f);
|
||||||
rotationAxis /= rotationAxis.w;
|
rotationAxis /= rotationAxis.w;
|
||||||
glm::vec4 signVec = glm::normalize(rotationAxis - partCenterRaw);
|
glm::vec4 signVec = glm::normalize(rotationAxis - partCenterRaw);
|
||||||
float sign = -glm::sign(signVec.z);
|
float sign = -glm::sign(signVec.z);
|
||||||
|
|
||||||
glm::vec3 angles = glm::abs(draggingHandle->normal) * sign * glm::vec3(angle);
|
glm::vec3 angles = glm::abs(draggingHandle->normal) * sign * glm::vec3(angle);
|
||||||
|
|
||||||
part->cframe = part->cframe * Data::CFrame::FromEulerAnglesXYZ(-angles);
|
part->cframe = initialFrame * Data::CFrame::FromEulerAnglesXYZ(-angles);
|
||||||
|
|
||||||
syncPartPhysics(std::dynamic_pointer_cast<Part>(editorToolHandles->adornee->lock()));
|
syncPartPhysics(std::dynamic_pointer_cast<Part>(editorToolHandles->adornee->lock()));
|
||||||
}
|
}
|
||||||
|
@ -335,6 +344,7 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
||||||
auto handle = raycastHandle(pointDir);
|
auto handle = raycastHandle(pointDir);
|
||||||
if (handle.has_value()) {
|
if (handle.has_value()) {
|
||||||
startPoint = glm::vec2(evt->pos().x(), evt->pos().y());
|
startPoint = glm::vec2(evt->pos().x(), evt->pos().y());
|
||||||
|
initialFrame = editorToolHandles->adornee->lock()->cframe;
|
||||||
isMouseDragging = true;
|
isMouseDragging = true;
|
||||||
draggingHandle = handle;
|
draggingHandle = handle;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -323,7 +323,7 @@ void MainWindow::updateToolbars() {
|
||||||
ui->actionGridSnap05->setChecked(snappingMode == GridSnappingMode::SNAP_05_STUDS);
|
ui->actionGridSnap05->setChecked(snappingMode == GridSnappingMode::SNAP_05_STUDS);
|
||||||
ui->actionGridSnapOff->setChecked(snappingMode == GridSnappingMode::SNAP_OFF);
|
ui->actionGridSnapOff->setChecked(snappingMode == GridSnappingMode::SNAP_OFF);
|
||||||
|
|
||||||
editorToolHandles->worldMode = selectedTool == SelectedTool::SCALE ? false : worldSpaceTransforms;
|
editorToolHandles->worldMode = (selectedTool == SelectedTool::SCALE || selectedTool == SelectedTool::ROTATE) ? false : worldSpaceTransforms;
|
||||||
editorToolHandles->nixAxes = selectedTool == SelectedTool::ROTATE;
|
editorToolHandles->nixAxes = selectedTool == SelectedTool::ROTATE;
|
||||||
|
|
||||||
editorToolHandles->active = selectedTool != SelectedTool::SELECT;
|
editorToolHandles->active = selectedTool != SelectedTool::SELECT;
|
||||||
|
|
Loading…
Add table
Reference in a new issue