fix(editor): make models draggable

This commit is contained in:
maelstrom 2025-06-10 20:21:01 +02:00
parent 166950f08d
commit 8df049d6c3
3 changed files with 30 additions and 16 deletions

View file

@ -36,15 +36,29 @@ PartAssembly::PartAssembly(std::vector<std::shared_ptr<Part>> parts, bool worldM
PartAssembly PartAssembly::FromSelection(std::vector<std::shared_ptr<Instance>> newSelection) { PartAssembly PartAssembly::FromSelection(std::vector<std::shared_ptr<Instance>> newSelection) {
std::vector<std::shared_ptr<Part>> selection; std::vector<std::shared_ptr<Part>> selection;
for (std::weak_ptr<Instance> obj : newSelection) { for (std::shared_ptr<Instance> obj : newSelection) {
if (obj.expired() || !obj.lock()->IsA<Part>()) continue; if (!obj->IsA<PVInstance>()) continue;
selection.push_back(obj.lock()->CastTo<Part>().expect()); if (obj->IsA<Part>())
selection.push_back(obj->CastTo<Part>().expect());
// Add object descendants
for (DescendantsIterator it = obj->GetDescendantsStart(); it != obj->GetDescendantsEnd(); it++) {
if (!(*it)->IsA<Part>()) continue;
selection.push_back((*it)->CastTo<Part>().expect());
}
} }
return PartAssembly(selection, editorToolHandles.worldMode); return PartAssembly(selection, editorToolHandles.worldMode);
} }
void PartAssembly::SetCollisionsEnabled(bool enabled) {
for (auto part : parts) {
part->rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled);
}
}
void PartAssembly::SetOrigin(CFrame newOrigin) { void PartAssembly::SetOrigin(CFrame newOrigin) {
for (auto part : parts) { for (auto part : parts) {
part->cframe = newOrigin * (_assemblyOrigin.Inverse() * part->cframe); part->cframe = newOrigin * (_assemblyOrigin.Inverse() * part->cframe);

View file

@ -32,4 +32,8 @@ public:
// If multiple parts are selected, finds the greatest scale factor of each component pair, and // If multiple parts are selected, finds the greatest scale factor of each component pair, and
// scales it up by that amount // scales it up by that amount
void Scale(Vector3 newSize, bool scaleUp = true); void Scale(Vector3 newSize, bool scaleUp = true);
// Update temporary collisions of rigidbodies. Useful for ignoring
// items for raycasts
void SetCollisionsEnabled(bool enabled);
}; };

View file

@ -132,10 +132,10 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
QPoint position = evt->pos(); QPoint position = evt->pos();
initialAssembly.SetCollisionsEnabled(false);
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height())); glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000, [](std::shared_ptr<Part> part) { std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
return (part == draggingObject.lock()) ? FilterResult::PASS : FilterResult::TARGET; initialAssembly.SetCollisionsEnabled(true);
});
if (!rayHit) return; if (!rayHit) return;
@ -148,13 +148,13 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
Vector3 vec = rayHit->worldPoint + (tFormedInitialPos - tFormedHitPos); Vector3 vec = rayHit->worldPoint + (tFormedInitialPos - tFormedHitPos);
// The part being dragged's frame local to the hit target's frame, but without its position component // The part being dragged's frame local to the hit target's frame, but without its position component
// To find a world vector local to the new frame, use newFrame, not localFrame, as localFrame is localFrame is local to targetFrame in itself // To find a world vector local to the new frame, use newFrame, not localFrame, as localFrame is localFrame is local to targetFrame in itself
CFrame localFrame = (targetFrame.Inverse() * (draggingObject.lock()->cframe.Rotation() + vec)); CFrame localFrame = (targetFrame.Inverse() * (initialAssembly.assemblyOrigin().Rotation() + vec));
// Snap axis // Snap axis
localFrame = snapCFrame(localFrame); localFrame = snapCFrame(localFrame);
// Snap to studs // Snap to studs
Vector3 draggingPartSize = draggingObject.lock()->size; Vector3 draggingPartSize = initialAssembly.bounds();
glm::vec3 inverseNormalPartSize = (Vector3)(partSize - glm::vec3(localFrame.Rotation() * draggingPartSize)) * inverseSurfaceNormal / 2.f; glm::vec3 inverseNormalPartSize = (Vector3)(partSize - glm::vec3(localFrame.Rotation() * draggingPartSize)) * inverseSurfaceNormal / 2.f;
if (snappingFactor() > 0) if (snappingFactor() > 0)
localFrame = localFrame.Rotation() + glm::round(glm::vec3(localFrame.Position() * inverseSurfaceNormal - inverseNormalPartSize) / snappingFactor()) * snappingFactor() + inverseNormalPartSize localFrame = localFrame.Rotation() + glm::round(glm::vec3(localFrame.Position() * inverseSurfaceNormal - inverseNormalPartSize) / snappingFactor()) * snappingFactor() + inverseNormalPartSize
@ -164,14 +164,9 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
// Unsink the object // Unsink the object
// Get the normal of the surface relative to the part's frame, and get the size along that vector // Get the normal of the surface relative to the part's frame, and get the size along that vector
Vector3 unsinkOffset = newFrame.Rotation() * ((newFrame.Rotation().Inverse() * rayHit->worldNormal) * draggingObject.lock()->size / 2); Vector3 unsinkOffset = newFrame.Rotation() * ((newFrame.Rotation().Inverse() * rayHit->worldNormal) * initialAssembly.bounds() / 2);
draggingObject.lock()->cframe = newFrame + unsinkOffset; initialAssembly.SetOrigin(newFrame + unsinkOffset);
gWorkspace()->SyncPartPhysics(draggingObject.lock());
draggingObject.lock()->UpdateProperty("Position");
sendPropertyUpdatedSignal(draggingObject.lock(), "Position", draggingObject.lock()->position());
} }
inline glm::vec3 vec3fy(glm::vec4 vec) { inline glm::vec3 vec3fy(glm::vec4 vec) {
@ -403,7 +398,8 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
} }
} }
initialFrame = part->cframe; initialAssembly = PartAssembly::FromSelection({selObject});
initialFrame = initialAssembly.assemblyOrigin();
initialHitPos = rayHit->worldPoint; initialHitPos = rayHit->worldPoint;
initialHitNormal = rayHit->worldNormal; initialHitNormal = rayHit->worldNormal;