Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Rendering large 2D panoramic image (13503×6935) using QtQuick3D on Raspberry Pi 5 – OpenGL ES max texture size limitation
Forum Updated to NodeBB v4.3 + New Features

Rendering large 2D panoramic image (13503×6935) using QtQuick3D on Raspberry Pi 5 – OpenGL ES max texture size limitation

Scheduled Pinned Locked Moved Unsolved Qt for Python
1 Posts 1 Posters 82 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Maharshi
    wrote last edited by
    #1

    Hello everybody!

    On the Raspberry Pi 5, attempting to load the full image as a 3D texture results in rendering failure (black or distorted output) due to the hardware's 4096x4096 texture size limit. The same code works flawlessly on other system (in Windows) , where the larger texture size is supported.

    I do not want to resize the image, as it leads to unacceptable quality loss for this use case (detailed panoramic view with interactive orbiting).

    Environment

    • Hardware: Raspberry Pi 5
    • GPU / API: OpenGL ES
    • Max texture size (glGetIntegerv): 4096
    • OS: Raspberry Pi OS (Wayland)
    • Python : 3.13.5
    • PySide6 : 6.10.1
    • Qt Modules: QtQuick, QtQuick3D
    • Image format: PNG
    • Image resolution : 13503 x 6935

    What I've tried :

    • By Tiling the Image with CustomeMaterial and shaders (Not Working )
    • Cube Map Texture (Not Working)

    Following are the relevant codes:

    main.py :

    import sys, os, re, ast, datetime, tempfile, requests, queue, threading, json
    
    # from pathlib import Path
    from pathlib import Path
    import pandas as pd
    import numpy as np
    # import sounddevice as sd
    from PySide6.QtCore import QUrl, QObject, Property, QAbstractListModel, Qt, QModelIndex, Slot, qVersion , QThread, Signal,QEvent
    from PySide6.QtGui import QGuiApplication
    from PySide6.QtQml import QQmlApplicationEngine
    from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput
    from PySide6.QtMultimediaWidgets import QGraphicsVideoItem
    from PySide6.QtQuickControls2 import QQuickStyle
    
    # ============ PROJECT PATHS ============
    project_dir = Path(__file__).parent.resolve()
    layouts_dir = project_dir / "assets" / "layouts"
    styles_dir = project_dir / "assets" / "styles"
    checker_dir = project_dir / "assets" / "hunspell"
    
    # ============ KEYBOARD CONFIGURATION ============
    # CRITICAL: Set BEFORE creating QGuiApplication
    os.environ["QT_IM_MODULE"] = "qtvirtualkeyboard"
    
    # Point to our custom layout directory
    os.environ["QT_VIRTUALKEYBOARD_LAYOUT_PATH"] = str(layouts_dir)
    
    # Point to custom style directory
    os.environ["QT_VIRTUALKEYBOARD_STYLE_PATH"] = str(styles_dir)
    
    os.environ["QT_VIRTUALKEYBOARD_HUNSPELL_DICTIONARY_PATH"] = str(checker_dir)
    
    # Enable word prediction and suggestions
    os.environ["QT_VIRTUALKEYBOARD_HUNSPELL"] = "1"  # Enable Hunspell dictionary
    
    # Number of word suggestions to show
    os.environ["QT_VIRTUALKEYBOARD_HUNSPELL_CHOICES"] = "6"
    
    # CRITICAL: Set the default input locale to match your dictionary
    os.environ["QT_VIRTUALKEYBOARD_DEFAULT_LOCALE"] = "en_US"
    
    # 8. Enable word prediction (very important!)
    os.environ["QT_VIRTUALKEYBOARD_WORD_PREDICTION"] = "1"
    
    # 9. Enable auto-capitalization
    os.environ["QT_VIRTUALKEYBOARD_AUTO_CAPITALIZATION"] = "1"
    
    # 10. Optional: Enable learning (keyboard learns new words)
    os.environ["QT_VIRTUALKEYBOARD_LEARN"] = "1"
    
    # Use our custom style (for bigger fonts)
    # os.environ["QT_VIRTUALKEYBOARD_STYLE"] = "myStyle"
    
    # Use our custom en_GB layout
    os.environ["QT_VIRTUALKEYBOARD_LAYOUTS"] = "en_US"
    
    # Disable default layouts (force use of custom only)
    os.environ["QT_VIRTUALKEYBOARD_DESKTOP_DISABLE"] = "0"
    
    os.environ['QT_IMAGEIO_MAXALLOC'] = "512"
    
    print("=" * 60)
    print(f"  Qt Version: {qVersion()}")
    print("=" * 60)
    
    def on_about_to_quit():
        pass
        
    if __name__ == "__main__":
        app = QGuiApplication(sys.argv)
        # Force a style that allows background customization
        QQuickStyle.setStyle("Fusion")   # or "Material", "Basic"
    
        screens = app.screens()
        print(f"Screen Resolution is {screens}")
        if len(screens) > 1:
            screen_size = screens[1].size()
            device_pixel_ratio = screens[1].devicePixelRatio()
        else:
            screen_size = screens[0].size()
            device_pixel_ratio = screens[0].devicePixelRatio()
            
        print(f"Screen Resolution is {screen_size}, Scale Factor: {device_pixel_ratio}")
    
        engine = QQmlApplicationEngine()
        
        # Load main.qml
        engine.load(QUrl("main.qml"))
        app.aboutToQuit.connect(on_about_to_quit)
        if not engine.rootObjects():
            sys.exit(-1)
    
        sys.exit(app.exec())
    
    

    main.qml :

    import QtQuick
    import QtQuick.Controls
    import QtQuick.Window
    import QtMultimedia
    import QtQuick.Layouts
    import QtQuick3D
    import QtQuick3D.Helpers
    import QtQuick.Shapes
    
    Window {
        id: mainWindow
        visible: true
        visibility: Window.FullScreen
        color: "transparent"
    
        panaroma3D {
            id: subMenuPage1
            mainViewImg: "./panaromicImg4.png"
            anchors.fill: parent
            visible: true
        }
        
        Component.onCompleted: {
            console.log("Screen resolution  is:", width, "x", height)
        }
    }
    
    

    panaroma3D.qml :

    import QtQuick
    import QtQuick.Controls
    import QtQuick.Layouts
    import QtQuick3D
    import QtQuick3D.Helpers
    import QtQuick.Shapes
    
    Item {
        id: control
        anchors.fill: parent
        z: 1
        focus: true
        
        property alias caveEulerRotate: cameraRig.eulerRotation
        property alias caveFieldOfView: camera.fieldOfView
        required property string mainViewImg
    
        View3D {    
            id: caveView3D
            anchors.fill: parent
            camera: camera
    
            environment: SceneEnvironment {
                backgroundMode: SceneEnvironment.Color
                clearColor: "black"
            }
    
            Node {
                id: sceneRoot
    
                // ─── Orbiting CameraRig ───
                Node {
                    id: cameraRig
                    eulerRotation: Qt.vector3d(12, 0, 0)
    
                    PerspectiveCamera {
                        id: camera
                        position: Qt.vector3d(0, 0, 0)          // fixed distance for Viewing
                        // position: Qt.vector3d(0, 0, 100)       // fixed distance for Mapping Hotspot
                        fieldOfView: 80
                    }
                }
    
                // ─── Central Sphere ───
                Model {
                    id: sphere
                    objectName: "mainSphere"
                    source: "#Sphere"
                    scale: Qt.vector3d(-200, 200, 200)
                    pickable: true
                    materials: PrincipledMaterial {
                        baseColorMap: Texture {
                            source: control.mainViewImg
                        }
                        lighting: PrincipledMaterial.NoLighting
                        cullMode: Material.NoCulling
                        // cullMode: Material.FrontFaceCulling  // fixed distance for Mapping Hotspot
                    }
                }
            }
    
            // ─── Mouse Drag to Orbit ───
            MouseArea {
                id: dragArea
                anchors.fill: caveView3D
                property real lastX: 0
                property real lastY: 0
                property bool isDragging: false
    
                onPressed: event => {
                    lastX = event.x
                    lastY = event.y
                    isDragging = false
                }
    
                onPositionChanged: event => {
                    let dx = event.x - lastX
                    let dy = event.y - lastY
    
                    if (Math.abs(dx) > 2 || Math.abs(dy) > 2) {
                        isDragging = true
    
                        // Horizontal orbit (yaw)
                        let newYaw = cameraRig.eulerRotation.y + dx * 0.003
                        let newTemp = camera.position.z + dx * 0.003
                        newYaw = Math.max(125, Math.min(295, newYaw)) // actual working
                        cameraRig.eulerRotation.y = newYaw
    
                        // Vertical orbit (pitch)
                        let newPitch = cameraRig.eulerRotation.x + dy * 0.003
                        newPitch = Math.max(12, Math.min(0, newPitch)) // clamp
                        cameraRig.eulerRotation.x = newPitch
    
                        lastX = event.x
                        lastY = event.y
                    }
                }
    
                onReleased: event => {
                    if (!isDragging) {
                        const result = caveView3D.pick(event.x, event.y)
                        if (result.objectHit) {
                            const name = result.objectHit.objectName
    
                            if (name == "mainSphere")
                            {
                                console.log("👉 Clicked on the sphere surface at:", result.scenePosition) // handle sphere clicks here
                            }
                        }
                    }
                }
            }
        }
    }
    
    
    1 Reply Last reply
    0

    • Login

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Get Qt Extensions
    • Unsolved