Qt3D Different Material for different RenderPasses - qt

I have a QML Scene3D with 2 viewports, left and right half of window. The scene contains two cameras (one per viewport) and a torus mesh. I want to use a viewport-specific material for the same torus, i.e. different QMaterials (QEffects, QShaderPrograms, ...) when rendering in the left and right viewport respectively.
// main.qml
Entity {
id: rootEntity
components: [
MyFrameGraph {
camLeft: cameraLeft
camRight: cameraRight
},
InputSettings { }
]
Camera {
id: cameraLeft
projectionType: CameraLens.PerspectiveProjection
position: Qt.vector3d( 0.0, 0.0, -200.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
Camera {
id: cameraRight
projectionType: CameraLens.PerspectiveProjection
position: Qt.vector3d( 0.0, 200.0, 0.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
TorusMesh {
id: torusMesh
radius: 20
minorRadius: 5
}
Transform {
id:torusTransform
}
Material{
id: myTorusMaterial
effect: MyEffect{}
}
Entity {
id: torus
components: [torusMesh,torusTransform,myTorusMaterial]
}
}
My FrameGraph contains two branches for the two viewports, whereas the leaf nodes are RenderPassFilters.
//MyFrameGraph.qml
RenderSettings {
id: root
property Camera camLeft
property Camera camRight
activeFrameGraph: RenderSurfaceSelector {
id: surfaceSelector
Viewport {
id: mainViewport
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
ClearBuffers {
buffers: ClearBuffers.ColorDepthBuffer
clearColor: "black"
}
Viewport {
normalizedRect: Qt.rect(0.0, 0.0, 0.5, 1)
CameraSelector {
camera: root.camLeft
RenderStateSet {
renderStates: [
DepthTest {depthFunction: DepthTest.Less}
]
RenderPassFilter {
matchAny: [FilterKey { name: "pass"; value: "myMaterialLeft" }]
}
}
}
}
Viewport {
normalizedRect: Qt.rect(0.5, 0.0, 0.5, 1)
CameraSelector {
camera: root.camRight
RenderStateSet {
renderStates: [
DepthTest {depthFunction: DepthTest.Less}
]
RenderPassFilter {
matchAny: [FilterKey { name: "pass"; value: "myMaterialRight" }]
}
}
}
}
}
}
}
In my custom Material/Effects I use FilterKeys in the RenderPass object.
//MyEffect.qml
Effect {
id: root
property color maincolor: Qt.rgba(0.0, 1.0, 0.0, 1.0)
ShaderProgram {
id: myShaderLeft
vertexShaderCode: loadSource("qrc:/shader/myShaderLeft.vert")
fragmentShaderCode: loadSource("qrc:/shader/myShaderLeft.frag")
}
ShaderProgram {
id: myShaderRight
vertexShaderCode: loadSource("qrc:/shader/myShaderRight.vert")
fragmentShaderCode: loadSource("qrc:/shader/myShaderRight.frag")
}
parameters: [
Parameter {
name: "maincolor"
value: Qt.vector3d(root.maincolor.r, root.maincolor.g, root.maincolor.b)
}
]
techniques: [
Technique {
filterKeys: [FilterKey { name: "renderingStyle"; value: "forward" }]
graphicsApiFilter {
api: GraphicsApiFilter.OpenGL
profile: GraphicsApiFilter.CoreProfile
majorVersion: 3
minorVersion: 1
}
RenderPass {
id:renderPassLeft
filterKeys: [ FilterKey { name: "pass"; value: "myMaterialLeft" } ]
shaderProgram: myShaderLeft
renderStates: [CullFace { mode: CullFace.NoCulling }]
}
RenderPass {
id: renderPassRight
filterKeys: [ FilterKey { name: "pass"; value: "myMaterialRight" } ]
shaderProgram: myShaderRight
renderStates: [CullFace { mode: CullFace.NoCulling }]
}
renderPasses:[renderPassLeft,renderPassRight]
}
]
}
This works as expected, the object is rendered with myShaderLeft in the left viewport and with myShaderRight in the right viewport.
Now I want to use an default Qt-material (QMetalRoughMaterial) when rendering in the left viewport, and my custom material/effect when rendering in the right viewport. How can I achieve that?
An idea was to access the ShaderProgram of the MetalRoughMaterial through metalRougMaterial.effect.techniques[0].renderPasses[0].shaderProgram and use it one of the RenderPasses of my custom Material/Effect. However, metalRougMaterial.effect.techniques returns an undefined object.
MetalRoughMaterial {
id: metalRoughMaterial
baseColor: "red"
}

From the source code, it looks like effect is not a property that you can access on the material.
I'm not sure if this will work but I guess you could subclass the material in C++ and make the effect accessible. This way, you could modify it in QML, once you've registered it as a new QML type and used this QML type instead of the normal material one.
Another option that I can think of would be to create the object twice, once of the right viewport and once for the left. Then create two QLayers and add one to each and two respective QLayerFilters for each framegraph branch, to which you also add one layer each.
I gues computationally this comes down to the same load but you'd have to think about how setting position etc. works (I think you can add the same QTransform to both, but I'm not sure).
Last but not least you could probably recreate the whole material in QML completely (with your filter key) but that's probably a lot of work.

Related

How to create Undo/Redo operations in Qt3D?

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:
When the user hits CTRL+Z, create a new 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;
Then, to remove a sphere from the screen, call entityModel.remove() with the index of the sphere that needs to be erased;
The "Redo" operation simply does the opposite:
When the user hits CTRL+Y, the last element of the global list of 3d vectors holds the location of the lastest sphere removed: append this position to entityModel so the sphere can be rendered again;
Then, remember to erase this position from the global list so the next Undo operation can render a different sphere;
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()
}
}
}
}
}

Qt3d QML: how to add Text as overlay to a standard example

Longtime programmer here, but QML nube.
I wish to start a Qt project from the example: "Qt 3D: Shadow Map QML Example", which is readily available from the examples listed in QtCreator. Here's a link to it as well: https://doc.qt.io/qt-5/qt3d-shadow-map-qml-example.html
I want to first customize it by adding 2d text, which would ideally remain in a fixed position on the screen, remaining in view as the camera position / angle changed. I would settle for just being able to add some simple text to the screen in any fashion!
Starting with that example, I added a file:
Title.qml
import Qt3D.Core 2.12
import Qt3D.Extras 2.13
Entity {
id: titleText
components: [ Transform { translation: Qt.vector3d(0.0, 10.0, 30.0) } ]
Text2DEntity {
font.family: "Sans Serif"
font.pointSize: 100
color: "white"
text: "MY TITLE"
width: text.length * font.pointSize*2
height: font.pointSize * 4
}
}
Then, at the bottom of main.qml, I attempt to incorporate that:
import QtQuick 2.1 as QQ2
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
Entity {
id: sceneRoot
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: _window.width / _window.height
nearPlane: 0.1
farPlane: 1000.0
position: Qt.vector3d(0.0, 10.0, 20.0)
viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
upVector: Qt.vector3d(0.0, 1.0, 0.0)
}
FirstPersonCameraController { camera: camera }
ShadowMapLight {
id: light
}
components: [
ShadowMapFrameGraph {
id: framegraph
viewCamera: camera
lightCamera: light.lightCamera
},
// Event Source will be set by the Qt3DQuickWindow
InputSettings { }
]
AdsEffect {
id: shadowMapEffect
shadowTexture: framegraph.shadowTexture
light: light
}
// Trefoil knot entity
Trefoil {
material: AdsMaterial {
effect: shadowMapEffect
specularColor: Qt.rgba(0.5, 0.5, 0.5, 1.0)
}
}
// Toyplane entity
Toyplane {
material: AdsMaterial {
effect: shadowMapEffect
diffuseColor: Qt.rgba(0.9, 0.5, 0.3, 1.0)
shininess: 75
}
}
// Plane entity
GroundPlane {
material: AdsMaterial {
effect: shadowMapEffect
diffuseColor: Qt.rgba(0.2, 0.5, 0.3, 1.0)
specularColor: Qt.rgba(0, 0, 0, 1.0)
}
}
// -------------------------------------
// Title entity
Title {}
// -------------------------------------
}
I know for certain the Title entity is being included. I've add a sound effect to that onload and console.logs() to prove such (removed from this post). I have tried manipulating the entity in various ways, but it never appears. I think other components must be hiding it / blocking it / rendering it incompatible from being displayed...
A text2D Entity is aimed at putting text into your 3D scene (like putting some text tags on specific objects). I think you just want to put text on your screen as an overlay.
This can be done by using the standard QML Text type.
I adapted the your code and marked new lines with //ADDED. Lines you don't longer need are marked with //REMOVED
pro file:
You will need the 3dextras module in your pro file
QT += 3dextras
main.cpp
Change your main.cpp by using a QQuickView instead of Qt3DQuickWindow. the reason for this is that the rendering mechanisms between scene3D and Qt3DQuickWindow are different.
Scene3D uses the renderer of QML to do its rendering, while Qt3DQuickWindow will create a dedicated render thread. To put it in another way : if your program only needs to show the 3D environment then stick with Qt3DQuickWindow.
If you want to put text and buttons on top of your 3D environment use QQuickView.
#include <Qt3DQuickExtras/qt3dquickwindow.h>
#include <Qt3DQuick/QQmlAspectEngine>
#include <QGuiApplication>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickView>//ADDED
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
//ADDED:
QQuickView view;
view.rootContext()->setContextProperty("_window", &view);
view.setSource(QUrl("qrc:/main.qml"));
view.setWidth(1600);
view.setHeight(900);
view.show();
//REMOVED:
// Qt3DExtras::Quick::Qt3DQuickWindow view;
// view.resize(1600, 800);
// view.engine()->qmlEngine()->rootContext()->setContextProperty("_window", &view);
// view.setSource(QUrl("qrc:/main.qml"));
// view.show();
return app.exec();
}
main.qml
In the following example I use a Rectangle as the root and the Scene3D on the same level as a Text (in the top left corner) and a Button to show how you can combine standard QML types.
Rectangle {
anchors.fill: parent
Scene3D{
anchors.fill: parent
focus: true
aspects: ["input", "logic"]
Entity {
id: sceneRoot
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: _window.width / _window.height
nearPlane: 0.1
farPlane: 1000.0
position: Qt.vector3d(0.0, 10.0, 20.0)
viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
upVector: Qt.vector3d(0.0, 1.0, 0.0)
}
FirstPersonCameraController { camera: camera }
ShadowMapLight {
id: light
}
components: [
ShadowMapFrameGraph {
id: framegraph
viewCamera: camera
lightCamera: light.lightCamera
},
// Event Source will be set by the Qt3DQuickWindow
InputSettings { }
]
AdsEffect {
id: shadowMapEffect
shadowTexture: framegraph.shadowTexture
light: light
}
// Trefoil knot entity
Trefoil {
material: AdsMaterial {
effect: shadowMapEffect
specularColor: Qt.rgba(0.5, 0.5, 0.5, 1.0)
}
}
// Toyplane entity
Toyplane {
material: AdsMaterial {
effect: shadowMapEffect
diffuseColor: Qt.rgba(0.9, 0.5, 0.3, 1.0)
shininess: 75
}
}
// Plane entity
GroundPlane {
material: AdsMaterial {
effect: shadowMapEffect
diffuseColor: Qt.rgba(0.2, 0.5, 0.3, 1.0)
specularColor: Qt.rgba(0, 0, 0, 1.0)
}
}
}
}
Text {
id: title
text: qsTr("TITLE")
font.family: "Arial"
font.pointSize: 30
color: "black"
anchors.top:parent.top
anchors.left:parent.left
anchors.leftMargin: 20
anchors.topMargin: 20
}
}
EDIT
Here is a print screen of the example running on Windows10 with Qt5.13.2 MSVC2015 64bit and works also on Qt5.14.0 MSVC2015 64bit

QML 3D - change size (expand/reduce) of model rendered in UI to fit in the current window

I am rendering a 3D model using Mesh by reading from a .obj file, and I am trying to change its size dynamically to take the parent window's dimensions. Is there a way to resize the object? Currently when I run the app the model takes roughly half the height and one-third of the width of the main-window, and I am not sure where it picks it up from.
I have tried to use viewportRect in ForwardRenderer but that did not change the display. I was also trying to figure out if zooming with the camera would be possible, but from what I saw in the docs the zoom scale factor needs hardcoded integer values and again I need it to be dynamic.
The current display is like this -
Here is my code -
main.qml
Rectangle {
id: rootWindow
color: "black"
Visualizer {}
}
Visualizer.qml
import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Extras 2.12
import Qt3D.Input 2.12
import QtQuick.Scene3D 2.12
import QtQuick 2.12 as QQ2
Scene3D {
id: scene3d
anchors.fill: parent
focus: true
aspects: ["input", "logic"]
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
Entity {
id: sceneRoot
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
nearPlane: 0.1
farPlane: 1000.0
position: Qt.vector3d(0.0, 0.0, 40.0)
upVector: Qt.vector3d(0.0, 1.0, 0.0)
viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
}
FirstPersonCameraController {
camera: camera
}
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera
clearColor: "transparent"
Viewport {
id: viewport
normalizedRect: Qt.rect(0, 0, 1, 1)
}
}
},
InputSettings {
id: inputSettings
}
]
PhongMaterial {
id: material
}
Mesh {
id: sphereMesh
// source: "images/face3d/face_bse_mesh.obj"
source: "images/robo-obj-pose4/source/d2f0cff60afc40f5afe79156ec7db657.obj"
}
Transform {
id: modelTransform
property real userAngle: 0.0
matrix: {
var m = Qt.matrix4x4()
m.rotate(userAngle, Qt.vector3d(0, 1, 0))
// m.translate(Qt.vector3d(20, 0, 0))
return m
}
}
QQ2.NumberAnimation {
target: modelTransform
property: "userAngle"
duration: 10000
from: 0
to: 360
loops: QQ2.Animation.Infinite
running: true
}
Entity {
id: sphereEntity
components: [sphereMesh, material, modelTransform]
}
OrbitCameraController{
id: orbitCamera
camera: camera
}
}
}
So after a lot of asking around I have found the solution to this. It's a fairly simple enough trick.
You just need to add the following code in the Mesh, and that takes care of resizing the model in it's containing window.
Mesh {
----
onStatusChanged: {
if(status == Mesh.Ready)
camera.viewAll()
}
}
Sometimes while rendering the model its edges tend to go beyond the boundaries of the parent window. Adding some anchors.margins in the root Scene3D usually takes care of that.

QML 3D basic example

I am trying to create a basic QML application that will load a 3D model from a .obj file and display it on the screen and be able to rotate it along its axes during runtime. I went through some of the Qt examples and came up with the below code - most of which was borrowed from the working examples. But when I run it the model is not rendered properly.
The actual model looks like:
and currently my app shows up like
.
Here is the QML code -
import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Extras 2.12
Entity {
id: sceneRoot
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 1820 / 1080
nearPlane: 0.1
farPlane: 1000.0
position: Qt.vector3d(0.014, 0.956, 2.178)
upVector: Qt.vector3d(0.0, 1.0, 0.0)
viewCenter: Qt.vector3d(0.0, 0.7, 0.0)
}
Entity {
components: [
DirectionalLight {
intensity: 0.9
worldDirection: Qt.vector3d(0, 0.6, -1)
}
]
}
RenderSettings {
id: external_forward_renderer
activeFrameGraph: ForwardRenderer {
camera: camera
clearColor: "transparent"
}
}
Mesh {
id: roboMesh
source: "images/robo-obj-pose4/source/d2f0cff60afc40f5afe79156ec7db657.obj"
}
Entity {
id: circleEntity
property Material roboMaterial: PhongAlphaMaterial {
alpha: 0.4
ambient: "black"
diffuse: "black"
specular: "black"
shininess: 10000
}
components: [roboMesh, roboMaterial]
}
}
What am I missing here? Sorry for a really silly question but I am totally new to Qt3D and am confused as to what else needs to go in my code.
You don't necessarily need a material file as suggested by the comments, you can assign generic materials the way you do it you just have some other issues with your code.
First, you need to add the RenderSettings as a component to the root entity, like so:
Entity {
id: sceneRoot
components: [external_forward_renderer]
...
Secondly, "transparent" is not a valid clear color. Use something like Qt.rgba(0, 0.5, 1, 1).
Thirdly, you need to add file:// to the beginning of the mesh URL, unless you have the file included in a resources file. At least I needed that prefix, maybe you don't. You can check this by having a look at the application output in QtCreator. If it says "file does not exist" then add this prefix.
If you still can't see your mesh try adding InputSettings (which have to be added as a component as well) and a OrbitCameraController:
InputSettings {
id: inputSettings
}
OrbitCameraController{
camera: camera
}

Qt3D How to move the rotation axis to the centre of the object?

I am working on a simple 3D application where I am rotating the 3D object based on the Quaternion values that I read from the MPU6050 sensor.
I used the below code from simple-qml example as reference:
Entity {
id: sceneRoot
property real x: 0.5
property real y: -0.5
property real z: 0.5
property real w: 0.5
onWChanged: console.log("3W: "+w)
onXChanged: console.log("3X: "+x)
onYChanged: console.log("3Y: "+y)
onZChanged: console.log("3Z: "+z)
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 90
nearPlane : 0.1
farPlane : 100
position: Qt.vector3d( 0.0, 0.0, 40.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
FirstPersonCameraController { camera: camera }
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera
clearColor: "transparent"
}
},
InputSettings { }
]
PhongMaterial {
id: material
}
Mesh
{
id: arrowMesh
source: "/3dObj/resources/3dObj/arrow.obj"
}
Transform
{
id: arrowTransform
//Default/Reset position
//Arrow head facing towards the screen
//x:90,y:90,z:0
property int eXAngle: 90
property int eYAngle: 90
property int eZAngle: 0
rotation:
{
//MPU6050 gives values in quaternion
Qt.quaternion(sceneRoot.w,sceneRoot.x,sceneRoot.y,sceneRoot.z)
}
scale: 0.05
}
Entity {
id: sphereEntity
components: [ arrowMesh, material, arrowTransform ]
}
}
The problem I am facing is that rotation happens around the head of the arrow (3D object) instead the centre of the arrow and also the object for certain quaternion values zooms.
What are the things I need to change so that I can rotate the object alone around its center without any zoom effects?
Also, I tried the three projectionTypes as well.
I need the 3D to behave like the one in the youtube link below:
Arduino MPU6050 example

Resources