fix: buggy handles
This commit is contained in:
parent
2895124778
commit
5081e18ea7
7 changed files with 89 additions and 47 deletions
|
@ -2,11 +2,15 @@
|
|||
#include "datatypes/vector.h"
|
||||
#include "physics/util.h"
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/gtc/matrix_inverse.hpp>
|
||||
#include <glm/matrix.hpp>
|
||||
#include <reactphysics3d/mathematics/Transform.h>
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/euler_angles.hpp>
|
||||
// #include "meta.h" // IWYU pragma: keep
|
||||
|
||||
const Data::CFrame Data::CFrame::IDENTITY(glm::vec3(0, 0, 0), glm::mat3(1.f));
|
||||
|
||||
Data::CFrame::CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22)
|
||||
: translation(x, y, z)
|
||||
, rotation({
|
||||
|
@ -37,13 +41,9 @@ glm::mat3 lookAt(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up)
|
|||
Data::Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
||||
Data::Vector3 u = up.Unit(); // Up
|
||||
Data::Vector3 s = f.Cross(u).Unit(); // Right
|
||||
u = s.Cross(u);
|
||||
u = s.Cross(f);
|
||||
|
||||
return {
|
||||
{ s.X(), u.X(), -f.X() },
|
||||
{ s.Y(), u.Y(), -f.Y() },
|
||||
{ s.Z(), u.Z(), -f.Z() },
|
||||
};
|
||||
return { s, u, f };
|
||||
}
|
||||
|
||||
Data::CFrame::CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up)
|
||||
|
@ -85,8 +85,21 @@ Data::CFrame Data::CFrame::FromEulerAnglesXYZ(Data::Vector3 vector) {
|
|||
return Data::CFrame(Data::Vector3::ZERO, glm::column(mat, 2), (Data::Vector3)glm::column(mat, 1)); // Getting LookAt (3rd) and Up (2nd) vectors
|
||||
}
|
||||
|
||||
Data::CFrame Data::CFrame::Inverse() const {
|
||||
return CFrame { -translation * glm::transpose(glm::inverse(rotation)), glm::inverse(rotation) };
|
||||
}
|
||||
|
||||
|
||||
// Operators
|
||||
|
||||
Data::CFrame Data::CFrame::operator *(Data::CFrame otherFrame) const {
|
||||
return CFrame { this->translation + this->rotation * otherFrame.translation, this->rotation * otherFrame.rotation };
|
||||
}
|
||||
|
||||
Data::Vector3 Data::CFrame::operator *(Data::Vector3 vector) const {
|
||||
return this->translation + this->rotation * vector;
|
||||
}
|
||||
|
||||
Data::CFrame Data::CFrame::operator +(Data::Vector3 vector) const {
|
||||
return CFrame { this->translation + glm::vec3(vector), this->rotation };
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <glm/fwd.hpp>
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <glm/gtc/matrix_inverse.hpp>
|
||||
#include <glm/matrix.hpp>
|
||||
#include <reactphysics3d/mathematics/Transform.h>
|
||||
#include <reactphysics3d/reactphysics3d.h>
|
||||
|
||||
|
@ -28,6 +30,8 @@ namespace Data {
|
|||
CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up = Data::Vector3(0, 1, 0));
|
||||
~CFrame();
|
||||
|
||||
static const CFrame IDENTITY;
|
||||
|
||||
virtual const TypeInfo& GetType() const override;
|
||||
static const TypeInfo TYPE;
|
||||
|
||||
|
@ -41,18 +45,21 @@ namespace Data {
|
|||
//inline static CFrame identity() { }
|
||||
inline Vector3 Position() const { return translation; }
|
||||
inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
||||
CFrame Inverse() const;
|
||||
inline float X() const { return translation.x; }
|
||||
inline float Y() const { return translation.y; }
|
||||
inline float Z() const { return translation.z; }
|
||||
|
||||
inline Vector3 RightVector() { return glm::column(rotation, 0); }
|
||||
inline Vector3 UpVector() { return glm::column(rotation, 1); }
|
||||
inline Vector3 LookVector() { return glm::column(rotation, 2); }
|
||||
inline Vector3 LookVector() { return -glm::column(rotation, 2); }
|
||||
|
||||
Vector3 ToEulerAnglesXYZ();
|
||||
static CFrame FromEulerAnglesXYZ(Data::Vector3);
|
||||
|
||||
// Operators
|
||||
Data::CFrame operator *(Data::CFrame) const;
|
||||
Data::Vector3 operator *(Data::Vector3) const;
|
||||
Data::CFrame operator +(Data::Vector3) const;
|
||||
Data::CFrame operator -(Data::Vector3) const;
|
||||
};
|
||||
|
|
|
@ -25,6 +25,14 @@ Data::Vector3::operator glm::vec3() const { return vector; };
|
|||
Data::Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
|
||||
|
||||
// Operators
|
||||
Data::Vector3 Data::Vector3::operator *(float scale) const {
|
||||
return Data::Vector3(this->X() * scale, this->Y() * scale, this->Z() * scale);
|
||||
}
|
||||
|
||||
Data::Vector3 Data::Vector3::operator /(float scale) const {
|
||||
return Data::Vector3(this->X() / scale, this->Y() / scale, this->Z() / scale);
|
||||
}
|
||||
|
||||
Data::Vector3 Data::Vector3::operator +(Data::Vector3 other) const {
|
||||
return Data::Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z());
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ namespace Data {
|
|||
float Dot(Data::Vector3) const;
|
||||
|
||||
// Operators
|
||||
Data::Vector3 operator *(float) const;
|
||||
Data::Vector3 operator /(float) const;
|
||||
Data::Vector3 operator +(Data::Vector3) const;
|
||||
Data::Vector3 operator -(Data::Vector3) const;
|
||||
Data::Vector3 operator -() const;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "handles.h"
|
||||
#include "common.h"
|
||||
#include "datatypes/cframe.h"
|
||||
#include "datatypes/vector.h"
|
||||
#include <optional>
|
||||
|
@ -36,19 +37,30 @@ Handles::Handles(): Instance(&TYPE) {
|
|||
Data::CFrame Handles::GetCFrameOfHandle(HandleFace face) {
|
||||
if (!adornee.has_value() || adornee->expired()) return Data::CFrame(glm::vec3(0,0,0), (Data::Vector3)glm::vec3(0,0,0));
|
||||
|
||||
// return adornee->lock()->cframe + face.normal * 5.f;
|
||||
if (worldMode)
|
||||
return adornee->lock()->cframe + (adornee->lock()->size * 0.5f * face.normal) + face.normal * 2.f;
|
||||
return adornee->lock()->cframe + glm::vec3(glm::mat4(adornee->lock()->cframe.Rotation()) * glm::vec4((adornee->lock()->size * 0.5f * face.normal) + face.normal * 2.f, 0));
|
||||
Data::CFrame localFrame = worldMode ? Data::CFrame::IDENTITY + adornee->lock()->position() : adornee->lock()->cframe;
|
||||
|
||||
// We don't want this to align with local * face.normal, or else we have problems.
|
||||
glm::vec3 upAxis(0, 0, 1);
|
||||
if (glm::abs(glm::dot(glm::vec3(localFrame.Rotation() * face.normal), upAxis)) > 0.9999f)
|
||||
upAxis = glm::vec3(0, 1, 0);
|
||||
|
||||
Data::Vector3 handlePos = localFrame * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
||||
Data::CFrame cframe(handlePos, handlePos + localFrame.Rotation() * face.normal, upAxis);
|
||||
|
||||
return cframe;
|
||||
}
|
||||
|
||||
Data::CFrame Handles::PartCFrameFromHandlePos(HandleFace face, Data::Vector3 newPos) {
|
||||
if (!adornee.has_value() || adornee->expired()) return Data::CFrame(glm::vec3(0,0,0), (Data::Vector3)glm::vec3(0,0,0));
|
||||
|
||||
// return adornee->lock()->cframe + face.normal * 5.f;
|
||||
if (worldMode)
|
||||
return adornee->lock()->cframe.Rotation() + newPos - (adornee->lock()->size * 0.5f * face.normal) - face.normal * 2.f;
|
||||
return adornee->lock()->cframe.Rotation() + newPos - glm::vec3(glm::mat4(adornee->lock()->cframe.Rotation()) * glm::vec4((adornee->lock()->size * 0.5f * face.normal) + face.normal * 2.f, 0));
|
||||
Data::CFrame localFrame = worldMode ? Data::CFrame::IDENTITY + adornee->lock()->position() : adornee->lock()->cframe;
|
||||
Data::CFrame inverseFrame = localFrame.Inverse();
|
||||
|
||||
Data::Vector3 handlePos = localFrame * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
||||
|
||||
// glm::vec3 localPos = inverseFrame * newPos;
|
||||
glm::vec3 newPartPos = newPos - localFrame.Rotation() * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
||||
return adornee->lock()->cframe.Rotation() + newPartPos;
|
||||
}
|
||||
|
||||
std::optional<HandleFace> Handles::RaycastHandle(rp3d::Ray ray) {
|
||||
|
|
|
@ -109,6 +109,8 @@ void MainGLWidget::handleHandleDrag(QMouseEvent* evt) {
|
|||
|
||||
QPoint position = evt->pos();
|
||||
|
||||
auto part = editorToolHandles->adornee->lock();
|
||||
|
||||
// This was actually quite a difficult problem to solve, managing to get the handle to go underneath the cursor
|
||||
|
||||
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
||||
|
@ -116,9 +118,12 @@ void MainGLWidget::handleHandleDrag(QMouseEvent* evt) {
|
|||
|
||||
Data::CFrame handleCFrame = editorToolHandles->GetCFrameOfHandle(draggingHandle.value());
|
||||
|
||||
// Current frame. Identity frame if worldMode == true, selected object's frame if worldMode == false
|
||||
Data::CFrame frame = editorToolHandles->worldMode ? Data::CFrame::IDENTITY + part->position() : part->cframe.Rotation();
|
||||
|
||||
// Segment from axis stretching -4096 to +4096 rel to handle's position
|
||||
glm::vec3 axisSegment0 = handleCFrame.Position() + glm::abs(draggingHandle->normal) * 4096.0f;
|
||||
glm::vec3 axisSegment1 = handleCFrame.Position() + glm::abs(draggingHandle->normal) * -4096.0f;
|
||||
glm::vec3 axisSegment0 = handleCFrame.Position() + (-handleCFrame.LookVector() * 4096.0f);
|
||||
glm::vec3 axisSegment1 = handleCFrame.Position() + (-handleCFrame.LookVector() * -4096.0f);
|
||||
|
||||
// Segment from camera stretching 4096 forward
|
||||
glm::vec3 mouseSegment0 = camera.cameraPos;
|
||||
|
@ -128,31 +133,16 @@ void MainGLWidget::handleHandleDrag(QMouseEvent* evt) {
|
|||
glm::vec3 handlePoint, rb;
|
||||
get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb);
|
||||
|
||||
if (mainWindow()->selectedTool == SelectedTool::MOVE) {
|
||||
glm::vec3 newPos = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position();
|
||||
glm::vec3 oldPos = editorToolHandles->adornee->lock()->cframe.Position();
|
||||
glm::vec3 diff = newPos - oldPos;
|
||||
// Find new part position
|
||||
glm::vec3 centerPoint = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position();
|
||||
|
||||
// Apply snapping
|
||||
if (snappingFactor()) diff = glm::floor(diff / snappingFactor()) * snappingFactor();
|
||||
newPos = diff + oldPos;
|
||||
// Apply snapping in the current frame
|
||||
glm::vec3 diff = centerPoint - (glm::vec3)editorToolHandles->adornee->lock()->position();
|
||||
// auto odiff = diff;
|
||||
if (snappingFactor()) diff = frame * (glm::round(glm::vec3(frame.Inverse() * diff) * snappingFactor()) / snappingFactor());
|
||||
|
||||
editorToolHandles->adornee->lock()->cframe = editorToolHandles->adornee->lock()->cframe.Rotation() + newPos;
|
||||
} else if (mainWindow()->selectedTool == SelectedTool::SCALE) {
|
||||
glm::vec3 handlePos = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position();
|
||||
|
||||
// Find change in handles, and negate difference in sign between axes
|
||||
glm::vec3 diff = handlePos - glm::vec3(editorToolHandles->adornee->lock()->position());
|
||||
|
||||
// Apply snapping
|
||||
if (snappingFactor()) diff = glm::floor(diff / snappingFactor()) * snappingFactor();
|
||||
|
||||
editorToolHandles->adornee->lock()->size += diff * glm::sign(draggingHandle->normal);
|
||||
|
||||
// If ctrl is not pressed, also reposition the part such that only the dragged side gets lengthened
|
||||
if (!(evt->modifiers() & Qt::ControlModifier))
|
||||
editorToolHandles->adornee->lock()->cframe = editorToolHandles->adornee->lock()->cframe + (diff / 2.0f);
|
||||
}
|
||||
// Add difference
|
||||
editorToolHandles->adornee->lock()->cframe = editorToolHandles->adornee->lock()->cframe + diff;
|
||||
|
||||
syncPartPhysics(std::dynamic_pointer_cast<Part>(editorToolHandles->adornee->lock()));
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
ConnectSelectionChangeHandler();
|
||||
});
|
||||
|
||||
// Update handles
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||
editorToolHandles->adornee = std::nullopt;
|
||||
if (newSelection.size() == 0) return;
|
||||
|
@ -93,6 +94,14 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
editorToolHandles->adornee = std::dynamic_pointer_cast<Part>(inst);
|
||||
});
|
||||
|
||||
// Update properties
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||
if (newSelection.size() == 0) return;
|
||||
if (newSelection.size() > 1)
|
||||
ui->propertiesView->setSelected(std::nullopt);
|
||||
ui->propertiesView->setSelected(newSelection[0].lock());
|
||||
});
|
||||
|
||||
// ui->explorerView->Init(ui);
|
||||
|
||||
simulationInit();
|
||||
|
@ -110,7 +119,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
|
||||
workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||
.position = glm::vec3(0),
|
||||
.rotation = glm::vec3(0),
|
||||
.rotation = glm::vec3(0.5, 2, 1),
|
||||
.size = glm::vec3(4, 1.2, 2),
|
||||
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||
}));
|
||||
|
@ -118,14 +127,14 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
}
|
||||
|
||||
void MainWindow::ConnectSelectionChangeHandler() {
|
||||
connect(ui->explorerView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) {
|
||||
if (selected.count() == 0) return;
|
||||
// connect(ui->explorerView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) {
|
||||
// if (selected.count() == 0) return;
|
||||
|
||||
std::optional<InstanceRef> inst = selected.count() == 0 ? std::nullopt
|
||||
: std::make_optional(((Instance*)selected.indexes()[0].internalPointer())->shared_from_this());
|
||||
// std::optional<InstanceRef> inst = selected.count() == 0 ? std::nullopt
|
||||
// : std::make_optional(((Instance*)selected.indexes()[0].internalPointer())->shared_from_this());
|
||||
|
||||
ui->propertiesView->setSelected(inst);
|
||||
});
|
||||
// ui->propertiesView->setSelected(inst);
|
||||
// });
|
||||
}
|
||||
|
||||
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
|
||||
|
@ -154,6 +163,7 @@ void MainWindow::updateToolbars() {
|
|||
ui->actionGridSnap05->setChecked(snappingMode == GridSnappingMode::SNAP_05_STUDS);
|
||||
ui->actionGridSnapOff->setChecked(snappingMode == GridSnappingMode::SNAP_OFF);
|
||||
|
||||
// editorToolHandles->worldMode = false;
|
||||
if (selectedTool == SelectedTool::MOVE) editorToolHandles->worldMode = true;
|
||||
if (selectedTool == SelectedTool::SCALE) editorToolHandles->worldMode = false;
|
||||
editorToolHandles->active = selectedTool != SelectedTool::SELECT;
|
||||
|
|
Loading…
Add table
Reference in a new issue