forked from qt-creator/qt-creator
QmlDesigner: Add camera alignment buttons
Add a button to 3D edit view that aligns the selected cameras to the view camera. Add another button that aligns the view camera to a selected camera. Task-number: QDS-4482 Change-Id: Ibe6ceaf498db10f45c8c351e3a108419d8d7a59b Reviewed-by: Samuel Ghinet <samuel.ghinet@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
committed by
Miikka Heikkinen
parent
f6a26fb13e
commit
a03a50a262
@@ -40,6 +40,8 @@ public:
|
||||
ScaleTool,
|
||||
RotateTool,
|
||||
FitToView,
|
||||
AlignCamerasToView,
|
||||
AlignViewToCamera,
|
||||
SelectionModeToggle,
|
||||
CameraToggle,
|
||||
OrientationToggle,
|
||||
|
||||
@@ -110,6 +110,37 @@ Item {
|
||||
storeCameraState(0);
|
||||
}
|
||||
|
||||
function alignCameras(targetNodes)
|
||||
{
|
||||
if (!camera)
|
||||
return;
|
||||
|
||||
// targetNodes could be a list of nodes or a single node
|
||||
var nodes = [];
|
||||
if (targetNodes instanceof Node)
|
||||
nodes.push(targetNodes);
|
||||
else
|
||||
nodes = targetNodes
|
||||
|
||||
_generalHelper.alignCameras(camera, nodes);
|
||||
}
|
||||
|
||||
function alignView(targetNodes)
|
||||
{
|
||||
if (!camera)
|
||||
return;
|
||||
|
||||
// targetNodes could be a list of nodes or a single node
|
||||
var nodes = [];
|
||||
if (targetNodes instanceof Node)
|
||||
nodes.push(targetNodes);
|
||||
else
|
||||
nodes = targetNodes
|
||||
|
||||
_lookAtPoint = _generalHelper.alignView(camera, nodes, _lookAtPoint);
|
||||
storeCameraState(0);
|
||||
}
|
||||
|
||||
function zoomRelative(distance)
|
||||
{
|
||||
if (!camera)
|
||||
|
||||
@@ -190,6 +190,22 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function alignCamerasToView()
|
||||
{
|
||||
if (editView) {
|
||||
cameraControl.alignCameras(selectedNodes);
|
||||
var propertyNames = ["position", "eulerRotation"];
|
||||
viewRoot.changeObjectProperty(selectedNodes, propertyNames);
|
||||
viewRoot.commitObjectProperty(selectedNodes, propertyNames);
|
||||
}
|
||||
}
|
||||
|
||||
function alignViewToCamera()
|
||||
{
|
||||
if (editView)
|
||||
cameraControl.alignView(selectedNodes);
|
||||
}
|
||||
|
||||
// If resetToDefault is true, tool states not specifically set to anything will be reset to
|
||||
// their default state.
|
||||
function updateToolStates(toolStates, resetToDefault)
|
||||
|
||||
@@ -110,6 +110,37 @@ Item {
|
||||
storeCameraState(0);
|
||||
}
|
||||
|
||||
function alignCameras(targetNodes)
|
||||
{
|
||||
if (!camera)
|
||||
return;
|
||||
|
||||
// targetNodes could be a list of nodes or a single node
|
||||
var nodes = [];
|
||||
if (targetNodes instanceof Node)
|
||||
nodes.push(targetNodes);
|
||||
else
|
||||
nodes = targetNodes
|
||||
|
||||
_generalHelper.alignCameras(camera, nodes);
|
||||
}
|
||||
|
||||
function alignView(targetNodes)
|
||||
{
|
||||
if (!camera)
|
||||
return;
|
||||
|
||||
// targetNodes could be a list of nodes or a single node
|
||||
var nodes = [];
|
||||
if (targetNodes instanceof Node)
|
||||
nodes.push(targetNodes);
|
||||
else
|
||||
nodes = targetNodes
|
||||
|
||||
_lookAtPoint = _generalHelper.alignView(camera, nodes, _lookAtPoint);
|
||||
storeCameraState(0);
|
||||
}
|
||||
|
||||
function zoomRelative(distance)
|
||||
{
|
||||
if (!camera)
|
||||
|
||||
@@ -181,6 +181,22 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function alignCamerasToView()
|
||||
{
|
||||
if (editView) {
|
||||
cameraControl.alignCameras(selectedNodes);
|
||||
var propertyNames = ["position", "eulerRotation"];
|
||||
viewRoot.changeObjectProperty(selectedNodes, propertyNames);
|
||||
viewRoot.commitObjectProperty(selectedNodes, propertyNames);
|
||||
}
|
||||
}
|
||||
|
||||
function alignViewToCamera()
|
||||
{
|
||||
if (editView)
|
||||
cameraControl.alignView(selectedNodes);
|
||||
}
|
||||
|
||||
// If resetToDefault is true, tool states not specifically set to anything will be reset to
|
||||
// their default state.
|
||||
function updateToolStates(toolStates, resetToDefault)
|
||||
|
||||
@@ -269,6 +269,53 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul
|
||||
return QVector4D(lookAt, cameraZoomFactor);
|
||||
}
|
||||
|
||||
// Aligns any cameras found in nodes list to a camera.
|
||||
// Only position and rotation are copied, rest of the camera properties stay the same.
|
||||
void GeneralHelper::alignCameras(QQuick3DCamera *camera, const QVariant &nodes)
|
||||
{
|
||||
QList<QQuick3DCamera *> nodeList;
|
||||
const QVariantList varNodes = nodes.value<QVariantList>();
|
||||
for (const auto &varNode : varNodes) {
|
||||
auto cameraNode = varNode.value<QQuick3DCamera *>();
|
||||
if (cameraNode)
|
||||
nodeList.append(cameraNode);
|
||||
}
|
||||
|
||||
for (QQuick3DCamera *node : qAsConst(nodeList)) {
|
||||
node->setPosition(camera->position());
|
||||
node->setRotation(camera->rotation());
|
||||
}
|
||||
}
|
||||
|
||||
// Aligns the camera to the first camera in nodes list.
|
||||
// Aligning means taking the position and XY rotation from the source camera. Rest of the properties
|
||||
// remain the same, as this is used to align edit cameras, which have fixed Z-rot, fov, and clips.
|
||||
// The new lookAt is set at same distance away as it was previously and scale isn't adjusted, so
|
||||
// the zoom factor of the edit camera stays the same.
|
||||
QVector3D GeneralHelper::alignView(QQuick3DCamera *camera, const QVariant &nodes,
|
||||
const QVector3D &lookAtPoint)
|
||||
{
|
||||
float lastDistance = (lookAtPoint - camera->position()).length();
|
||||
const QVariantList varNodes = nodes.value<QVariantList>();
|
||||
QQuick3DCamera *cameraNode = nullptr;
|
||||
for (const auto &varNode : varNodes) {
|
||||
cameraNode = varNode.value<QQuick3DCamera *>();
|
||||
if (cameraNode)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cameraNode) {
|
||||
camera->setPosition(cameraNode->position());
|
||||
QVector3D newRotation = cameraNode->eulerRotation();
|
||||
newRotation.setZ(0.f);
|
||||
camera->setEulerRotation(newRotation);
|
||||
}
|
||||
|
||||
QVector3D lookAt = camera->position() + camera->forward() * lastDistance;
|
||||
|
||||
return lookAt;
|
||||
}
|
||||
|
||||
bool GeneralHelper::fuzzyCompare(double a, double b)
|
||||
{
|
||||
return qFuzzyCompare(a, b);
|
||||
|
||||
@@ -72,6 +72,9 @@ public:
|
||||
const QVariant &nodes, QQuick3DViewport *viewPort,
|
||||
float oldZoom, bool updateZoom = true,
|
||||
bool closeUp = false);
|
||||
Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes);
|
||||
Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes,
|
||||
const QVector3D &lookAtPoint);
|
||||
Q_INVOKABLE bool fuzzyCompare(double a, double b);
|
||||
Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
const QVariant& value);
|
||||
|
||||
@@ -2090,6 +2090,12 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
|
||||
case View3DActionCommand::FitToView:
|
||||
QMetaObject::invokeMethod(m_editView3DData.rootItem, "fitToView");
|
||||
break;
|
||||
case View3DActionCommand::AlignCamerasToView:
|
||||
QMetaObject::invokeMethod(m_editView3DData.rootItem, "alignCamerasToView");
|
||||
break;
|
||||
case View3DActionCommand::AlignViewToCamera:
|
||||
QMetaObject::invokeMethod(m_editView3DData.rootItem, "alignViewToCamera");
|
||||
break;
|
||||
case View3DActionCommand::SelectionModeToggle:
|
||||
updatedState.insert("selectionMode", command.isEnabled() ? 1 : 0);
|
||||
break;
|
||||
|
||||
@@ -44,5 +44,9 @@
|
||||
<file>images/particles_pause@2x.png</file>
|
||||
<file>images/particles_restart.png</file>
|
||||
<file>images/particles_restart@2x.png</file>
|
||||
</qresource>
|
||||
<file>images/align_camera_on.png</file>
|
||||
<file>images/align_camera_on@2x.png</file>
|
||||
<file>images/align_view_on.png</file>
|
||||
<file>images/align_view_on@2x.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
#include <viewmanager.h>
|
||||
#include <nodeinstanceview.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <nodemetainfo.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
@@ -94,5 +97,21 @@ bool Edit3DAction::isEnabled(const SelectionContext &selectionContext) const
|
||||
return isVisible(selectionContext);
|
||||
}
|
||||
|
||||
Edit3DCameraAction::Edit3DCameraAction(const QByteArray &menuId, View3DActionCommand::Type type,
|
||||
const QString &description, const QKeySequence &key,
|
||||
bool checkable, bool checked, const QIcon &iconOff,
|
||||
const QIcon &iconOn,
|
||||
SelectionContextOperation selectionAction)
|
||||
: Edit3DAction(menuId, type, description, key, checkable, checked, iconOff, iconOn, selectionAction)
|
||||
{
|
||||
}
|
||||
|
||||
bool Edit3DCameraAction::isEnabled(const SelectionContext &selectionContext) const
|
||||
{
|
||||
return Utils::anyOf(selectionContext.selectedModelNodes(), [](const ModelNode &node) {
|
||||
return node.isValid() && node.metaInfo().isSubclassOf("QQuick3D.Camera");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -81,4 +81,15 @@ private:
|
||||
QByteArray m_menuId;
|
||||
};
|
||||
|
||||
class Edit3DCameraAction : public Edit3DAction
|
||||
{
|
||||
public:
|
||||
Edit3DCameraAction(const QByteArray &menuId, View3DActionCommand::Type type,
|
||||
const QString &description, const QKeySequence &key, bool checkable, bool checked,
|
||||
const QIcon &iconOff, const QIcon &iconOn,
|
||||
SelectionContextOperation selectionAction = nullptr);
|
||||
protected:
|
||||
bool isEnabled(const SelectionContext &selectionContext) const override;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -90,6 +90,16 @@ Edit3DWidget *Edit3DView::edit3DWidget() const
|
||||
return m_edit3DWidget.data();
|
||||
}
|
||||
|
||||
void Edit3DView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList, const QList<ModelNode> &lastSelectedNodeList)
|
||||
{
|
||||
SelectionContext selectionContext(this);
|
||||
selectionContext.setUpdateMode(SelectionContext::UpdateMode::Fast);
|
||||
if (m_alignCamerasAction)
|
||||
m_alignCamerasAction->currentContextChanged(selectionContext);
|
||||
if (m_alignViewAction)
|
||||
m_alignViewAction->currentContextChanged(selectionContext);
|
||||
}
|
||||
|
||||
void Edit3DView::renderImage3DChanged(const QImage &img)
|
||||
{
|
||||
edit3DWidget()->canvas()->updateRenderImage(img);
|
||||
@@ -256,6 +266,16 @@ void Edit3DView::createEdit3DActions()
|
||||
QCoreApplication::translate("FitToViewAction", "Fit Selected Object to View"),
|
||||
QKeySequence(Qt::Key_F), false, false, Icons::EDIT3D_FIT_SELECTED_OFF.icon(), {});
|
||||
|
||||
m_alignCamerasAction = new Edit3DCameraAction(
|
||||
QmlDesigner::Constants::EDIT3D_ALIGN_CAMERAS, View3DActionCommand::AlignCamerasToView,
|
||||
QCoreApplication::translate("AlignCamerasToViewAction", "Align Selected Cameras to View"),
|
||||
QKeySequence(), false, false, Icons::EDIT3D_ALIGN_CAMERA_ON.icon(), {});
|
||||
|
||||
m_alignViewAction = new Edit3DCameraAction(
|
||||
QmlDesigner::Constants::EDIT3D_ALIGN_VIEW, View3DActionCommand::AlignViewToCamera,
|
||||
QCoreApplication::translate("AlignCamerasToViewAction", "Align View to Selected Camera"),
|
||||
QKeySequence(), false, false, Icons::EDIT3D_ALIGN_VIEW_ON.icon(), {});
|
||||
|
||||
m_cameraModeAction
|
||||
= new Edit3DAction(
|
||||
QmlDesigner::Constants::EDIT3D_EDIT_CAMERA, View3DActionCommand::CameraToggle,
|
||||
@@ -351,6 +371,9 @@ void Edit3DView::createEdit3DActions()
|
||||
m_leftActions << m_orientationModeAction;
|
||||
m_leftActions << m_editLightAction;
|
||||
m_leftActions << m_showGridAction;
|
||||
m_leftActions << nullptr;
|
||||
m_leftActions << m_alignCamerasAction;
|
||||
m_leftActions << m_alignViewAction;
|
||||
|
||||
m_rightActions << m_particleViewModeAction;
|
||||
m_rightActions << m_particlesPlayAction;
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace QmlDesigner {
|
||||
|
||||
class Edit3DWidget;
|
||||
class Edit3DAction;
|
||||
class Edit3DCameraAction;
|
||||
|
||||
class QMLDESIGNERCORE_EXPORT Edit3DView : public AbstractView
|
||||
{
|
||||
@@ -54,6 +55,7 @@ public:
|
||||
|
||||
Edit3DWidget *edit3DWidget() const;
|
||||
|
||||
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList, const QList<ModelNode> &lastSelectedNodeList) override;
|
||||
void renderImage3DChanged(const QImage &img) override;
|
||||
void updateActiveScene3D(const QVariantMap &sceneState) override;
|
||||
void modelAttached(Model *model) override;
|
||||
@@ -87,6 +89,8 @@ private:
|
||||
Edit3DAction *m_rotateToolAction = nullptr;
|
||||
Edit3DAction *m_scaleToolAction = nullptr;
|
||||
Edit3DAction *m_fitAction = nullptr;
|
||||
Edit3DCameraAction *m_alignCamerasAction = nullptr;
|
||||
Edit3DCameraAction *m_alignViewAction = nullptr;
|
||||
Edit3DAction *m_cameraModeAction = nullptr;
|
||||
Edit3DAction *m_orientationModeAction = nullptr;
|
||||
Edit3DAction *m_editLightAction = nullptr;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 368 B |
Binary file not shown.
|
After Width: | Height: | Size: 687 B |
Binary file not shown.
|
After Width: | Height: | Size: 321 B |
Binary file not shown.
|
After Width: | Height: | Size: 660 B |
@@ -59,6 +59,8 @@ const char EDIT3D_MOVE_TOOL[] = "QmlDesigner.Editor3D.MoveTool";
|
||||
const char EDIT3D_ROTATE_TOOL[] = "QmlDesigner.Editor3D.RotateTool";
|
||||
const char EDIT3D_SCALE_TOOL[] = "QmlDesigner.Editor3D.ScaleTool";
|
||||
const char EDIT3D_FIT_SELECTED[] = "QmlDesigner.Editor3D.FitSelected";
|
||||
const char EDIT3D_ALIGN_CAMERAS[] = "QmlDesigner.Editor3D.AlignCameras";
|
||||
const char EDIT3D_ALIGN_VIEW[] = "QmlDesigner.Editor3D.AlignView";
|
||||
const char EDIT3D_EDIT_CAMERA[] = "QmlDesigner.Editor3D.EditCameraToggle";
|
||||
const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle";
|
||||
const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle";
|
||||
|
||||
@@ -91,6 +91,10 @@ const Utils::Icon EDIT3D_ORIENTATION_ON({
|
||||
{":/edit3d/images/global.png", Utils::Theme::QmlDesigner_HighlightColor}});
|
||||
const Utils::Icon EDIT3D_ORIENTATION_OFF({
|
||||
{":/edit3d/images/local.png", Utils::Theme::IconsBaseColor}});
|
||||
const Utils::Icon EDIT3D_ALIGN_CAMERA_ON({
|
||||
{":/edit3d/images/align_camera_on.png", Utils::Theme::IconsBaseColor}});
|
||||
const Utils::Icon EDIT3D_ALIGN_VIEW_ON({
|
||||
{":/edit3d/images/align_view_on.png", Utils::Theme::IconsBaseColor}});
|
||||
|
||||
} // Icons
|
||||
} // QmlDesigner
|
||||
|
||||
Reference in New Issue
Block a user