Jacob Krieg
Jacob Krieg

Reputation: 3164

Control a textured 3D object opacity in QML

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:

enter image description here

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:

enter image description here

Upvotes: 4

Views: 1995

Answers (1)

Florian Blume
Florian Blume

Reputation: 3345

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.

Upvotes: 2

Related Questions