Unsolved Qt3D Problem with transparent object.
-
Hello. I'm adding a Sphere with a texture and a transparent Teapot to the scene. Everything is displayed as it should(pic 1). But when I swap the Sphere with the Teapot, the Sphere is always displayed in the foreground(pic 2) .
pic 1. Sphere with texture and transparent Teapot
Scene.qml
import QtQuick 2.0 import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Extras 2.0 import Qt3D.Input 2.0 Entity { id: scene objectName: "scene" property real cameraDistance: 100 function spherePos(pos, angle) { sphere.position = pos; sphere.angle = angle; } Camera { id: camera projectionType: CameraLens.PerspectiveProjection fieldOfView: 40 aspectRatio: _window.width / _window.height nearPlane : 0.1 farPlane : 1000.0 position: Qt.vector3d( 0.0, 100.0, 30 ) upVector: Qt.vector3d( 0.0, 0.0, 1.0 ) viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) } components: [ RenderSettings { activeFrameGraph: ForwardRenderer{ camera: camera clearColor: "white" } } ] Sphere { id: sphere } Teapot { } }
Sphere.qml
import QtQuick 2.0 import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Extras 2.0 Entity { property alias position: transform.translation property real angle: 0 onPositionChanged: { var x = cameraDistance * Math.cos(-(angle-180)*Math.PI/180) var y = cameraDistance * Math.sin(-(angle-180)*Math.PI/180) camera.upVector = Qt.vector3d( 0.0, 0.0, 1.0 ) camera.viewCenter = position camera.position = Qt.vector3d(x, y, 30).plus(position) } onAngleChanged: { var x = cameraDistance * Math.cos(-(angle-180)*Math.PI/180) var y = cameraDistance * Math.sin(-(angle-180)*Math.PI/180) camera.upVector = Qt.vector3d( 0.0, 0.0, 1.0 ) camera.viewCenter = position camera.position = Qt.vector3d(x, y, 30).plus(position) } Behavior on angle{ RotationAnimation { duration: 5000; direction: RotationAnimation.Shortest } } components: [ sphere, diffusematerial, transform ] DiffuseMapMaterial { id: diffusematerial ambient: Qt.rgba( 1, 1, 1, 1 ) diffuse: TextureLoader{ source: "qrc:/assets/textures/sphere.jpg" } shininess: 0 specular: Qt.rgba( 1, 1, 1, 1 ) textureScale: 4 } Transform { id: transform rotation: fromEulerAngles( angle+180, 90, 90 ) scale: 10 Behavior on translation { Vector3dAnimation { duration: 5000 } } } SphereMesh { id: sphere } }
Teapot.qml
import QtQuick 2.0 import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Extras 2.0 Entity { property alias position: transform.translation property real angle: 0 Behavior on angle{ RotationAnimation { duration: 5000; direction: RotationAnimation.Shortest } } components: [ mesh, alpha, transform ] PhongMaterial { id: material ambient: Qt.rgba( 1, 0, 0, 1 ) diffuse: Qt.rgba( 1, 0, 0, 1 ) shininess: 50 } PhongAlphaMaterial { id: alpha alpha: 0.9 ambient: Qt.rgba( 1, 0, 0, 1 ) diffuse: Qt.rgba( 1, 0, 0, 1 ) shininess: 50 } Transform { id: transform rotation: fromEulerAngles( angle+180, 90, 90 ) scale: 10 Behavior on translation { Vector3dAnimation { duration: 5000 } } } Mesh { id: mesh source: "qrc:/assets/mesh/teapot.obj" } }
pic 2. Swapped the Sphere and the Teapot
Scene.qml
import QtQuick 2.0 import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Extras 2.0 import Qt3D.Input 2.0 Entity { id: scene objectName: "scene" property real cameraDistance: 100 function tractorPos(pos, angle) { sphere.position = pos; sphere.angle = angle; } Camera { id: camera projectionType: CameraLens.PerspectiveProjection fieldOfView: 40 aspectRatio: _window.width / _window.height nearPlane : 0.1 farPlane : 1000.0 position: Qt.vector3d( 0.0, 100.0, 30 ) upVector: Qt.vector3d( 0.0, 0.0, 1.0 ) viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) } components: [ RenderSettings { activeFrameGraph: ForwardRenderer{ camera: camera clearColor: "white" } } ] Teapot { } Sphere { id: sphere } }
-
Why does the order of writing objects in the code affect their display?
-
Hi
Maybe it gets the zorder that way? -
@mrjj do you mean z buffer?
By the way, if use a material without transparency (for example: PhongMaterial). Order of objects does not affect the display
pic 1. Normal order of objects
pic 2. Order of objects is changed
I think I need to use custom FrameGraph. But, I do not understand how to write it to ensure, that transparency worked normally.
-
And the most interesting. Everything I described above appears in versions 5.6 and 5.9. And in versions 5.7 and 5.8 the behavior is different.
pic 1. Normal order of objects (5.7 and 5.8)
pic 2. Order of objects is changed (5.7 and 5.8)
-
I have similar problems whenever I try to rend any 3D object that uses a built-in material with alpha. It's like transparent objects stop writing depth values in z-buffer. And alpha blend stage looks weird too: it looks like pixels with alpha are not blended against the 3D viewport clear color but underlying window color or any other QML visual item that's beneath Scene3D object.
-
I think the intention is that you draw opaque objects, then draw transparent ones using the render graph system to set up multiple passes. This is a pain in the ass, and not at all clear from the documentation. (A lot of parts of Qt3D are still maturing.)
Traditionally, it's a common idiom in game rendering to draw all opaque objects with Z-writing enabled, then sort the transparent objects back to front and draw them with Z buffer writes disabled. The result is that you will blend a transparent object with whatever is behind it, and reject the fragment if it is behind something opaque. A reasonable person might expect Qt3D to do this for you, given the relatively high level expectations when working in something like QML, but c'est la vie. Qt3D tries to give you a bunch of flexibility to control the lower level fraw process of frame graph evaluation, rather than just being a trivial drawscene() API with a bunch of magic that isn't flexible. In moments of frustration, I have described the general philosophy as "making hard things somewhat easier by making some of the easy things much, much harder."
-
Also, I am like 90% sure that using https://doc.qt.io/qt-5.10/qt3drender-qsortpolicy.html in your frame graph and setting Qt3DRender::QSortPolicy::BackToFront will be useful in getting the transparency render pass working.
But right now the documentation is not quite fleshed out in this area. For example, the value of Qt3DRender::QSortPolicy::FrontToBack is just listed as a "?" in the table. So even the documentation is confused and has no real idea what exactly it is or how you are supposed to use it. Life is fun on the bleeding edge. So you are gonna need to do a bit of experimentation with setting up the frame graph in c++.
-
@wrosecrans Yeah, that makes sense. Thanks. I guess that built-in materials like Phong and PhongAlpha probably set their own render states when rendering. Just like you can set render states when building your own custom Material by filling renderSates list property in RenderPass.
And setting sorting in the frame graph takes care of the render sequence.
-
Glad to hear that sorting worked for you.
Obviously, if you are sorting geometry that is completely opaque, sorting it is a waste of time if you could just render it with a Z-buffer. So separating into several passes with filters, and tweaking what geometry gets filtered with what coarseness, how, is necessary if you are trying to push the limits of performance, etc. I have managed to grasp quite a bit of the theory, but actually taking advantage of all the bells and whistles in Qt3D in an optimal way still seems rather complex.
-
I have exact problem in this topic. If alphaBlending is true, last added object is shown fully in front of that object even though alpha value is 1 (completely opaque) like second picture in first post.
Since question is a bit old for Qt3D and answers are unclear, what can I do to fix this? I would like to see if there is an example.