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++:
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();
}
For opengl code you can find it in Florian Blume git project : here
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