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) {
|
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);
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue