Control a textured 3D object opacity in QML - qt

I am a bit new to Qt 3D in QML and I am trying to control the opacity of a textured 3D object.
I am using the simpleqml3d test project in order to do that.
I have played with the materials, but couldn't get it to work.
This is my modified IronMan.qml entity from the simpleqml3d test project:
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Extras 2.0
Entity {
id: root
property real x: 0
property real y: 0
property real z: 0
property real scale: 1.0
Texture2D{
id: texture
TextureImage {
source: "qrc:/man.png"
}
}
//COPY RenderableEntity.qml in your project!!!!!!
RenderableEntity{
id: chest
source: "qrc:/man.obj" //Path to iron man model. You can open it with 3D Builder on Windows 10
position: Qt.vector3d(root.x, root.y, root.z)
scale: root.scale
// material: DiffuseMapMaterial {
// id: material
// diffuse: texture
// specular: Qt.rgba( 0.2, 0.2, 0.2, 1.0 )
// shininess: 2.0
// }
// material: DiffuseMapMaterial {
// diffuse: texture
// specular: Qt.rgba( 0.2, 0.2, 0.2, 1.0 )
// shininess: 2.0
// }
// material: DiffuseSpecularMaterial {
// alphaBlending: true
// diffuse: Qt.rgba(0.2, 0.2, 0.2, 0.0)//texture
// specular: texture//Qt.rgba(0.2, 0.2, 0.2, 0.5)
// shininess: 2.0
// }
// material: PhongMaterial {
// ambient: Qt.rgba( 1, 0, 0, 0 )
// diffuse: Qt.rgba( 1, 0, 0, 0 )
// shininess: 50
// }
// material: PhongAlphaMaterial {
// alpha: 0.0
// diffuse: Qt.rgba(0.2, 0.2, 0.2, 0.0)//texture
// specular: Qt.rgba(0.2, 0.2, 0.2, 0.0)
// shininess: 2.0
// }
material: PhongAlphaMaterial {
alpha: 0.0
ambient: Qt.rgba( 1, 0, 0, 0 )
diffuse: Qt.rgba( 1, 0, 0, 0 )
shininess: 50
}
}
}
The commented materials are the materials I have played with. I couldn't get working not even with a PhongAlphaMaterial, when the opacity is set to 0.0 the model is still displayed like this:
Can somebody please help me control the textured 3D object opacity but also without loosing the texture?
Edit:
I have accepted Florian Blume's answer and because the answer is based on a Github repository I figured it's better to have the code also here, on StackOverflow in case something bad happens to his forked repository branch. So I will post here the sources that fully make the project work.
simpleqml3d.pro
TEMPLATE = app
QT += core gui widgets 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras
CONFIG += c++11
SOURCES += main.cpp
RESOURCES += resources.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
main.cpp
/****************************************************************************
**
** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <Qt3DQuickExtras/qt3dquickwindow.h>
#include <Qt3DQuick/QQmlAspectEngine>
#include <QGuiApplication>
#include <QQmlEngine>
#include <QQmlContext>
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
Qt3DExtras::Quick::Qt3DQuickWindow view;
// Expose the window as a context property so we can set the aspect ratio
view.engine()->qmlEngine()->rootContext()->setContextProperty("_window", &view);
view.setSource(QUrl("qrc:/main.qml"));
view.show();
return app.exec();
}
resources.qrc
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>IronMan.qml</file>
<file>man.obj</file>
<file>man.png</file>
<file>TextureAlphaMaterial.qml</file>
</qresource>
<qresource prefix="/shaders">
<file>unlittexture.frag</file>
<file>unlittexture.vert</file>
</qresource>
</RCC>
main.qml
/****************************************************************************
**
** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.1
import Qt3D.Core 2.0
import Qt3D.Render 2.9
import Qt3D.Input 2.0
import Qt3D.Extras 2.9
Entity {
id: root
objectName: "root"
// Use the renderer configuration specified in ForwardRenderer.qml
// and render from the mainCamera
components: [
RenderSettings {
activeFrameGraph: RenderSurfaceSelector {
id: renderSurfaceSelector
CameraSelector {
id: cameraSelector
camera: camera
Viewport {
id: viewport
normalizedRect: Qt.rect(0, 0, 1, 1)
ClearBuffers {
buffers: ClearBuffers.AllBuffers
clearColor: "white"
NoDraw{}
}
LayerFilter {
layers: [opaqueLayer]
}
LayerFilter {
layers: [opaqueLayer]
filterMode: LayerFilter.DiscardAllMatchingLayers
NoDepthMask {}
}
}
}
}
},
InputSettings { }
]
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d( 0.0, 4.0, -5.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
FirstPersonCameraController { camera: camera }
Entity {
components: [
PointLight {
enabled: parent.enabled
color: "black"
intensity: 0
}
]
}
Entity {
PlaneMesh {
id: groundMesh
width: 50
height: width
meshResolution: Qt.size(2, 2)
}
Transform {
id: groundTransform
translation: Qt.vector3d(0, 0, 0)
}
Layer {
id: opaqueLayer
}
PhongMaterial {
id: material
diffuse: Qt.rgba( 0.5, 0.5, 0.5, 1 )
ambient: Qt.rgba( 0.5, 0.5, 0.5, 1 )
}
components: [
groundMesh,
groundTransform,
material,
opaqueLayer
]
}
IronMan {
id: ironMan
}
}
IronMan.qml
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Extras 2.0
import QtQml 2.14
Entity {
id: root
property vector3d position: Qt.vector3d(0, 0, 0)
property real scale: 1.0
property real rotationAngle: 0.0
property vector3d rotationAxis: Qt.vector3d(1, 0, 0)
property alias source: mesh.source
property Material material
components: [ transform, mesh, material ]
Transform {
id: transform
scale: root.scale
rotation: fromAxisAndAngle(root.rotationAxis, root.rotationAngle)
translation: root.position
}
Mesh {
id: mesh
source: "qrc:/man.obj"
}
material: TextureAlphaMaterial {
id: material
opacity: 0.5
}
}
TextureAlphaMaterial.qml
import Qt3D.Core 2.0
import Qt3D.Render 2.0
Material {
id: root
property real opacity: 1.
parameters: [
Parameter {
name: "diffuseTexture"
value: Texture2D {
textureImages: [
TextureImage {
source: "qrc:/man.png"
}
]
}
}
]
effect: Effect {
id: rootEffect
parameters: [
Parameter
{
name: "opacity"
value: root.opacity
}
]
techniques: [
Technique {
graphicsApiFilter {
api: GraphicsApiFilter.OpenGL
profile: GraphicsApiFilter.CoreProfile
majorVersion: 3
minorVersion: 1
}
filterKeys: [ FilterKey { name: "renderingStyle"; value: "forward" } ]
renderPasses: [
RenderPass {
shaderProgram: ShaderProgram {
vertexShaderCode: loadSource("qrc:/shaders/unlittexture.vert")
fragmentShaderCode: loadSource("qrc:/shaders/unlittexture.frag")
}
renderStates: [
DepthTest {
depthFunction: DepthTest.LessOrEqual
},
NoDepthMask {
},
BlendEquation {
blendFunction: BlendEquation.Add
},
BlendEquationArguments {
sourceRgb: BlendEquationArguments.One
destinationRgb: BlendEquationArguments.OneMinusSourceAlpha
sourceAlpha: BlendEquationArguments.One
destinationAlpha: BlendEquationArguments.OneMinusSourceAlpha
}
]
}
]
}
]
}
}
unlittexture.frag
#version 150 core
uniform sampler2D diffuseTexture;
uniform float opacity;
in vec3 position;
in vec2 texCoord;
out vec4 fragColor;
void main()
{
fragColor = vec4(texture(diffuseTexture, texCoord).xyz * opacity, opacity);
}
unlittexture.vert
#version 150 core
in vec3 vertexPosition;
in vec2 vertexTexCoord;
out vec3 position;
out vec2 texCoord;
uniform mat4 modelView;
uniform mat4 mvp;
void main()
{
vec3 t = vec3(vertexTexCoord, 1.0);
texCoord = (t / t.z).xy;
position = vec3(modelView * vec4(vertexPosition, 1.0));
gl_Position = mvp * vec4(vertexPosition, 1.0);
}
Note:
You can replace man.obj and man.png with any 3D model(exported to obj using Blender or any other 3D software) or mapped texture respectively. Nevertheless they can be found on Florian's repository or on tripolskypetr's repository.
This is the end result:

Edit 2
I modified your project. It now shows the model with a transparent texture, you can find it on GitHub. Be sure to check out the branch transparent_texture.
I didn't implement functionality that allows setting the transparency dynamically but I think you can do that yourself starting from the example. The model is also unlit, i.e. only the texture is displayed without any lightning, but it should be easy to implement some simple phong lightning by looking at the other Qt3D materials.
Original Answer
Qt3D doesn't provide a material for transparent textured objects which means that you have to implement it yourself. I'll get back to that later.
Simple Transparency
Regarding your transparency issue, I played around with the code and got the following to work but without the buttons:
main.cpp:
#include <Qt3DQuickExtras/qt3dquickwindow.h>
#include <Qt3DQuick/QQmlAspectEngine>
#include <QGuiApplication>
#include <QQmlEngine>
#include <QQmlContext>
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
Qt3DExtras::Quick::Qt3DQuickWindow view;
view.engine()->qmlEngine()->rootContext()->setContextProperty("_window", &view);
view.setSource(QUrl("qrc:/main.qml"));
view.show();
return app.exec();
}
main.qml:
import QtQuick 2.1
import Qt3D.Core 2.0
import Qt3D.Render 2.9
import Qt3D.Input 2.0
import Qt3D.Extras 2.9
Entity {
id: root
objectName: "root"
// Use the renderer configuration specified in ForwardRenderer.qml
// and render from the mainCamera
components: [
RenderSettings {
activeFrameGraph: RenderSurfaceSelector {
id: renderSurfaceSelector
CameraSelector {
id: cameraSelector
camera: camera
Viewport {
id: viewport
normalizedRect: Qt.rect(0, 0, 1, 1)
ClearBuffers {
buffers: ClearBuffers.AllBuffers
clearColor: "white"
NoDraw{}
}
LayerFilter {
layers: [opaqueLayer]
}
LayerFilter {
layers: [opaqueLayer]
filterMode: LayerFilter.DiscardAllMatchingLayers
}
}
}
}
},
// Event Source will be set by the Qt3DQuickWindow
InputSettings { }
]
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d( 0.0, 4.0, -5.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
FirstPersonCameraController { camera: camera }
Entity {
components: [
PointLight {
enabled: parent.enabled
color: "black"
intensity: 0
}
]
}
Entity {
PlaneMesh {
id: groundMesh
width: 50
height: width
meshResolution: Qt.size(2, 2)
}
Transform {
id: groundTransform
translation: Qt.vector3d(0, 0, 0)
}
Layer {
id: opaqueLayer
}
PhongMaterial {
id: material
diffuse: Qt.rgba( 0.5, 0.5, 0.5, 1 )
ambient: Qt.rgba( 0.5, 0.5, 0.5, 1 )
}
components: [
groundMesh,
groundTransform,
material,
opaqueLayer
]
}
Entity {
id: sphere1
Mesh {
id: man
source: "qrc:/man.obj"
}
components: [
man,
matSphere1Material
]
PhongAlphaMaterial {
id: matSphere1Material
alpha: 0.1
ambient: Qt.rgba( 1, 1, 0, 0.0 )
diffuse: Qt.rgba( 1, 1, 0, 0.0 )
shininess: 50
}
}
}
I simplified your example to find out what the issue was and it looks like you used the wrong QML engine in the main.cpp. But I'd suggest you try out the Scene3DView example because there transparency works with a similar setup like yours (if you need buttons in your UI). I often use the examples and modify them to my needs. I just wanted to get you started with the code I provided.
If you ask yourself why I have LayerFilters in there, checkout my answer which explains why this is necessary when you have transparent objects in your scene.
Transparent Textured Objects
This is more difficult (and I don't have time to provide example code unfortunately, maybe start and then ask questions when something doesn't work). Here you have to implement your own shader. Qt3D simply doesn't offer any read-made implementation that takes alpha into account. One repository that always helped me a lot is the q3dpostproc repository. You can see how you can build your own Qt3D materials, load your own shaders and pass parameters to them.
There's also the Advanced Custom Material example which can provide a lot of help how to create custom shaders and pass on parameters.
If you want to see how to texture an object in a shader checkout the shader of QTextureMaterial and its code. I tried to recreate it in QML but it didn't work straight away.
I'd suggest you play around with the q3dpostproc code and try to texture one of the objects there (the structure of the project is a bit more complex because it's a showcase but after a while it all makes sense). It already has a shader that uses texturing because it draws everything to an offscreen buffer first and then uses that texture to draw the screen. After you've textured one of the objects successfully with your own shader you can do something like this in it:
fragColor = vec4(texture(...).xyz, 0.5);
This should give you a transparent texture. You probably just need to replace texture(...).xyz in the end with something more elaborate when you want to texture to be lit correctly. But for this you can check out the phong shader in the Qt3D GitHub repository that I linked or get one from this repository or somewhere else from the internet.
I hope this information helps.
Edit 1
I modified the q3dpostproc code to show transparent textures in a GitHub branch. The objects aren't lit yet but this should make the functioning clear.

Related

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

How to keep texture aspect ratio when the mesh dimensions change in Qt3D

I’m testing the current status of Qt3D. I’m very fond of the MetalRoughMaterial, but I can’t seem to handle this simple use case in Qt3D: I would like to use textures that repeat to fill the face they are on.
Desired result:
What I get is this (see code below):
In case you’re wondering, I made 2 cubes next to one another to make the 2nd image, but I don’t consider this a real solution…)
I have been experimenting with WrapMode, Qtexture, textureScale but can’t find a solution in Qt3D yet.
I noticed that when I change textureScale, this repeats the texture on all faces. But on the small faces we get the same amount of images as in the longer ones. Is there a way to change this for x, y and z differently?
code:
import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Input 2.12
import Qt3D.Extras 2.12
Entity {
id: sceneRoot
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer{
camera: camera
}
},
InputSettings { },
DirectionalLight {
worldDirection: Qt.vector3d(-1, -1, -1);
color: "white"
intensity: 2.0
}
]
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 800/600
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d( 2.0, 2.0, 2.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
OrbitCameraController { camera: camera }
CuboidMesh {
id: cuboidMesh
xExtent: 2
yExtent: 1
zExtent: 1
}
Transform {
id: cuboidTranslation
translation: Qt.vector3d(0, 0, 0)
}
Entity {
id: cuboidEntity
components: [ cuboidMesh, testMaterial, cuboidTranslation ]
}
MetalRoughMaterial {
id: testMaterial
baseColor: TextureLoader {
source: "qrc:/assets/textures/checkers.png"
}
metalness:0.0
roughness: 1.0
textureScale :1
}
}
I know how to do it in pure opengl(without Qt3D) by altering texturecoordinates of vertex data. If that is the direction to go I suspect I will have to make my own custom Mesh. Can somebody confirm this is the way to go? Or are there other solutions for this use case?
Thanks for your time reading this. Every help, suggestion is welcome, even the pure opengl solutions.
Yes, you can change texture coordinates in geometry, but I think it's easier to write custom shader, which gets proper texture coordinates from computations. For example, you can start with SimpleMaterial shader, modify it to display grid like you want. I had similar code for fragment shader:
#version 150 core
uniform vec3 boxSize;//all model
uniform vec2 wallSectionSize;//x y - size of cell inside this model
varying highp vec3 pos;
void main() {
vec3 pt = pos.xyz;
float x = pt.x;
float y = pt.y;
float z = pt.z;
bool side = false;
if(x==0 || x==boxSize.x) {
x = z;
side = true;
} else if(y==0 || y==boxSize.y) {
y = z;
}
//b == block number
const int nbx = int(x/wallSectionSize.x);
const int nby = int(y/wallSectionSize.y);//floor number from 0
//coordinates in this block umber
float bx = x - nbx * wallSectionSize.x;
float by = y - nby * wallSectionSize.y;
if(nbx % 2)
//fragColor = texture2D(...);
fragColor = vec4(1,1,0,0);
else
fragColor = vec4(1,0,1,0);
}
Also you can use textureScale property if your cube grows equally in all directions. In your example, where cube is not equally scaled, you can use textureTransform matrix. Also I created example which uses both approaches and a shader:
https://github.com/neurocod/StackOverflow/tree/master/texture-sapect-ratio

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
}

How to change the texture or colour of an object in Qt3D with QML?

I have a project, where i have one 3d object (.obj file) and i want to click on this object. For the first test i would be happy to change the texture or colour of the object. As far as i know it's called picking. Do you guys know how to manage this in qt3d? My whole project is written in qml, so it would be great if i could do the picking with qml (without c++), but if it's necessary im ready to try it that way, too.
My project is structured as followed:
I have an Entity as rootEntity and 3D-Entity, where my mesh is loaded. This structure is in an own qml file called View3d.qml. Now I set a Scene3D in my main.qml and load setup an instance of View3d.
I am using the Qt 5.5 beta with included qt3d on a windows 8.1 64Bit system, if its necessary.
The easiest way is that you add Texture to your .obj file with blender and then add it to your project .for doing this by using blender there is a lot of tutorials, see this How to Add Texture and this video.
another way is to use Texture and Texture2D
look at this code as an Example :
I have 2 qml class
in main.qml :
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Scene3D 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Scene3D
{
id : scene3d
anchors.fill: parent
focus: true
aspects: ["render", "logic", "input"]
hoverEnabled: true
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
antialiasing: true
RootEntity
{
id:root
}
}
}
and in RootEntity.qml :
import QtQuick 2.12
import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Input 2.12
import Qt3D.Extras 2.12
Entity {
id: sceneRoot
readonly property var textureModel: [texture1, texture2, texture3, texture4]
readonly property Texture texture1: TextureLoader {
source: "qrc:/images/image.png"
}
readonly property Texture texture2: TextureLoader {
source: "qrc:/images/wood.jpg"
}
readonly property Texture texture3: Texture2D {
format: Texture.RGBA8_UNorm
textureImages: TextureImage {
source:"qrc:/images/image.png"
}
}
readonly property Texture texture4: Texture2D {
format: Texture.RGBA8_UNorm
textureImages: TextureImage {
source:"qrc:/images/wood.jpg"
}
}
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d( 0.0, 20.0, -40.0 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
OrbitCameraController {
camera: camera
}
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
clearColor: "#333339"
camera: camera
}
},
// Event Source will be set by the Qt3DQuickWindow
InputSettings { }
]
CuboidMesh { id: mesh }
NodeInstantiator {
id: instantiator
model: sceneRoot.textureModel
Entity {
readonly property Transform transform: Transform {
readonly property real angle: model.index / instantiator.count * Math.PI * 2
translation: Qt.vector3d(Math.cos(angle) * 10, 0, Math.sin(angle) * 10)
scale: 10
}
readonly property DiffuseMapMaterial material: DiffuseMapMaterial {
diffuse: model.modelData
ambient: "white"
}
components: [ mesh, material, transform ]
}
}
}
the output is :
See the demos/qt3d/teaservice. This shows how to do picking (ie selection of an object using the mouse). Note you need the qt3d demo, not the QML teaservice.

Resources