I created some entities using qt3d in QML. For example, this code shows a Scene3D
element that declares RootEntity
which is another QML element that contains the scene graph:
Scene3D
{
id : scene3d
anchors.fill: parent
focus: true
aspects: ["render", "logic", "input"]
hoverEnabled: true
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
antialiasing: true
RootEntity
{
id:root
}
}
RootEntity.qml:
Entity {
id:root
property double x : 0.0
Camera {
id: mainCamera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d(0.0, 4.49373, -3.78577)
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d(0.0, 0.5, 0.0)
}
OrbitCameraController
{
id: mainCameraController
camera: mainCamera
}
components: [
RenderSettings {
Viewport {
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
RenderSurfaceSelector {
CameraSelector {
id: cameraSelector
camera: mainCamera
FrustumCulling {
ClearBuffers {
buffers: ClearBuffers.AllBuffers
clearColor: "#444449"
NoDraw {}
}
LayerFilter {
filterMode: LayerFilter.DiscardAnyMatchingLayers
layers: [topLayer]
}
LayerFilter {
filterMode: LayerFilter.AcceptAnyMatchingLayers
layers: [topLayer]
ClearBuffers {
buffers: ClearBuffers.DepthBuffer
}
}
}
}
}
}
},
InputSettings {}
]
Layer {
id: topLayer
recursive: true
}
ListModel {
id: entityModel
ListElement { x:0;y:0;z:0 }
}
NodeInstantiator
{
id:instance
model: entityModel
delegate: Entity {
id: sphereEntity
components: [
SphereMesh
{
id:sphereMesh
radius: 0.3
},
PhongMaterial
{
id: materialSphere
ambient:"red"
},
Transform {
id: transform
translation:Qt.vector3d(x, y, z)
}
]
}
}
MouseDevice
{
id: mouseDev
}
MouseHandler
{
id: mouseHandler
sourceDevice: mouseDev
onPressed:
{
x++;
entityModel.append({"x":x,"y":0.0,"z": Math.random()})
}
}
}
When the mouse is clicked in my Scene3D, one sphere is displayed.
I don't know how to delete a specific Entity or create undo/redo effect by hitting Ctrl+Z and Ctrl+Shift+Z in Qt3d. Thanks.
One approach is to maintain a global list of Qt.vector3d
elements and use it to record the position of the spheres that are removed with the "Undo" operation:
Qt.vector3d
object to store the position of the last sphere rendered (that is, the one that was last appended to entityModel
) and add that position to the global list of 3d vectors;entityModel.remove()
with the index of the sphere that needs to be erased;The "Redo" operation simply does the opposite:
entityModel
so the sphere can be rendered again;RootEntity.qml:
import QtQuick 2.0
import QtQml.Models 2.15
import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Extras 2.12
import Qt3D.Input 2.12
Entity {
id: root
// global list of Qt.vector3d elements that store the location of the spheres that are removed
property variant removedSpheres : []
// x-coordinate of the next sphere that will be added
property double x : 0.0
Camera {
id: mainCamera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d(0.0, 4.49373, -3.78577)
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d(0.0, 0.5, 0.0)
}
OrbitCameraController {
id: mainCameraController
camera: mainCamera
}
components: [
RenderSettings {
Viewport {
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
RenderSurfaceSelector {
CameraSelector {
id: cameraSelector
camera: mainCamera
FrustumCulling {
ClearBuffers {
buffers: ClearBuffers.AllBuffers
clearColor: "#444449"
NoDraw {}
}
LayerFilter {
filterMode: LayerFilter.DiscardAnyMatchingLayers
layers: [topLayer]
}
LayerFilter {
filterMode: LayerFilter.AcceptAnyMatchingLayers
layers: [topLayer]
ClearBuffers {
buffers: ClearBuffers.DepthBuffer
}
}
}
}
}
}
},
InputSettings {}
]
Layer {
id: topLayer
recursive: true
}
ListModel {
id: entityModel
ListElement { x: 0; y: 0; z: 0 }
}
NodeInstantiator {
id: instance
model: entityModel
delegate: Entity {
id: sphereEntity
components: [
SphereMesh { id:sphereMesh; radius: 0.3 },
PhongMaterial { id: materialSphere; ambient:"red" },
Transform { id: transform; translation:Qt.vector3d(x, y, z) }
]
}
}
MouseDevice {
id: mouseDev
}
MouseHandler {
id: mouseHandler
sourceDevice: mouseDev
onPressed:
{
if (mouse.button === Qt.LeftButton)
{
console.log("LeftButton: new sphere")
// add new sphere
entityModel.append( {"x" : ++root.x, "y" : 0.0, "z" : Math.random()} )
}
if (mouse.button === Qt.MiddleButton)
{
console.log("MiddleButton: clear spheres")
// removes all spheres (can't be undone)
root.x = 0;
entityModel.clear();
removedSpheres.length = 0;
}
}
}
KeyboardDevice {
id: keyboardDev
}
KeyboardHandler {
id: keyboardHandler
sourceDevice: keyboardDev
focus: true
onPressed: {
// handle CTRL+Z: undo
if (event.key === Qt.Key_Z && (event.modifiers & Qt.ControlModifier))
{
console.log("CTRL+Z")
// remove the last sphere added to the screen
let lastIdx = entityModel.count - 1;
if (lastIdx >= 0)
{
// save sphere position before removal
removedSpheres.push(Qt.vector3d(entityModel.get(lastIdx).x, entityModel.get(lastIdx).y, entityModel.get(lastIdx).z));
// remove sphere from the model
entityModel.remove(lastIdx);
}
}
// handle CTRL+Y: redo
if (event.key === Qt.Key_Y && (event.modifiers & Qt.ControlModifier))
{
console.log("CTRL+Y")
// add the last sphere removed back into the model
if (removedSpheres.length > 0)
{
// add the sphere
let lastIdx = removedSpheres.length - 1;
entityModel.append( {"x" : removedSpheres[lastIdx].x, "y" : removedSpheres[lastIdx].y, "z" : removedSpheres[lastIdx].z} )
// erase the last item added to removedSpheres
removedSpheres.pop()
}
}
}
}
}