fix(editor): make models draggable
This commit is contained in:
parent
166950f08d
commit
8df049d6c3
3 changed files with 30 additions and 16 deletions
|
@ -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) {
|
||||
std::vector<std::shared_ptr<Part>> selection;
|
||||
|
||||
for (std::weak_ptr<Instance> obj : newSelection) {
|
||||
if (obj.expired() || !obj.lock()->IsA<Part>()) continue;
|
||||
for (std::shared_ptr<Instance> obj : newSelection) {
|
||||
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);
|
||||
}
|
||||
|
||||
void PartAssembly::SetCollisionsEnabled(bool enabled) {
|
||||
for (auto part : parts) {
|
||||
part->rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void PartAssembly::SetOrigin(CFrame newOrigin) {
|
||||
for (auto part : parts) {
|
||||
part->cframe = newOrigin * (_assemblyOrigin.Inverse() * part->cframe);
|
||||
|
|
|
@ -32,4 +32,8 @@ public:
|
|||
// If multiple parts are selected, finds the greatest scale factor of each component pair, and
|
||||
// scales it up by that amount
|
||||
void Scale(Vector3 newSize, bool scaleUp = true);
|
||||
|
||||
// Update temporary collisions of rigidbodies. Useful for ignoring
|
||||
// items for raycasts
|
||||
void SetCollisionsEnabled(bool enabled);
|
||||
};
|
|
@ -132,10 +132,10 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
|||
|
||||
QPoint position = evt->pos();
|
||||
|
||||
initialAssembly.SetCollisionsEnabled(false);
|
||||
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) {
|
||||
return (part == draggingObject.lock()) ? FilterResult::PASS : FilterResult::TARGET;
|
||||
});
|
||||
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
||||
initialAssembly.SetCollisionsEnabled(true);
|
||||
|
||||
if (!rayHit) return;
|
||||
|
||||
|
@ -148,13 +148,13 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
|||
Vector3 vec = rayHit->worldPoint + (tFormedInitialPos - tFormedHitPos);
|
||||
// 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
|
||||
CFrame localFrame = (targetFrame.Inverse() * (draggingObject.lock()->cframe.Rotation() + vec));
|
||||
CFrame localFrame = (targetFrame.Inverse() * (initialAssembly.assemblyOrigin().Rotation() + vec));
|
||||
|
||||
// Snap axis
|
||||
localFrame = snapCFrame(localFrame);
|
||||
|
||||
// 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;
|
||||
if (snappingFactor() > 0)
|
||||
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
|
||||
// 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;
|
||||
|
||||
|
||||
gWorkspace()->SyncPartPhysics(draggingObject.lock());
|
||||
draggingObject.lock()->UpdateProperty("Position");
|
||||
sendPropertyUpdatedSignal(draggingObject.lock(), "Position", draggingObject.lock()->position());
|
||||
initialAssembly.SetOrigin(newFrame + unsinkOffset);
|
||||
}
|
||||
|
||||
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;
|
||||
initialHitNormal = rayHit->worldNormal;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue