qtqmlqt6qt3d

How applied a multiple textures images or one image into a cube in qt 6 with qml?


Hello I am learning Qt 3d in version 6.4.2 using QTCreator and qml and after researching in the official qt documentation and even here in stack overflow I did not find a way to put several images as faces of a cube or one texture image mapped in, I tried using CubeMapTexture but I get an error, I also tried with the material but I couldn't either

here is a minimal code to reproduce

import QtQuick
import QtQuick3D
import QtQuick3D.Effects
import QtQuick3D.Helpers
import QtQuick.Controls
import QtQuick.Layouts

Window {
    id: window
    width: 1280
    height: 720
    visible: true
    title: "Example"
    color: "#848895"

    SplitView {
        id: splitView
        anchors.fill: parent

        View3D {
            id: viewport
            SplitView.fillHeight: true
            SplitView.fillWidth: true
            SplitView.minimumWidth: splitView.width * 0.5
            environment: SceneEnvironment {
                property bool enableEffects: false
                antialiasingMode: SceneEnvironment.MSAA
                antialiasingQuality: SceneEnvironment.High
                lightProbe: Texture {
                    source: "maps/OpenfootageNET_garage-1024.hdr"
                }
                effects: enableEffects ? [bloom, scurveTonemap] : []
                backgroundMode: SceneEnvironment.SkyBox

                SCurveTonemap {
                    id: scurveTonemap
                }
                HDRBloomTonemap {
                    id: bloom
                }
            }

            Node {
                id: originNode
                PerspectiveCamera {
                    id: cameraNode
                    z: 600
                    clipNear: 1
                    clipFar: 10000
                }
            }

            PrincipledMaterial {
                id: basicMaterial
                baseColorMap: CubeMapTexture{
                    source: "maps/side.png"
                }
            }

            Model {
                id: cube
                source: "#Cube"
                materials: basicMaterial
                pickable: true
            }


            OrbitCameraController {
                origin: originNode
                camera: cameraNode
            }

            MouseArea {
                id: pickController
                anchors.fill: parent
                onClicked: function(mouse) {
                    let pickResult = viewport.pick(mouse.x, mouse.y);
                    if (pickResult.objectHit) {
                        let pickedObject = pickResult.objectHit;
                        // Move the camera orbit origin to be the clicked object
                        originNode.position = pickedObject.position
                    }
                }
            }

        }
    }
}

The error using CubeMapTexture is this "Sampler qt_BaseColorMap_sampler expects a 2D texture but the associated texture is a cube map. This will lead to problems." but in other ways I can't put multiple textures in the cube or just one texture and map it.


