Transparency problem between QCustom3DVolume of the same Scatter3D
-
Hi,
Using Qt6.7 :I would like to display on a single Scatter3D a multitude of objects instantiated from a 'BallVolume' class derived from QCustom3DVolume. In this example, these objects are balls of different sizes, colours and transparencies, but they can also have a random shape.
You can see in the images below that the objects remain opaque to each other whatever the level of transparency I apply
I apply transparency in the definition of the colour table and also by playing with the alphaMultiplier parameter. I've also tried the preserveOpacity parameter.Is this the normal behaviour of Scatter3D or is there something I haven't understood?
If so, what solution can I use with Qt to display a multitude of items (a few hundred) of different shapes, different sizes, more or less transparent, of different colours and which are transparent in relation to each other (even if it means not using Datavisualization)?
Below my code
ballvolume.h
#define BALLVOLUME_H #include <QCustom3DVolume> #include <QtQml> class BallVolume : public QCustom3DVolume { Q_OBJECT QML_ELEMENT Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL) Q_PROPERTY(int alphaMin READ alphaMin WRITE setAlphaMin NOTIFY alphaMinChanged FINAL) Q_PROPERTY(int alphaMax READ alphaMax WRITE setAlphaMax NOTIFY alphaMaxChanged FINAL) Q_PROPERTY(double xScale READ xScale WRITE setXScale NOTIFY xScaleChanged FINAL) Q_PROPERTY(double yScale READ yScale WRITE setYScale NOTIFY yScaleChanged FINAL) Q_PROPERTY(double zScale READ zScale WRITE setZScale NOTIFY zScaleChanged FINAL) Q_PROPERTY(double xPosition READ xPosition WRITE setXPosition NOTIFY xPositionChanged FINAL) Q_PROPERTY(double yPosition READ yPosition WRITE setYPosition NOTIFY yPositionChanged FINAL) Q_PROPERTY(double zPosition READ zPosition WRITE setZPosition NOTIFY zPositionChanged FINAL) public: explicit BallVolume(QObject *parent = nullptr); virtual ~BallVolume(); QColor color() const; void setColor(const QColor &newColor); int alphaMin() const; void setAlphaMin(int newAlphaMin); int alphaMax() const; void setAlphaMax(int newAlphaMax); double xScale() const; void setXScale(double newXScale); double yScale() const; void setYScale(double newYScale); double zScale() const; void setZScale(double newZScale); double xPosition() const; void setXPosition(double newXPosition); double yPosition() const; void setYPosition(double newYPosition); double zPosition() const; void setZPosition(double newZPosition); signals: void colorChanged(); void alphaMinChanged(); void alphaMaxChanged(); void xScaleChanged(); void yScaleChanged(); void zScaleChanged(); void xPositionChanged(); void yPositionChanged(); void zPositionChanged(); private slots: void updateColorTable(); void updateScaling(); void updatePosiiton(); private: QList<uchar> *_textureData; QColor m_color; int m_alphaMin; int m_alphaMax; double m_xScale; double m_yScale; double m_zScale; double m_xPosition; double m_yPosition; double m_zPosition; }; #endif // BALLVOLUME_H
ballvolume.cpp
#include "ballvolume.h" BallVolume::BallVolume(QObject *parent) : QCustom3DVolume{parent}, _textureData{new QList<uchar>()}, m_color{Qt::red}, m_alphaMin{0}, m_alphaMax{255}, m_xScale{0.1}, m_yScale{0.1}, m_zScale{0.1}, m_xPosition{0.}, m_yPosition{0.}, m_zPosition{0.} { setTextureFormat(QImage::Format_Indexed8); setScalingAbsolute(false); updateColorTable(); int const width = 64; int const height = 64; int const depth = 64; int const halfWidth = width/2; int const halfHeight = height/2; int const halfDepth = depth/2; int const surface = width * height; int const volume = width * surface; _textureData->resize(volume); std::fill(_textureData->begin(), _textureData->end(), 0); double norm = width; norm = std::min(norm, double(height)); norm = std::min(norm, double(depth)); norm /=2.; for(int zIdx = 0 ; zIdx < depth ; ++zIdx){ int const zOffset = zIdx * surface; for(int yIdx = 0 ; yIdx < height ; ++yIdx){ int const yOffset = yIdx * width; int const yzOffset = yOffset + zOffset; for(int xIdx = 0 ; xIdx < width ; ++xIdx){ const int idx = xIdx + yzOffset; double const deltaX = double(xIdx - halfWidth); double const deltaY = double(yIdx - halfHeight); double const deltaZ = double(zIdx - halfDepth); double const radNorm = sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / norm; (*_textureData)[idx] = radNorm > 1. ? 0 : uchar(std::round(255.*(1.-radNorm))); } } } setTextureWidth(width); setTextureHeight(height); setTextureDepth(width); setTextureData(_textureData); connect(this, &BallVolume::colorChanged, this, &BallVolume::updateColorTable); connect(this, &BallVolume::alphaMinChanged, this, &BallVolume::updateColorTable); connect(this, &BallVolume::alphaMaxChanged, this, &BallVolume::updateColorTable); connect(this, &BallVolume::xScaleChanged, this, &BallVolume::updateScaling); connect(this, &BallVolume::yScaleChanged, this, &BallVolume::updateScaling); connect(this, &BallVolume::zScaleChanged, this, &BallVolume::updateScaling); connect(this, &BallVolume::xPositionChanged, this, &BallVolume::updatePosiiton); connect(this, &BallVolume::yPositionChanged, this, &BallVolume::updatePosiiton); connect(this, &BallVolume::zPositionChanged, this, &BallVolume::updatePosiiton); } BallVolume::~BallVolume() { delete _textureData; } void BallVolume::updateColorTable() { const int colorTableSize = 256; QList<QRgb> colorTable(colorTableSize); double const alphaRange = 255./double(m_alphaMax - m_alphaMin); for (int i = 0; i < colorTableSize; i++) { int alpha = (i - m_alphaMin) * alphaRange; alpha = alpha > m_alphaMax? m_alphaMax : alpha; alpha = alpha < m_alphaMin? m_alphaMin : alpha; QColor clr = m_color; clr.setAlpha(alpha); colorTable[i] = clr.rgba(); } setColorTable(colorTable); } void BallVolume::updateScaling() { setScaling(QVector3D(m_xScale, m_yScale, m_zScale)); //Defaults to QVector3D(0.1, 0.1, 0.1). } void BallVolume::updatePosiiton() { setPosition(QVector3D(m_xPosition, m_yPosition, m_zPosition)); //Defaults to QVector3D(0.0, 0.0, 0.0) } QColor BallVolume::color() const { return m_color; } void BallVolume::setColor(const QColor &newColor) { if (m_color == newColor) return; m_color = newColor; emit colorChanged(); } int BallVolume::alphaMin() const { return m_alphaMin; } void BallVolume::setAlphaMin(int newAlphaMin) { if (m_alphaMin == newAlphaMin) return; m_alphaMin = newAlphaMin; emit alphaMinChanged(); } int BallVolume::alphaMax() const { return m_alphaMax; } void BallVolume::setAlphaMax(int newAlphaMax) { if (m_alphaMax == newAlphaMax) return; m_alphaMax = newAlphaMax; emit alphaMaxChanged(); } double BallVolume::xScale() const { return m_xScale; } void BallVolume::setXScale(double newXScale) { if (qFuzzyCompare(m_xScale, newXScale)) return; m_xScale = newXScale; emit xScaleChanged(); } double BallVolume::yScale() const { return m_yScale; } void BallVolume::setYScale(double newYScale) { if (qFuzzyCompare(m_yScale, newYScale)) return; m_yScale = newYScale; emit yScaleChanged(); } double BallVolume::zScale() const { return m_zScale; } void BallVolume::setZScale(double newZScale) { if (qFuzzyCompare(m_zScale, newZScale)) return; m_zScale = newZScale; emit zScaleChanged(); } double BallVolume::xPosition() const { return m_xPosition; } void BallVolume::setXPosition(double newXPosition) { if (qFuzzyCompare(m_xPosition, newXPosition)) return; m_xPosition = newXPosition; emit xPositionChanged(); } double BallVolume::yPosition() const { return m_yPosition; } void BallVolume::setYPosition(double newYPosition) { if (qFuzzyCompare(m_yPosition, newYPosition)) return; m_yPosition = newYPosition; emit yPositionChanged(); } double BallVolume::zPosition() const { return m_zPosition; } void BallVolume::setZPosition(double newZPosition) { if (qFuzzyCompare(m_zPosition, newZPosition)) return; m_zPosition = newZPosition; emit zPositionChanged(); }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/multiScatterCustom3DVolume/Main.qml")); QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
Main.qml
import QtQuick import QtQuick.Controls import QtDataVisualization import multiScatterCustom3DVolume Window { id : mnWnd width: 640 height: 480 visible: true title: qsTr("Hello multiScatterCustom3DVolume") BallVolume{ id : ball1 color : "red" } BallVolume{ id : ball2 color : "green" } Scatter3D { anchors.top: parent.top anchors.right : parent.right anchors.left : parent.left anchors.bottom : scatterCtr.top orthoProjection: true aspectRatio: 1.0 Component.onCompleted: { addCustomItem(ball1) addCustomItem(ball2) } } Column{ id : scatterCtr anchors.right : parent.right anchors.left : parent.left anchors.bottom : parent.bottom BallCtrl{ ball : ball1 anchors.right : parent.right anchors.left : parent.left ballScaling: 0.5 ballYPos : 0.25 ballAlphaMult : 0.05 } BallCtrl{ ball : ball2 anchors.right : parent.right anchors.left : parent.left } } }
BallCtr.qml
import QtQuick import QtQuick.Controls Item { property QtObject ball: scale.text property real ballAlphaMult : 1. property real ballScaling : 0.1 property real ballXPos : 0. property real ballYPos : 0. property real ballZPos : 0. height : childrenRect.height onBallChanged: { updateBallScaling() updateXPos() updateYPos() updateZPos() updateBallAlphaMult() } onBallScalingChanged: updateBallScaling() onBallXPosChanged: updateXPos() onBallYPosChanged: updateYPos() onBallZPosChanged: updateZPos() onBallAlphaMultChanged: updateBallAlphaMult() function updateBallScaling(){ if (ball !== null) ball.xScale = ballScaling if (ball !== null) ball.yScale = ballScaling if (ball !== null) ball.zScale = ballScaling } function updateXPos(){ if (ball !== null) ball.xPosition = ballXPos} function updateYPos(){ if (ball !== null) ball.yPosition = ballYPos} function updateZPos(){ if (ball !== null) ball.zPosition = ballZPos} function updateBallAlphaMult(){ if (ball !== null) ball.alphaMultiplier = ballAlphaMult} Column { anchors.right : parent.right anchors.left : parent.left Row{ Label { text : "Scale"} TextInput{ id : scale text : Number(ballScaling) onTextEdited: {ballScaling = Number(text)} } } Row{ Label { text : "Position"} TextInput{id : xPos ; width : 100 ; text : Number(ballXPos) ; onTextEdited: ballXPos = Number(text)} TextInput{id : yPos ; width : 100 ; text : Number(ballYPos) ; onTextEdited: ballYPos = Number(text)} TextInput{id : zPos ; width : 100 ; text : Number(ballZPos) ; onTextEdited: ballZPos = Number(text)} } RangeSlider { id : alphaSlider anchors.right : parent.right anchors.left : parent.left from: 0 to: 255 first.value : 0 second.value : 255 ToolTip.visible: first.pressed || second.pressed ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval ToolTip.text: "[" + first.value.toFixed(2) + ";" + second.value.toFixed(2) + "]" first.onValueChanged: if (ball !== null) ball.alphaMin = first.value second.onValueChanged: if (ball !== null) ball.alphaMax = second.value } Slider{ id : alphaMultSlider anchors.right : parent.right anchors.left : parent.left value : Number(ballAlphaMult) onValueChanged : ballAlphaMult = value ToolTip.visible: pressed ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval ToolTip.text: value.toFixed(2) } } }
CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(multiScatterCustom3DVolume VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.4 REQUIRED COMPONENTS Quick DataVisualization) qt_standard_project_setup() qt_add_executable(appmultiScatterCustom3DVolume main.cpp ) qt_add_qml_module(appmultiScatterCustom3DVolume URI multiScatterCustom3DVolume VERSION 1.0 QML_FILES Main.qml SOURCES ballvolume.h ballvolume.cpp QML_FILES BallCtrl.qml ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an # explicit, fixed bundle identifier manually though. set_target_properties(appmultiScatterCustom3DVolume PROPERTIES # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appmultiScatterCustom3DVolume MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE ) target_link_libraries(appmultiScatterCustom3DVolume PRIVATE Qt6::Quick Qt::DataVisualization ) include(GNUInstallDirs) install(TARGETS appmultiScatterCustom3DVolume BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
-
-