QmlDesigner: Update light gizmos

Directional light model was made constant size, as it doesn't have
actual physical presence.

Spot light cone now shows the cone angle correctly and the length of
the cone is calculated so that 5% of the brightness reaches the
center of the cone bottom.

Area light rectangle matches the area of the light.

Point light mesh changed to three perpendicular circles.
Same formula for size of the circles used as for spotlight length.

All light types share a common brightness indicator arrow.

Task-number: QDS-2037
Change-Id: I534dbcda9cfa2a7768c2537868ba83818979b250
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Miikka Heikkinen
2020-05-04 17:42:22 +03:00
parent 4d23e6300f
commit a3e6e24427
11 changed files with 374 additions and 167 deletions

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** 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 LineGeometry 1.0
Arrow {
id: arrowRoot
property real length: 10
source: ""
Model {
geometry: LineGeometry {
id: lineGeometry
name: "Edit 3D ScalableArrow"
startPos: Qt.vector3d(0, 0, 0)
endPos: Qt.vector3d(0, 1, 0)
}
materials: [ arrowRoot.material ]
scale: Qt.vector3d(1, arrowRoot.length, 1)
}
Model {
id: arrowHead
source: "#Cone"
materials: [ arrowRoot.material ]
y: arrowRoot.length
scale: Qt.vector3d(0.02, 0.035, 0.02)
}
}

View File