Solution

  • For the Texture consider using sourceItem. That will allow you to use traditional 2D components such as Image as your texture. In my example, I've used SVG images so that I can quickly apply a mixture of vector graphics to my textures. For you, you don't have to limit yourself to using Image as your sourceItem. You can choose, any 2D component, e.g. Item, Rectangle, Text, Label, Canvas, Shape, etc.

          materials: [
               DefaultMaterial {
                    diffuseMap: Texture {
                        sourceItem: Image {
                            anchors.centerIn: parent
                            width: 224
                            height: 224
                            source: "Dice1.svg"
                            sourceSize: Qt.size(width, height)
                            cache: false
                        }
                    }
                }
            ]
    

    If you use "#Cube", the Material(s) you use will be the same on all 6 sides. If you switch to using 6 "#Rectangle"s, you can use a different material for each rectangle. We can use this technique to create a 6-sided dice. Each face of the dice is rendered with its own SVG image:

    import QtQuick
    import QtQuick.Controls
    import QtQuick.Layouts
    import QtQuick3D
    Page {
        id: page
        background: Rectangle { color: "#848895" }
        header: Frame {
            background: Rectangle { color: "#eee" }
            CheckBox { id: chkLabels; text: qsTr("Labels"); checked: true }
        }
        Node {
            id: standAloneScene
            DirectionalLight { ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0) }
            Node {
                id: node
                Repeater3D {
                    model: [
                        ["Dice1.svg", 0, 0 ],
                        ["Dice6.svg", 0, 180 ],
                        ["Dice3.svg", 0, 90 ],
                        ["Dice4.svg", 0, -90 ],
                        ["Dice2.svg", 90, 0 ],
                        ["Dice5.svg", -90, 0 ],
                    ]
                    delegate: Node {
                        eulerRotation.x: modelData[1]
                        eulerRotation.y: modelData[2]
                        Model {
                            source: "#Rectangle"
                            materials: [
                                DefaultMaterial {
                                    diffuseMap: Texture {
                                        sourceItem: Item {
                                            anchors.centerIn: parent
                                            width: 224
                                            height: 224
                                            Image {
                                                anchors.fill: parent
                                                source: modelData[0]
                                                sourceSize: Qt.size(width, height)
                                                cache: false
                                            }
                                            Label {
                                                visible: chkLabels.checked
                                                anchors.horizontalCenter: parent.horizontalCenter
                                                anchors.bottom: parent.bottom
                                                anchors.bottomMargin: 10
                                                text: modelData[0]
                                                color: "white"
                                                Rectangle {
                                                    anchors.fill: parent
                                                    anchors.margins: -5
                                                    color: "blue"
                                                    border.color: "yellow"
                                                    radius: 5
                                                    z: -2
                                                }
                                            }
                                        }
                                    }
                                }
                            ]
                            z: 50
                        }
                    }
                }
            }
            OrthographicCamera {
                id: cameraOrthographicFront
                lookAtNode: node
                y: 800; z: 1000
                property double sc: 300/Math.max(Math.min(page.width, page.height), 1)
                scale: Qt.vector3d(sc, sc, 1)
            }
        }
        View3D {
            anchors.fill: parent
            importScene: standAloneScene
            camera: cameraOrthographicFront
        }
        NumberAnimation {
            target: node
            property: "eulerRotation.y"
            loops: Animation.Infinite
            running: true
            from: 720; to: 0
            duration: 10000
        }
        NumberAnimation {
            target: node
            property: "eulerRotation.x"
            loops: Animation.Infinite
            running: true
            from: 360; to: 0
            duration: 10000
        }
    }
    
    // Dice1.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <rect width="32" height="32" fill="#444"/>
    <circle cx="16" cy="16" r="4" fill="#800"/>
    </svg>
    
    // Dice2.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <rect width="32" height="32" fill="#444"/>
    <circle cx="24" cy="8" r="3" fill="#ccc"/>
    <circle cx="8" cy="24" r="3" fill="#ccc"/>
    </svg>
    
    // Dice3.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <rect width="32" height="32" fill="#444"/>
    <circle cx="24" cy="8" r="3" fill="#ccc"/>
    <circle cx="16" cy="16" r="3" fill="#ccc"/>
    <circle cx="8" cy="24" r="3" fill="#ccc"/>
    </svg>
    
    // Dice4.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <rect width="32" height="32" fill="#444"/>
    <circle cx="8" cy="8" r="3" fill="#800"/>
    <circle cx="24" cy="8" r="3" fill="#800"/>
    <circle cx="8" cy="24" r="3" fill="#800"/>
    <circle cx="24" cy="24" r="3" fill="#800"/>
    </svg>
    
    // Dice5.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <rect width="32" height="32" fill="#444"/>
    <circle cx="8" cy="8" r="3" fill="#ccc"/>
    <circle cx="24" cy="8" r="3" fill="#ccc"/>
    <circle cx="16" cy="16" r="3" fill="#ccc"/>
    <circle cx="8" cy="24" r="3" fill="#ccc"/>
    <circle cx="24" cy="24" r="3" fill="#ccc"/>
    </svg>
    
    // Dice6.svg
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
    <rect width="32" height="32" fill="#444"/>
    <circle cx="8" cy="8" r="3" fill="#ccc"/>
    <circle cx="8" cy="16" r="3" fill="#ccc"/>
    <circle cx="8" cy="24" r="3" fill="#ccc"/>
    <circle cx="24" cy="8" r="3" fill="#ccc"/>
    <circle cx="24" cy="16" r="3" fill="#ccc"/>
    <circle cx="24" cy="24" r="3" fill="#ccc"/>
    </svg>
    

    You can Try it Online!