QmlDesigner: Add light meshes to edit 3d view

Change-Id: I996498fde14510fc78c729f56cb8d46b28b233bb
Fixes: QDS-1634
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2020-03-09 16:08:13 +02:00
parent 3d67fbc55f
commit 2c842453b0
12 changed files with 383 additions and 9 deletions

View File

@@ -24,11 +24,12 @@
****************************************************************************/
import QtQuick 2.0
import QtQuick3D 1.15
IconGizmo {
id: cameraGizmo
property var frustumModel: null
property Model frustumModel: null
iconSource: "qrc:///qtquickplugin/mockfiles/images/editor_camera.png"

View File

@@ -134,7 +134,7 @@ Item {
function fitToView()
{
if (editView) {
var targetNode = selectedNodes.length > 0
var targetNode = selectionBoxes.length > 0
? selectionBoxes[0].model : null;
cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true);
}
@@ -301,16 +301,20 @@ Item {
}
// No free gizmos available, create a new one
var component = Qt.createComponent("LightGizmo.qml");
if (component.status === Component.Ready) {
var gizmo = component.createObject(overlayView,
{"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene,
"activeScene": activeScene});
var gizmoComponent = Qt.createComponent("LightGizmo.qml");
var modelComponent = Qt.createComponent("LightModel.qml");
if (gizmoComponent.status === Component.Ready && modelComponent.status === Component.Ready) {
var geometryName = _generalHelper.generateUniqueName("LightGeometry");
var model = modelComponent.createObject(overlayScene, {"geometryName": geometryName});
var gizmo = gizmoComponent.createObject(overlayView,
{"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene,
"activeScene": activeScene});
lightGizmos[lightGizmos.length] = gizmo;
gizmo.clicked.connect(handleObjectClicked);
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
gizmo.activeScene = Qt.binding(function() {return activeScene;});
gizmo.connectModel(model);
}
}

View File

@@ -29,6 +29,8 @@ import QtQuick3D 1.15
IconGizmo {
id: lightGizmo
property Model lightModel: null
iconSource: targetNode
? targetNode instanceof DirectionalLight
? "qrc:///qtquickplugin/mockfiles/images/directional_light_gradient.png"
@@ -39,4 +41,26 @@ IconGizmo {
// ColorOverlay doesn't work correctly with hidden windows so commenting it out for now
//overlayColor: targetNode ? targetNode.color : "transparent"
function connectModel(model)
{
lightModel = model;
model.selected = selected;
model.selected = Qt.binding(function() {return selected;});
model.scene = scene;
model.scene = Qt.binding(function() {return scene;});
model.targetNode = targetNode;
model.targetNode = Qt.binding(function() {return targetNode;});
model.visible = visible;
model.visible = Qt.binding(function() {return visible;});
}
onActiveSceneChanged: {
if (lightModel && activeScene == scene)
lightModel.updateGeometry();
}
}

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.0
import QtQuick3D 1.15
import LightGeometry 1.0
Model {
id: lightModel
property string geometryName
property alias geometryName: lightGeometry.name // Name must be unique for each geometry
property Node targetNode: null
property Node scene: null
property bool selected: false
function updateGeometry()
{
lightGeometry.update();
}
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
rotation: targetNode ? targetNode.sceneRotation : Qt.quaternion(1, 0, 0, 0)
scale: Qt.vector3d(50, 50, 50)
geometry: lightGeometry
materials: [
DefaultMaterial {
id: defaultMaterial
emissiveColor: lightModel.selected ? "#FF0000" : "#555555"
lighting: DefaultMaterial.NoLighting
cullMode: Material.NoCulling
}
]
LightGeometry {
id: lightGeometry
light: lightModel.scene && lightModel.targetNode ? lightModel.targetNode : null
}
}

View File

@@ -183,7 +183,7 @@ void CameraGeometry::fillVertexData(QByteArray &vertexData, QByteArray &indexDat
{
const int vertexSize = int(sizeof(float)) * 8 * 3; // 8 vertices, 3 floats/vert
vertexData.resize(vertexSize);
const int indexSize = int(sizeof(quint16)) * 12 * 2; // 16 lines, 2 vert/line
const int indexSize = int(sizeof(quint16)) * 12 * 2; // 12 lines, 2 vert/line
indexData.resize(indexSize);
auto dataPtr = reinterpret_cast<float *>(vertexData.data());

View File

@@ -1,6 +1,7 @@
HEADERS += $$PWD/generalhelper.h \
$$PWD/mousearea3d.h \
$$PWD/camerageometry.h \
$$PWD/lightgeometry.h \
$$PWD/gridgeometry.h \
$$PWD/selectionboxgeometry.h \
$$PWD/linegeometry.h
@@ -8,6 +9,7 @@ HEADERS += $$PWD/generalhelper.h \
SOURCES += $$PWD/generalhelper.cpp \
$$PWD/mousearea3d.cpp \
$$PWD/camerageometry.cpp \
$$PWD/lightgeometry.cpp \
$$PWD/gridgeometry.cpp \
$$PWD/selectionboxgeometry.cpp \
$$PWD/linegeometry.cpp

View File

@@ -0,0 +1,208 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifdef QUICK3D_MODULE
#include "lightgeometry.h"
#include <QtQuick3DRuntimeRender/private/qssgrendergeometry_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
#include <QtQuick3D/private/qquick3darealight_p.h>
#include <QtQuick3D/private/qquick3ddirectionallight_p.h>
#include <QtQuick3D/private/qquick3dpointlight_p.h>
#include <QtCore/qmath.h>
#include <limits>
namespace QmlDesigner {
namespace Internal {
LightGeometry::LightGeometry()
: QQuick3DGeometry()
{
}
LightGeometry::~LightGeometry()
{
}
QQuick3DAbstractLight *QmlDesigner::Internal::LightGeometry::light() const
{
return m_light;
}
void QmlDesigner::Internal::LightGeometry::setLight(QQuick3DAbstractLight *light)
{
if (m_light == light)
return;
m_light = light;
emit lightChanged();
update();
}
QSSGRenderGraphObject *LightGeometry::updateSpatialNode(QSSGRenderGraphObject *node)
{
if (!m_light)
return node;
node = QQuick3DGeometry::updateSpatialNode(node);
QSSGRenderGeometry *geometry = static_cast<QSSGRenderGeometry *>(node);
geometry->clear();
QByteArray vertexData;
QByteArray indexData;
QVector3D minBounds;
QVector3D maxBounds;
fillVertexData(vertexData, indexData, minBounds, maxBounds);
geometry->addAttribute(QSSGRenderGeometry::Attribute::PositionSemantic, 0,
QSSGRenderGeometry::Attribute::ComponentType::F32Type);
geometry->addAttribute(QSSGRenderGeometry::Attribute::IndexSemantic, 0,
QSSGRenderGeometry::Attribute::ComponentType::U16Type);
geometry->setStride(12);
geometry->setVertexData(vertexData);
geometry->setIndexData(indexData);
geometry->setPrimitiveType(QSSGRenderGeometry::Lines);
geometry->setBounds(minBounds, maxBounds);
return node;
}
void LightGeometry::fillVertexData(QByteArray &vertexData, QByteArray &indexData,
QVector3D &minBounds, QVector3D &maxBounds)
{
int vertexSize = 0;
int indexSize = 0;
const int dirSegments = 12;
const int pointLightDensity = 5;
if (qobject_cast<QQuick3DAreaLight *>(m_light)) {
// Area light model is a rectangle with perpendicular lines on corners
vertexSize = int(sizeof(float)) * 3 * 8;
indexSize = int(sizeof(quint16)) * 8 * 2;
} else if (qobject_cast<QQuick3DDirectionalLight *>(m_light)) {
// Directional light model is a circle with perpendicular lines on circumference vertices
vertexSize = int(sizeof(float)) * 3 * dirSegments * 2;
indexSize = int(sizeof(quint16)) * dirSegments * 2 * 2;
} else if (qobject_cast<QQuick3DPointLight *>(m_light)) {
// Point light model is a set of lines radiating from central point.
// We reserve more than we need so we don't have to calculate the actual need here,
// and resize later when we know the exact count.
vertexSize = int(sizeof(float)) * 3 * pointLightDensity * pointLightDensity * 4;
indexSize = int(sizeof(quint16)) * pointLightDensity * pointLightDensity * 4;
}
vertexData.resize(vertexSize);
indexData.resize(indexSize);
auto dataPtr = reinterpret_cast<float *>(vertexData.data());
auto indexPtr = reinterpret_cast<quint16 *>(indexData.data());
if (qobject_cast<QQuick3DAreaLight *>(m_light)) {
*dataPtr++ = -1.f; *dataPtr++ = 1.f; *dataPtr++ = 0.f;
*dataPtr++ = -1.f; *dataPtr++ = -1.f; *dataPtr++ = 0.f;
*dataPtr++ = 1.f; *dataPtr++ = -1.f; *dataPtr++ = 0.f;
*dataPtr++ = 1.f; *dataPtr++ = 1.f; *dataPtr++ = 0.f;
*dataPtr++ = -1.f; *dataPtr++ = 1.f; *dataPtr++ = -1.f;
*dataPtr++ = -1.f; *dataPtr++ = -1.f; *dataPtr++ = -1.f;
*dataPtr++ = 1.f; *dataPtr++ = -1.f; *dataPtr++ = -1.f;
*dataPtr++ = 1.f; *dataPtr++ = 1.f; *dataPtr++ = -1.f;
*indexPtr++ = 0; *indexPtr++ = 1;
*indexPtr++ = 1; *indexPtr++ = 2;
*indexPtr++ = 2; *indexPtr++ = 3;
*indexPtr++ = 3; *indexPtr++ = 0;
*indexPtr++ = 0; *indexPtr++ = 4;
*indexPtr++ = 1; *indexPtr++ = 5;
*indexPtr++ = 2; *indexPtr++ = 6;
*indexPtr++ = 3; *indexPtr++ = 7;
} else if (qobject_cast<QQuick3DDirectionalLight *>(m_light)) {
const double segment = M_PI * 2. / double(dirSegments);
for (quint16 i = 0; i < dirSegments; ++i) {
float x = float(qCos(i * segment));
float y = float(qSin(i * segment));
*dataPtr++ = x; *dataPtr++ = y; *dataPtr++ = 0.f;
*dataPtr++ = x; *dataPtr++ = y; *dataPtr++ = -1.f;
const quint16 base = i * 2;
*indexPtr++ = base; *indexPtr++ = base + 1;
*indexPtr++ = base; *indexPtr++ = base + 2;
}
// Adjust the final index to complete the circle
*(--indexPtr) = 0;
} else if (qobject_cast<QQuick3DPointLight *>(m_light)) {
const double innerRad = .3;
vertexSize = 0;
indexSize = 0;
int vertexIndex = 0;
for (quint16 i = 0; i < pointLightDensity; ++i) {
double latAngle = (((.9 / (pointLightDensity - 1)) * i) + .05) * M_PI;
quint16 longPoints = pointLightDensity * 2 * qSin(latAngle);
latAngle -= M_PI_2;
const double longSegment = M_PI * 2. / double(longPoints);
for (quint16 j = 0; j < longPoints; ++j) {
double longAngle = longSegment * j;
float q = float(qCos(latAngle));
float x = float(qCos(longAngle) * q);
float y = float(qSin(latAngle));
float z = float(qSin(longAngle) * q);
*dataPtr++ = x * innerRad; *dataPtr++ = y * innerRad; *dataPtr++ = z * innerRad;
*dataPtr++ = x; *dataPtr++ = y; *dataPtr++ = z;
*indexPtr++ = vertexIndex; *indexPtr++ = vertexIndex + 1;
vertexIndex += 2;
vertexSize += 6 * sizeof(float);
indexSize += 2 * sizeof(quint16);
}
}
vertexData.resize(vertexSize);
indexData.resize(indexSize);
}
static const float floatMin = std::numeric_limits<float>::lowest();
static const float floatMax = std::numeric_limits<float>::max();
auto vertexPtr = reinterpret_cast<QVector3D *>(vertexData.data());
minBounds = QVector3D(floatMax, floatMax, floatMax);
maxBounds = QVector3D(floatMin, floatMin, floatMin);
for (int i = 0; i < vertexSize / 12; ++i) {
minBounds[0] = qMin((*vertexPtr)[0], minBounds[0]);
minBounds[1] = qMin((*vertexPtr)[1], minBounds[1]);
minBounds[2] = qMin((*vertexPtr)[2], minBounds[2]);
maxBounds[0] = qMax((*vertexPtr)[0], maxBounds[0]);
maxBounds[1] = qMax((*vertexPtr)[1], maxBounds[1]);
maxBounds[2] = qMax((*vertexPtr)[2], maxBounds[2]);
++vertexPtr;
}
}
}
}
#endif // QUICK3D_MODULE

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#ifdef QUICK3D_MODULE
#include <QtQuick3D/private/qquick3dgeometry_p.h>
#include <QtQuick3D/private/qquick3dabstractlight_p.h>
namespace QmlDesigner {
namespace Internal {
class LightGeometry : public QQuick3DGeometry
{
Q_OBJECT
Q_PROPERTY(QQuick3DAbstractLight *light READ light WRITE setLight NOTIFY lightChanged)
public:
LightGeometry();
~LightGeometry() override;
QQuick3DAbstractLight *light() const;
public Q_SLOTS:
void setLight(QQuick3DAbstractLight *light);
Q_SIGNALS:
void lightChanged();
protected:
QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override;
private:
void fillVertexData(QByteArray &vertexData, QByteArray &indexData,
QVector3D &minBounds, QVector3D &maxBounds);
QQuick3DAbstractLight *m_light = nullptr;
};
}
}
QML_DECLARE_TYPE(QmlDesigner::Internal::LightGeometry)
#endif // QUICK3D_MODULE

View File

@@ -67,6 +67,7 @@
#include "../editor3d/generalhelper.h"
#include "../editor3d/mousearea3d.h"
#include "../editor3d/camerageometry.h"
#include "../editor3d/lightgeometry.h"
#include "../editor3d/gridgeometry.h"
#include "../editor3d/selectionboxgeometry.h"
#include "../editor3d/linegeometry.h"
@@ -104,6 +105,7 @@ void Qt5InformationNodeInstanceServer::createEditView3D()
qmlRegisterRevision<QQuick3DNode, 1>("MouseArea3D", 1, 0);
qmlRegisterType<QmlDesigner::Internal::MouseArea3D>("MouseArea3D", 1, 0, "MouseArea3D");
qmlRegisterType<QmlDesigner::Internal::CameraGeometry>("CameraGeometry", 1, 0, "CameraGeometry");
qmlRegisterType<QmlDesigner::Internal::LightGeometry>("LightGeometry", 1, 0, "LightGeometry");
qmlRegisterType<QmlDesigner::Internal::GridGeometry>("GridGeometry", 1, 0, "GridGeometry");
qmlRegisterType<QmlDesigner::Internal::SelectionBoxGeometry>("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry");
qmlRegisterType<QmlDesigner::Internal::LineGeometry>("LineGeometry", 1, 0, "LineGeometry");

View File

@@ -14,6 +14,7 @@
<file>mockfiles/MoveGizmo.qml</file>
<file>mockfiles/CameraFrustum.qml</file>
<file>mockfiles/CameraGizmo.qml</file>
<file>mockfiles/LightModel.qml</file>
<file>mockfiles/LightGizmo.qml</file>
<file>mockfiles/IconGizmo.qml</file>
<file>mockfiles/Overlay2D.qml</file>