@@ -25,7 +25,6 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick3D 1.15 import QtQuick3D 1.15
import MouseArea3D 1.0
DirectionalDraggable { DirectionalDraggable {
id: arrow id: arrow

View File

@@ -36,6 +36,7 @@ Model {
property bool dragging: mouseAreaYZ.dragging || mouseAreaXZ.dragging property bool dragging: mouseAreaYZ.dragging || mouseAreaXZ.dragging
property bool active: false property bool active: false
property MouseArea3D dragHelper: null property MouseArea3D dragHelper: null
property alias material: material
readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering
@@ -47,12 +48,14 @@ Model {
signal dragged(var mouseArea, vector3d sceneRelativeDistance, real relativeDistance) signal dragged(var mouseArea, vector3d sceneRelativeDistance, real relativeDistance)
signal released(var mouseArea, vector3d sceneRelativeDistance, real relativeDistance) signal released(var mouseArea, vector3d sceneRelativeDistance, real relativeDistance)
materials: DefaultMaterial { DefaultMaterial {
id: material id: material
emissiveColor: "white" emissiveColor: "white"
lighting: DefaultMaterial.NoLighting lighting: DefaultMaterial.NoLighting
} }
materials: [ material ]
function handlePressed(mouseArea, planePos) function handlePressed(mouseArea, planePos)
{ {
if (!targetNode) if (!targetNode)

View File

@@ -54,7 +54,7 @@ Item {
property Node selectedNode: null // This is non-null only in single selection case property Node selectedNode: null // This is non-null only in single selection case
property var selectedNodes: [] // All selected nodes property var selectedNodes: [] // All selected nodes
property var lightGizmos: [] property var lightIconGizmos: []
property var cameraGizmos: [] property var cameraGizmos: []
property var selectionBoxes: [] property var selectionBoxes: []
property rect viewPortRect: Qt.rect(0, 0, 1000, 1000) property rect viewPortRect: Qt.rect(0, 0, 1000, 1000)
@@ -278,29 +278,25 @@ Item {
function addLightGizmo(scene, obj) function addLightGizmo(scene, obj)
{ {
// Insert into first available gizmo // Insert into first available gizmo
for (var i = 0; i < lightGizmos.length; ++i) { for (var i = 0; i < lightIconGizmos.length; ++i) {
if (!lightGizmos[i].targetNode) { if (!lightIconGizmos[i].targetNode) {
lightGizmos[i].scene = scene; lightIconGizmos[i].scene = scene;
lightGizmos[i].targetNode = obj; lightIconGizmos[i].targetNode = obj;
return; return;
} }
} }
// No free gizmos available, create a new one // No free gizmos available, create a new one
var gizmoComponent = Qt.createComponent("LightGizmo.qml"); var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
var modelComponent = Qt.createComponent("LightModel.qml"); if (gizmoComponent.status === Component.Ready) {
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, var gizmo = gizmoComponent.createObject(overlayView,
{"view3D": overlayView, "targetNode": obj, {"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene, "selectedNodes": selectedNodes, "scene": scene,
"activeScene": activeScene}); "activeScene": activeScene});
lightGizmos[lightGizmos.length] = gizmo; lightIconGizmos[lightIconGizmos.length] = gizmo;
gizmo.clicked.connect(handleObjectClicked); gizmo.clicked.connect(handleObjectClicked);
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;}); gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
gizmo.activeScene = Qt.binding(function() {return activeScene;}); gizmo.activeScene = Qt.binding(function() {return activeScene;});
gizmo.connectModel(model);
} }
} }
@@ -338,10 +334,10 @@ Item {
function releaseLightGizmo(obj) function releaseLightGizmo(obj)
{ {
for (var i = 0; i < lightGizmos.length; ++i) { for (var i = 0; i < lightIconGizmos.length; ++i) {
if (lightGizmos[i].targetNode === obj) { if (lightIconGizmos[i].targetNode === obj) {
lightGizmos[i].scene = null; lightIconGizmos[i].scene = null;
lightGizmos[i].targetNode = null; lightIconGizmos[i].targetNode = null;
return; return;
} }
} }
@@ -360,9 +356,9 @@ Item {
function updateLightGizmoScene(scene, obj) function updateLightGizmoScene(scene, obj)
{ {
for (var i = 0; i < lightGizmos.length; ++i) { for (var i = 0; i < lightIconGizmos.length; ++i) {
if (lightGizmos[i].targetNode === obj) { if (lightIconGizmos[i].targetNode === obj) {
lightGizmos[i].scene = scene; lightIconGizmos[i].scene = scene;
return; return;
} }
} }
@@ -455,6 +451,13 @@ Item {
onRotateChange: viewRoot.changeObjectProperty(viewRoot.selectedNode, "eulerRotation") onRotateChange: viewRoot.changeObjectProperty(viewRoot.selectedNode, "eulerRotation")
} }
LightGizmo {
id: lightGizmo
targetNode: viewRoot.selectedNode
view3D: overlayView
dragHelper: gizmoDragHelper
}
AutoScaleHelper { AutoScaleHelper {
id: autoScale id: autoScale
view3D: overlayView view3D: overlayView

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -25,45 +25,138 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick3D 1.15 import QtQuick3D 1.15
import MouseArea3D 1.0
import LightGeometry 1.0
IconGizmo { Node {
id: lightGizmo id: lightGizmo
property Model lightModel: null property View3D view3D
property color overlayColor: targetNode ? targetNode.color : "transparent" property Node targetNode: null
property MouseArea3D dragHelper: null
iconSource: targetNode property color color: Qt.rgba(1, 1, 0, 1)
? targetNode instanceof DirectionalLight property real brightnessScale: targetNode ? Math.max(1.0, 1.0 + targetNode.brightness) : 100
? "image://IconGizmoImageProvider/directional.png:" + overlayColor property real fadeScale: {
: targetNode instanceof AreaLight // Value indicates area where intensity is above certain percent of total brightness.
? "image://IconGizmoImageProvider/area.png:" + overlayColor if (lightGizmo.targetNode instanceof SpotLight || lightGizmo.targetNode instanceof PointLight) {
: targetNode instanceof PointLight var l = targetNode.linearFade;
? "image://IconGizmoImageProvider/point.png:" + overlayColor var q = targetNode.quadraticFade;
: "image://IconGizmoImageProvider/spot.png:" + overlayColor var c = targetNode.constantFade;
: "image://IconGizmoImageProvider/point.png:" + overlayColor var d = 20; // divisor to target intensity value. E.g. 20 = 1/20 = 5%
if (l === 0 && q === 0)
function connectModel(model) l = 1;
{ // Solved from equation in shader:
lightModel = model; // 1 / d = 1 / (c + (l + q * dist) * dist);
if (q === 0)
model.selected = selected; return 100 * Math.max(((d - c) / l), 1);
model.selected = Qt.binding(function() {return selected;}); else
return 100 * ((Math.sqrt(4 * q * (d - c) + (l * l)) - l) / (2 * q));
model.scene = scene; } else {
model.scene = Qt.binding(function() {return scene;}); return 100;
}
model.targetNode = targetNode;
model.targetNode = Qt.binding(function() {return targetNode;});
model.color = lightGizmo.overlayColor;
model.color = Qt.binding(function() {return lightGizmo.overlayColor;});
model.visible = visible;
model.visible = Qt.binding(function() {return visible;});
} }
onActiveSceneChanged: { position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
if (lightModel && activeScene == scene) visible: lightGizmo.targetNode instanceof SpotLight
lightModel.updateGeometry(); || lightGizmo.targetNode instanceof AreaLight
|| lightGizmo.targetNode instanceof DirectionalLight
|| lightGizmo.targetNode instanceof PointLight
AutoScaleHelper {
id: autoScale
view3D: lightGizmo.view3D
}
Node {
rotation: !lightGizmo.targetNode ? Qt.quaternion(1, 0, 0, 0)
: lightGizmo.targetNode.sceneRotation
LightModel {
id: spotModel
property real coneScale: visible
? lightGizmo.fadeScale * Math.tan(Math.PI * targetNode.coneAngle / 180)
: 1
geometryName: "Edit 3D SpotLight"
geometryType: LightGeometry.Spot
color: lightGizmo.color
visible: lightGizmo.targetNode instanceof SpotLight
scale: Qt.vector3d(coneScale, coneScale, lightGizmo.fadeScale)
}
Node {
visible: lightGizmo.targetNode instanceof SpotLight
SpotLightHandle {
id: sphereHandle1
view3D: lightGizmo.view3D
material: lightMaterial
position: Qt.vector3d(0, spotModel.scale.y, -spotModel.scale.z)
}
SpotLightHandle {
id: sphereHandle2
view3D: lightGizmo.view3D
material: lightMaterial
position: Qt.vector3d(spotModel.scale.x, 0, -spotModel.scale.z)
}
SpotLightHandle {
id: sphereHandle3
view3D: lightGizmo.view3D
material: lightMaterial
position: Qt.vector3d(0, -spotModel.scale.y, -spotModel.scale.z)
}
SpotLightHandle {
id: sphereHandle4
view3D: lightGizmo.view3D
material: lightMaterial
position: Qt.vector3d(-spotModel.scale.x, 0, -spotModel.scale.z)
}
}
LightModel {
id: areaModel
geometryName: "Edit 3D AreaLight"
geometryType: LightGeometry.Area
color: lightGizmo.color
visible: lightGizmo.targetNode instanceof AreaLight
scale: visible ? Qt.vector3d(lightGizmo.targetNode.width / 2,
lightGizmo.targetNode.height / 2, 1)
.times(lightGizmo.targetNode.scale)
: Qt.vector3d(1, 1, 1)
}
LightModel {
id: directionalModel
geometryName: "Edit 3D DirLight"
geometryType: LightGeometry.Directional
color: lightGizmo.color
visible: lightGizmo.targetNode instanceof DirectionalLight
scale: autoScale.getScale(Qt.vector3d(50, 50, 50))
}
LightModel {
id: pointModel
geometryName: "Edit 3D PointLight"
geometryType: LightGeometry.Point
color: lightGizmo.color
visible: lightGizmo.targetNode instanceof PointLight
scale: Qt.vector3d(lightGizmo.fadeScale, lightGizmo.fadeScale, lightGizmo.fadeScale)
}
AdjustableArrow {
id: primaryArrow
eulerRotation: Qt.vector3d(-90, 0, 0)
targetNode: lightGizmo.targetNode
color: lightGizmo.color
view3D: lightGizmo.view3D
active: false
dragHelper: lightGizmo.dragHelper
scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
length: lightGizmo.brightnessScale / 10
}
DefaultMaterial {
id: lightMaterial
emissiveColor: lightGizmo.color
lighting: DefaultMaterial.NoLighting
cullMode: Material.NoCulling
}
} }
} }

View File

@@ -0,0 +1,43 @@
/****************************************************************************
**
** 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
IconGizmo {
id: lightIconGizmo
property color overlayColor: targetNode ? targetNode.color : "transparent"
iconSource: targetNode
? targetNode instanceof DirectionalLight
? "image://IconGizmoImageProvider/directional.png:" + overlayColor
: targetNode instanceof AreaLight
? "image://IconGizmoImageProvider/area.png:" + overlayColor
: targetNode instanceof PointLight
? "image://IconGizmoImageProvider/point.png:" + overlayColor
: "image://IconGizmoImageProvider/spot.png:" + overlayColor
: "image://IconGizmoImageProvider/point.png:" + overlayColor
}

View File

@@ -30,11 +30,8 @@ import LightGeometry 1.0
Model { Model {
id: lightModel id: lightModel
property string geometryName
property alias geometryName: lightGeometry.name // Name must be unique for each geometry property alias geometryName: lightGeometry.name // Name must be unique for each geometry
property Node targetNode: null property alias geometryType: lightGeometry.lightType
property Node scene: null
property bool selected: false
property color color property color color
function updateGeometry() function updateGeometry()
@@ -42,15 +39,13 @@ Model {
lightGeometry.update(); 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) scale: Qt.vector3d(50, 50, 50)
geometry: lightGeometry geometry: lightGeometry
materials: [ materials: [
DefaultMaterial { DefaultMaterial {
id: defaultMaterial id: defaultMaterial
emissiveColor: lightModel.selected ? lightModel.color : "#555555" emissiveColor: lightModel.color
lighting: DefaultMaterial.NoLighting lighting: DefaultMaterial.NoLighting
cullMode: Material.NoCulling cullMode: Material.NoCulling
} }
@@ -58,6 +53,5 @@ Model {
LightGeometry { LightGeometry {
id: lightGeometry id: lightGeometry
light: lightModel.scene && lightModel.targetNode ? lightModel.targetNode : null
} }
} }

View File

@@ -0,0 +1,45 @@
/****************************************************************************
**
** 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
Node {
id: handleRoot
property DefaultMaterial material
property View3D view3D
Model {
scale: autoScale.getScale(Qt.vector3d(0.1, 0.1, 0.1))
source: "#Sphere"
materials: [ handleRoot.material ]
}
AutoScaleHelper {
id: autoScale
view3D: handleRoot.view3D
}
}

View File

@@ -29,10 +29,6 @@
#include <QtQuick3DRuntimeRender/private/qssgrendergeometry_p.h> #include <QtQuick3DRuntimeRender/private/qssgrendergeometry_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrenderlight_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 <QtQuick3D/private/qquick3dspotlight_p.h>
#include <QtCore/qmath.h> #include <QtCore/qmath.h>
#include <limits> #include <limits>
@@ -49,25 +45,25 @@ LightGeometry::~LightGeometry()
{ {
} }
QQuick3DAbstractLight *QmlDesigner::Internal::LightGeometry::light() const LightGeometry::LightType LightGeometry::lightType() const
{ {
return m_light; return m_lightType;
} }
void QmlDesigner::Internal::LightGeometry::setLight(QQuick3DAbstractLight *light) void LightGeometry::setLightType(LightGeometry::LightType lightType)
{ {
if (m_light == light) if (m_lightType == lightType)
return; return;
m_light = light; m_lightType = lightType;
emit lightChanged(); emit lightTypeChanged();
update(); update();
} }
QSSGRenderGraphObject *LightGeometry::updateSpatialNode(QSSGRenderGraphObject *node) QSSGRenderGraphObject *LightGeometry::updateSpatialNode(QSSGRenderGraphObject *node)
{ {
if (!m_light) if (m_lightType == LightType::Invalid)
return node; return node;
node = QQuick3DGeometry::updateSpatialNode(node); node = QQuick3DGeometry::updateSpatialNode(node);
@@ -99,28 +95,26 @@ void LightGeometry::fillVertexData(QByteArray &vertexData, QByteArray &indexData
{ {
int vertexSize = 0; int vertexSize = 0;
int indexSize = 0; int indexSize = 0;
const int dirSegments = 12; // Segment lines in directional light circle const int arc = 12; // Segment lines per cone line in spot/directional light arc
const int spotArc = 6; // Segment lines per cone line in spotlight arc const int dirLines = 4; // Directional lines in spot/directional light
const int spotCone = 4; // Lines in spotlight cone const quint16 segments = arc * dirLines;
const int pointLightDensity = 5; const double segment = M_PI * 2. / double(segments);
if (qobject_cast<QQuick3DAreaLight *>(m_light)) { if (m_lightType == LightType::Area) {
// Area light model is a rectangle with perpendicular lines on corners // Area light model is a rectangle
vertexSize = int(sizeof(float)) * 3 * 8; vertexSize = int(sizeof(float)) * 3 * 4;
indexSize = int(sizeof(quint16)) * 8 * 2; indexSize = int(sizeof(quint16)) * 4 * 2;
} else if (qobject_cast<QQuick3DDirectionalLight *>(m_light)) { } else if (m_lightType == LightType::Directional) {
// Directional light model is a circle with perpendicular lines on circumference vertices // Directional light model is a circle with perpendicular lines on circumference vertices
vertexSize = int(sizeof(float)) * 3 * dirSegments * 2; vertexSize = int(sizeof(float)) * 3 * (segments + dirLines);
indexSize = int(sizeof(quint16)) * dirSegments * 2 * 2; indexSize = int(sizeof(quint16)) * (segments + dirLines) * 2;
} else if (qobject_cast<QQuick3DPointLight *>(m_light)) { } else if (m_lightType == LightType::Point) {
// Point light model is a set of lines radiating from central point. // Point light model is a set of three perpendicular circles
// We reserve more than we need so we don't have to calculate the actual need here, vertexSize = int(sizeof(float)) * 3 * segments * 3;
// and resize later when we know the exact count. indexSize = int(sizeof(quint16)) * segments * 2 * 3;
vertexSize = int(sizeof(float)) * 3 * pointLightDensity * pointLightDensity * 4; } else if (m_lightType == LightType::Spot) {
indexSize = int(sizeof(quint16)) * pointLightDensity * pointLightDensity * 4; vertexSize = int(sizeof(float)) * 3 * (segments + 1);
} else if (qobject_cast<QQuick3DSpotLight *>(m_light)) { indexSize = int(sizeof(quint16)) * (segments + dirLines) * 2;
vertexSize = int(sizeof(float)) * 3 * (spotArc * spotCone + 1);
indexSize = int(sizeof(quint16)) * (spotArc + 1) * spotCone * 2;
} }
vertexData.resize(vertexSize); vertexData.resize(vertexSize);
indexData.resize(indexSize); indexData.resize(indexSize);
@@ -128,89 +122,56 @@ void LightGeometry::fillVertexData(QByteArray &vertexData, QByteArray &indexData
auto dataPtr = reinterpret_cast<float *>(vertexData.data()); auto dataPtr = reinterpret_cast<float *>(vertexData.data());
auto indexPtr = reinterpret_cast<quint16 *>(indexData.data()); auto indexPtr = reinterpret_cast<quint16 *>(indexData.data());
if (qobject_cast<QQuick3DAreaLight *>(m_light)) { auto createCircle = [&](quint16 startIndex, float zVal, int xIdx, int yIdx, int zIdx) {
for (quint16 i = 0; i < segments; ++i) {
float x = float(qCos(i * segment));
float y = float(qSin(i * segment));
auto vecPtr = reinterpret_cast<QVector3D *>(dataPtr);
(*vecPtr)[xIdx] = x;
(*vecPtr)[yIdx] = y;
(*vecPtr)[zIdx] = zVal;
dataPtr += 3;
*indexPtr++ = startIndex + i; *indexPtr++ = startIndex + i + 1;
}
// Adjust the final index to complete the circle
*(indexPtr - 1) = startIndex;
};
if (m_lightType == LightType::Area) {
*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++ = 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++ = 0; *indexPtr++ = 1;
*indexPtr++ = 1; *indexPtr++ = 2; *indexPtr++ = 1; *indexPtr++ = 2;
*indexPtr++ = 2; *indexPtr++ = 3; *indexPtr++ = 2; *indexPtr++ = 3;
*indexPtr++ = 3; *indexPtr++ = 0; *indexPtr++ = 3; *indexPtr++ = 0;
} else if (m_lightType == LightType::Directional) {
createCircle(0, 0.f, 0, 1, 2);
*indexPtr++ = 0; *indexPtr++ = 4; // Dir lines
*indexPtr++ = 1; *indexPtr++ = 5; for (quint16 i = 0; i < dirLines; ++i) {
*indexPtr++ = 2; *indexPtr++ = 6; auto circlePtr = reinterpret_cast<float *>(vertexData.data()) + (3 * arc * i);
*indexPtr++ = 3; *indexPtr++ = 7; *dataPtr++ = *circlePtr; *dataPtr++ = *(circlePtr + 1); *dataPtr++ = -3.f;
} else if (qobject_cast<QQuick3DDirectionalLight *>(m_light)) { *indexPtr++ = i * arc;
const double segment = M_PI * 2. / double(dirSegments); *indexPtr++ = i + segments;
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 } else if (m_lightType == LightType::Point) {
*(--indexPtr) = 0; createCircle(0, 0.f, 0, 1, 2);
} else if (qobject_cast<QQuick3DPointLight *>(m_light)) { createCircle(segments, 0.f, 2, 0, 1);
const double innerRad = .3; createCircle(segments * 2, 0.f, 1, 2, 0);
vertexSize = 0; } else if (m_lightType == LightType::Spot) {
indexSize = 0; createCircle(0, -1.f, 0, 1, 2);
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);
} else if (qobject_cast<QQuick3DSpotLight *>(m_light)) {
const quint16 segments = spotArc * spotCone;
const double segment = M_PI * 2. / double(segments);
// Circle
for (quint16 i = 0; i < segments; ++i) {
float x = float(qCos(i * segment));
float y = float(qSin(i * segment));
*dataPtr++ = x; *dataPtr++ = y; *dataPtr++ = -2.f;
*indexPtr++ = i; *indexPtr++ = i + 1;
}
// Adjust the final index to complete the circle
*(indexPtr - 1) = 0;
// Cone tip // Cone tip
*dataPtr++ = 0.f; *dataPtr++ = 0.f; *dataPtr++ = 0.f; *dataPtr++ = 0.f; *dataPtr++ = 0.f; *dataPtr++ = 0.f;
quint16 tipIndex = segments; quint16 tipIndex = segments;
// Cone lines // Cone lines
for (quint16 i = 0; i < spotCone; ++i) { for (quint16 i = 0; i < dirLines; ++i) {
*indexPtr++ = tipIndex; *indexPtr++ = tipIndex;
*indexPtr++ = i * spotArc; *indexPtr++ = i * arc;
} }
} }

View File

@@ -28,7 +28,6 @@
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
#include <QtQuick3D/private/qquick3dgeometry_p.h> #include <QtQuick3D/private/qquick3dgeometry_p.h>
#include <QtQuick3D/private/qquick3dabstractlight_p.h>
namespace QmlDesigner { namespace QmlDesigner {
namespace Internal { namespace Internal {
@@ -36,19 +35,28 @@ namespace Internal {
class LightGeometry : public QQuick3DGeometry class LightGeometry : public QQuick3DGeometry
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QQuick3DAbstractLight *light READ light WRITE setLight NOTIFY lightChanged) Q_PROPERTY(LightType lightType READ lightType WRITE setLightType NOTIFY lightTypeChanged)
public: public:
enum class LightType {
Invalid,
Spot,
Area,
Directional,
Point
};
Q_ENUM(LightType)
LightGeometry(); LightGeometry();
~LightGeometry() override; ~LightGeometry() override;
QQuick3DAbstractLight *light() const; LightType lightType() const;
public Q_SLOTS: public Q_SLOTS:
void setLight(QQuick3DAbstractLight *light); void setLightType(LightType lightType);
Q_SIGNALS: Q_SIGNALS:
void lightChanged(); void lightTypeChanged();
protected: protected:
QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override; QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override;
@@ -56,7 +64,7 @@ protected:
private: private:
void fillVertexData(QByteArray &vertexData, QByteArray &indexData, void fillVertexData(QByteArray &vertexData, QByteArray &indexData,
QVector3D &minBounds, QVector3D &maxBounds); QVector3D &minBounds, QVector3D &maxBounds);
QQuick3DAbstractLight *m_light = nullptr; LightType m_lightType = LightType::Invalid;
}; };
} }

View File

@@ -16,7 +16,10 @@
<file>mockfiles/CameraFrustum.qml</file> <file>mockfiles/CameraFrustum.qml</file>
<file>mockfiles/CameraGizmo.qml</file> <file>mockfiles/CameraGizmo.qml</file>
<file>mockfiles/LightModel.qml</file> <file>mockfiles/LightModel.qml</file>
<file>mockfiles/LightIconGizmo.qml</file>
<file>mockfiles/LightGizmo.qml</file> <file>mockfiles/LightGizmo.qml</file>
<file>mockfiles/SpotLightHandle.qml</file>
<file>mockfiles/AdjustableArrow.qml</file>
<file>mockfiles/IconGizmo.qml</file> <file>mockfiles/IconGizmo.qml</file>
<file>mockfiles/Overlay2D.qml</file> <file>mockfiles/Overlay2D.qml</file>
<file>mockfiles/HelperGrid.qml</file> <file>mockfiles/HelperGrid.qml</file>