I am developping a 3D color picker cube in QML, I have developpe the cube textures but I don't know how to code the color picking.
I want when i click on a cube face to have the color on which I clicked, is it possible to do it in qml ?
Here is my code for the cube :
Entity {
id: root
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: cubeTransform.translation
}
CustomCameraController {
id: mainCameraController
camera: mainCamera
}
components: [
DirectionalLight{
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(1, 0, 0)
},
DirectionalLight{
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, 1, 0)
},
DirectionalLight{
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(-1, 0, 0)
},
DirectionalLight{
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, -1, 0)
},
DirectionalLight{
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, 0, 1)
},
DirectionalLight{
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, 0, -1)
},
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: "black"
NoDraw {}
}
LayerFilter {
filterMode: LayerFilter.DiscardAnyMatchingLayers
layers: [topLayer]
}
LayerFilter {
filterMode: LayerFilter.AcceptAnyMatchingLayers
layers: [topLayer]
ClearBuffers {
buffers: ClearBuffers.DepthBuffer
}
}
}
}
}
}
},
InputSettings {}
]
Layer {
id: topLayer
recursive: true
}
Entity {
id: cubeEntity
Texture2D {
id: cubeTexture
TextureImage {
source: "qrc:/texture.png"
}
}
Mesh {
id: cubeMesh
source: "qrc:/cube.obj"
}
Transform {
id: cubeTransform
}
ObjectPicker {
id: cubePicker
onClicked: {
console.log("x : " + pick.localIntersection.normalized().x)
console.log("y : " + pick.localIntersection.normalized().y)
console.log("z : " + pick.localIntersection.normalized().z)
}
}
NormalDiffuseMapMaterial{
id: cubeMaterial
diffuse: cubeTexture
normal: cubeTexture
specular: "black"
shininess: 50
}
components: [cubeMesh, cubeTransform, cubeMaterial, cubePicker]
}
}
I add, a picture of my actual cube if someone could help me, it will be great
Here is the answer for the color picking using qml, opengl and c++:
C++ classes
pixelvaluereader.h
#pragma once
#include <QObject>
#include <Qt3DRender/QRenderCaptureReply>
class PixelValueReader : public QObject
{
Q_OBJECT
public:
explicit PixelValueReader(QObject *parent = nullptr);
Q_INVOKABLE QColor getColor(Qt3DRender::QRenderCaptureReply *reply, int x, int y);
signals:
void newColor(QColor color);
};
pixelvaluereader.cpp
#include "pixelvaluereader.h"
#include <QDebug>
PixelValueReader::PixelValueReader(QObject* parent)
: QObject(parent)
{
}
QColor PixelValueReader::getColor(Qt3DRender::QRenderCaptureReply* reply, int x, int y)
{
QRgb pixel = reply->image().pixel(x, y);
int red = qRed(pixel);
int blue = qBlue(pixel);
int green = qGreen(pixel);
int alpha = qAlpha(pixel);
qDebug() << red * 0xFF000000 + green * 0xFF0000 + blue * 0xFF00 + alpha;
if (red * 0xFF000000 + green * 0xFF0000 + blue * 0xFF00 + alpha > 0) {
emit newColor(QColor(pixel));
qDebug() << "color : " << QColor(pixel).name(); // here is the color of the pixel
}
// RGBA captures the ID but since we masked and right shifted the respective values in the shader
// (e.g. (red & 0xFF000000) >> 24 for red) to prevent overflow in the color values we have to
// undo the shift here again.
return QColor(pixel);
}
main.cpp
#include <Qt3DRender/QAbstractTextureImage>
#include <Qt3DQuickExtras/qt3dquickwindow.h>
#include <Qt3DQuick/QQmlAspectEngine>
#include <QGuiApplication>
#include <QQmlContext>
#include <QQmlEngine>
#include "pixelvaluereader.h"
//Q_DECLARE_METATYPE(Qt3DRender::QAbstractTextureImage)
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
QVector<QVector3D> pos;
pos << QVector3D(1, 1, 0);
pos << QVector3D(-1, 2, 8);
pos << QVector3D(1, 1, 7);
pos << QVector3D(0, 0, 4);
pos << QVector3D(1, 5, 1);
pos << QVector3D(-3, 3, 0);
pos << QVector3D(2, 2, -2);
PixelValueReader *valueReader = new PixelValueReader();
qmlRegisterType<PixelValueReader>("PixelValueReader", 1, 0, "PixelValueReader");
Qt3DExtras::Quick::Qt3DQuickWindow view;
view.setTitle("Instanced Rendering");
view.resize(1600, 800);
view.engine()->qmlEngine()->rootContext()->setContextProperty("_window", &view);
view.engine()->qmlEngine()->rootContext()->setContextProperty("pixelValueReader", valueReader);
view.setSource(QUrl("qrc:/main.qml"));
view.show();
return app.exec();
}
Opengl
For opengl code you can find it in Florian Blume git project : here
QML
main.qml
import QtQuick 2.1 as QQ2
import Qt3D.Core 2.0
import Qt3D.Render 2.10
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
Entity {
components: [
rendSettings,
inputSettings,
light1,
light2,
light3,
light4,
light5,
light6
]
DirectionalLight{
id: light1
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(1, 0, 0)
}
DirectionalLight{
id: light2
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, 1, 0)
}
DirectionalLight{
id: light3
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(-1, 0, 0)
}
DirectionalLight{
id: light4
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, -1, 0)
}
DirectionalLight{
id: light5
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, 0, 1)
}
DirectionalLight{
id: light6
color: "#e0eef0"
intensity: 0.4
enabled: true
worldDirection: Qt.vector3d(0, 0, -1)
}
InputSettings { id: inputSettings }
RenderSettings {
id: rendSettings
activeFrameGraph: RenderSurfaceSelector {
id: surfaceSelector
Viewport {
normalizedRect: Qt.rect(0, 0, 1, 1)
CameraSelector {
camera: camera
ClearBuffers {
buffers: ClearBuffers.ColorDepthBuffer
clearColor: "transparent"
FrustumCulling {
DepthTest {
depthFunction: DepthTest.LessOrEqual
RenderPassFilter {
matchAny: []
}
RenderPassFilter {
matchAny: []
RenderTargetSelector {
target: rt
TextureRenderTarget {
id: rt
width: surfaceSelector.surface ? surfaceSelector.surface.width : 512
height: surfaceSelector.surface ? surfaceSelector.surface.height : 256
}
RenderCapture {
id: renderCapture
}
}
}
}
}
}
}
}
}
}
MouseDevice {
id: mouseDevice
}
MouseHandler {
sourceDevice: mouseDevice
property var reply
property bool isHold: false
property var x
property var y
onReleased: {
if (!isHold) {
x = mouse.x
y = mouse.y
doRenderCapture()
}
isHold = false;
}
onPositionChanged: {
if (mouse.buttons === 1){
isHold = true
}
}
function doRenderCapture() {
reply = renderCapture.requestCapture()
reply.completeChanged.connect(onRenderCaptureCompleted)
}
function onRenderCaptureCompleted() {
var color = pixelValueReader.getColor(reply, x, y)
}
}
Camera {
id: camera
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: cubeTransform.translation
}
CustomCameraController {camera: camera}
Entity {
id: cubeEntity
Texture2D {
id: cubeTexture
TextureImage {
source: "qrc:/texture.png"
}
}
Mesh {
id: cubeMesh
source: "qrc:/cube.obj"
}
Transform {
id: cubeTransform
}
NormalDiffuseMapMaterial{
id: cubeMaterial
diffuse: cubeTexture
normal: cubeTexture
specular: "black"
shininess: 50
}
components: [cubeMesh, cubeTransform, cubeMaterial]
}
}
TextureRenderTarget.qml
import Qt3D.Core 2.0
import Qt3D.Render 2.0
RenderTarget {
id: rt
property real width: 512
property real height: 512
property alias colorTexture: colorTexture
property variant depthTexture
attachments : [
RenderTargetOutput {
attachmentPoint: RenderTargetOutput.Color0
texture: Texture2D {
id: colorTexture
width: rt.width
height: rt.height
format: Texture.RGBA8_UNorm
minificationFilter: Texture.Linear
magnificationFilter: Texture.Linear
}
},
RenderTargetOutput {
attachmentPoint: RenderTargetOutput.Depth
texture : Texture2D {
id: depthTexture
width: rt.width
height: rt.height
format: Texture.D32
minificationFilter: Texture.Linear
magnificationFilter: Texture.Linear
comparisonFunction: Texture.CompareLessEqual
comparisonMode: Texture.CompareRefToTexture
}
}
]
}
My CustomCameraController don't change
I am trying to rotate my stl. file in the screen in x,y,z dimensions. My whole main.qml code is here:
ApplicationWindow
{
visible: true
width: 640
height: 480
title: qsTr("3D Viewer")
header: ToolBar
{
ToolButton
{
text: "Open 3D Model"
onPressed:
{
fileDialog.open()
}
}
}
FileDialog
{
id: fileDialog
onAccepted:
{
sceneLoader.source = fileDialog.fileUrl
}
}
Scene3D
{
anchors.fill: parent
aspects: ["input", "logic"]
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
Entity
{
id: sceneRoot
Camera
{
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 90
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 100.0
position: Qt.vector3d( 0.0,-40.0, 10.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 10.0, 0.0, 0.0 )
}
OrbitCameraController
{
camera: camera
}
components: [
RenderSettings
{
activeFrameGraph: ForwardRenderer
{
clearColor: Qt.rgba(0.0,1, 1, 1)
camera: camera
}
},
InputSettings
{
}
]
Entity
{
id: satEntity
components: [
SceneLoader
{
id: sceneLoader
}
]
Transform {
id: satTransform
scale: 0.3
rotation: Qt.vector3d(0.0, 0.0, 0.0)
translation: Qt.vector3d(0.0, 0.0, 1)
rotationX: 0
rotationY: 0
rotationZ: 0
}
}
}
}
}
But its rotation doesn't change even I change the rotationX, rotationY, and rotationZ. Moreover there is no error it works but it always in the same position. It is basic but I don't know where I fail.
I have solved the problem and I share it for one who may see the same problem in the future.
ApplicationWindow
{
visible: true
width: 640
height: 480
title: qsTr("3D Viewer")
header: ToolBar
{
ToolButton
{
text: "Open 3D Model"
onPressed:
{
fileDialog.open()
}
}
}
FileDialog
{
id: fileDialog
onAccepted:
{
sceneLoader.source = fileDialog.fileUrl
}
}
Scene3D
{
anchors.fill: parent
aspects: ["input", "logic"]
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
Entity
{
id: sceneRoot
Camera
{
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 90
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 100.0
position: Qt.vector3d( 0.0,-40.0, 10.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 10.0, 0.0, 0.0 )
}
OrbitCameraController
{
camera: camera
}
components: [
RenderSettings
{
activeFrameGraph: ForwardRenderer
{
clearColor: Qt.rgba(0.0,1, 1, 1)
camera: camera
}
},
InputSettings
{
}
]
Entity
{
id: satEntity
components: [
SceneLoader
{
id: sceneLoader
},
Transform {
id: satTransform
rotationX: 0 //you can type whatever you want.
rotationY: 0 //you can type whatever you want.
rotationZ: 0 //you can type whatever you want.
}
]
}
}
}
}
I want to implement a coverflow in QML but having a problem with the angle animation.
Scrolling to the left (from number 1→18→17→...) works great, but right scrolling is not behaving as expected. I'm not sure I got the angles right but they seem to animate from -40°→0° which looks odd (correct would be from 40°→0).
Is there a way to correct this behavior?
Here is a working example of my code:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
visible: true
width: 1280
height: 800
MouseArea {
anchors.fill: parent
onWheel: {
if (wheel.angleDelta.y < 0)
{
view.incrementCurrentIndex()
}
else if (wheel.angleDelta.y > 0)
{
view.decrementCurrentIndex()
}
}
}
PathView {
id: view
property int itemAngle: 40.0
property int itemSize: width/3.5
anchors.fill: parent
pathItemCount: 10
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
interactive: true
model: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
delegate: viewDelegate
path: Path {
startX: 0
startY: height / 2
PathPercent { value: 0.0 }
PathAttribute { name: "z"; value: 0 }
PathAttribute { name: "angle"; value: view.itemAngle }
PathAttribute { name: "origin"; value: 0 }
PathLine {x: view.width*0.4; y: view.height / 2}
PathPercent { value: 0.45 }
PathAttribute { name: "angle"; value: view.itemAngle }
PathAttribute { name: "origin"; value: 0 }
PathAttribute { name: "z"; value: 10 }
PathLine { relativeX: 0; relativeY: 0 }
PathAttribute { name: "angle"; value: 0.0 }
PathAttribute { name: "origin"; value: 0 }
PathAttribute { name: "z"; value: 10 }
PathLine {x: view.width*0.6; y: view.height / 2}
PathPercent { value: 0.55 }
PathAttribute { name: "angle"; value: 0.0 }
PathAttribute { name: "origin"; value: 0 }
PathAttribute { name: "z"; value: 10 }
PathLine { relativeX: 0; relativeY: 0 }
PathAttribute { name: "angle"; value: -view.itemAngle }
PathAttribute { name: "origin"; value: view.itemSize }
PathAttribute { name: "z"; value: 10 }
PathLine {x: view.width; y: view.height / 2}
PathPercent { value: 1 }
PathAttribute { name: "angle"; value: -view.itemAngle }
PathAttribute { name: "origin"; value: view.itemSize }
PathAttribute { name: "z"; value: 0 }
}
}
Component {
id: viewDelegate
Rectangle {
id: flipItem
width: view.itemSize
height: view.height
color: "white"
z: PathView.z
property var rotationAngle: PathView.angle
property var rotationOrigin: PathView.origin
transform:
Rotation {
id: rot
axis { x: 0; y: 1; z: 0 }
angle: rotationAngle
origin.x: rotationOrigin
origin.y: width
Behavior on angle { PropertyAnimation{} }
}
Rectangle {
border.color: "black"
border.width: 2
color: (index%2 === 0) ? "yellow" : "royalblue"
anchors.top: flipItem.top
anchors.topMargin: 100
anchors.left: flipItem.left
anchors.right: flipItem.right
width: flipItem.width
height: flipItem.height*0.55
smooth: true
antialiasing: true
Text {
text: model.modelData
color: "gray"
font.pixelSize: 30
font.bold: true
anchors.centerIn: parent
}
}
}
}
}
I have created a path view with a delegate and model. Is it possible to change current index of the PathView via mouse wheel instead of mouse click drag?
Following is my PathView code:
PathView {
id: pathView;
anchors.fill: parent;
model: sampleModel;
delegate: delegate;
path: Path {
startX: 45; startY: 100
PathAttribute { name: "iconScale"; value: 0.3 }
PathAttribute { name: "iconOpacity"; value: 0.1 }
PathQuad { x: 45; y: 300; controlX: 45; controlY: 200 }
PathAttribute { name: "iconScale"; value: 1 }
PathAttribute { name: "iconOpacity"; value: 1 }
PathQuad { x: 45; y: 500; controlX: 45; controlY: 400 }
}
}
I had the the same problem. Here is my solution:
Every time a wheel event occurs, I in/decrement a "wheelIndex" and set the view.currentIndex to this value.
To reset the wheelIndex after the wheel usage, I use a timer:
PathView {
id: view
anchors.fill: parent
focus: true
model: monthModel
property int wheelIndex:- 1;
currentIndex: 0;
MouseArea {
anchors.fill: parent
preventStealing: true;
propagateComposedEvents: true
Timer {
id:wheelTimer
interval: 200;
running: false;
repeat: false
onTriggered: {
view.wheelIndex = -1;
}
}
onWheel: {
wheelTimer.start();
if (view.wheelIndex === -1) {
view.wheelIndex = view.currentIndex;
}
if (wheel.angleDelta.y > 0) {
view.wheelIndex++
if (view.wheelIndex > view.model.count) {
view.wheelIndex = 0;
}
view.currentIndex = view.wheelIndex;
} else {
view.wheelIndex--;
if (view.wheelIndex < 0) {
view.wheelIndex = view.model.count - 1;
}
view.currentIndex = view.wheelIndex;
}
}
}
}
by adding a MouseArea as child to your PathView with anchors.fill:parent and implementing the onWheel() event as follow :
PathView{
id:view
......
MouseArea{
id:mouse
anchors.fill: parent
onWheel:
{
if( wheel.angleDelta.y > 0 ) view.incrementCurrentIndex();
else view.decrementCurrentIndex();
}
}
you'll get it working with both ,mouse drag and mouse scroll (wheel).For more info look at QtQuick 5.0: WheelEvent
I have been trying to implement a scroll kind of thing using the Pathview element of QML.Below image shows the progress
I want the reduce the distance between the Calendar and the Messaging element. Please help.
Below is my code of the scroll.
import QtQuick 2.0
Rectangle {
// property real rotationOrigin: PathView.origin
id: scroll
width: 800; height: 480
color: "white"
// property real rotationAngle
ListModel {
id: appModel
ListElement { name: "Music"; icon: "pics/AudioPlayer_48.png" }
ListElement { name: "Movies"; icon: "pics/VideoPlayer_48.png" }
ListElement { name: "Camera"; icon: "pics/Camera_48.png" }
ListElement { name: "Calendar"; icon: "pics/DateBook_48.png" }
ListElement { name: "Messaging"; icon: "pics/EMail_48.png" }
/*ListElement { name: "Todo List"; icon: "pics/TodoList_48.png" }
ListElement { name: "Contacts"; icon: "pics/AddressBook_48.png" }*/
}
Component {
id: appDelegate
Item {
id: item
width: 240; height: 80
scale: PathView.iconScale
property real rotationAngle: PathView.angle
transform: Rotation {
id: rotation
origin.x: item.width/2
origin.y: item.height/2
axis.x: 1; axis.y:0 ; axis.z: 0
angle: rotationAngle
}
Image {
id: myIcon
y: 20; anchors.verticalCenter: parent.verticalCenter
source: icon
smooth: true
}
Text {
anchors {
leftMargin: 10
left: myIcon.right; verticalCenter: parent.verticalCenter }
text: name
font.pointSize: 25
smooth: true
}
MouseArea {
anchors.fill: parent
onClicked: {
view.currentIndex = index
console.log("onClicked" + index);
}
}
}
}
Component {
id: appHighlight
Rectangle { width: 240; height: 80; color: "lightsteelblue" }
}
PathView {
Keys.onRightPressed: if (!moving) { incrementCurrentIndex(); console.log(moving) }
Keys.onLeftPressed: if (!moving) decrementCurrentIndex()
id: view
anchors.fill: parent
highlight: appHighlight
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
focus: true
model: appModel
delegate: appDelegate
path: Path {
startX: scroll.width/2
startY: 0
PathAttribute { name: "z"; value: 0 }
PathAttribute { name: "angle"; value: 75 }
PathAttribute { name: "iconScale"; value: 0.85 }
PathLine { x: scroll.width / 2; y: scroll.height / 4; }
PathAttribute { name: "z"; value: 50 }
PathAttribute { name: "angle"; value: 70 }
PathAttribute { name: "iconScale"; value: 0.85 }
PathLine { x: scroll.width /2; y: scroll.height/2; }
PathAttribute { name: "z"; value: 100 }
PathAttribute { name: "angle"; value: 0 }
PathAttribute { name: "iconScale"; value: 1.0 }
PathLine { x: scroll.width /2; y: 3*(scroll.height/4); }
PathAttribute { name: "z"; value: 50 }
PathAttribute { name: "angle"; value: -70 }
PathAttribute { name: "iconScale"; value: 0.85 }
PathLine { x: scroll.width /2; y: scroll.height; }
PathAttribute { name: "z"; value: 0 }
PathAttribute { name: "angle"; value: -75 }
PathAttribute { name: "iconScale"; value: 0.85 }
}
}
}
Did you try with PathPercent? Take a look here:
http://qmlbook.github.io/en/ch06/index.html#the-pathview