Scrolling Background in QtQuick



  • Hey Guys,

    Im trying to get an image to scroll horizontally tiled indefinitely in the back ground. Here is what I currently have

    import QtQuick 2.0
    
    Item {
        anchors.fill: parent
    
        // *** Background image ***
        Image {
            id: backgroundImage
            width: parent.width
            height: parent.height
            source: "images/diver_background_sea.png"
            //anchors.fill: parent
            //fillMode: Image.TileHorizontally
            //cache: false
            mirror: true
            //horizontalAlignment: Image.AlignLeft
            /* Parallax Scrolling
            x: ­gameView.width/8.0 – boardFlickable.contentX/4.0
            y: ­gameView.height/8.0 – boardFlickable.contentY/4.0
            */
            NumberAnimation on x {
                duration: 6000000
                to: -80000
            }
        }
    }
    

    When the image reaches the edge the background shows up, I would like it so that instead of the background showing up the image would just be tiled horizontally forever. I tried setting tiled Horizontally but it only tiled once.



  • I don't think animating x is doing what you think it is... it's actually moving the image item around. Tiling doesn't tile the image pixels outside the Image item into the surrounding area, so you get to see the background.

    One possible solution might be to use a layer.effect to modify how pixels are mapped from image to screen:

    import QtQuick 2.7
    
    Rectangle {
      width: 400
      height: 300
      color: 'black'
    
      Image {
        anchors.fill: parent
        source: 'http://www.placecage.com/c/200/300'
        fillMode: Image.Tile
        layer.enabled: true
        layer.wrapMode: ShaderEffectSource.Repeat
        layer.effect: ShaderEffect {
          NumberAnimation on displacement {
            duration: 2500
            from: 0.0
            to: 1.0
            loops: Animation.Infinite
          }
          property variant displacement: 0.0
          fragmentShader: "
            uniform highp float displacement;
            uniform lowp sampler2D source;
            uniform lowp float qt_Opacity; // inherited opacity of this item
            varying highp vec2 qt_TexCoord0;
            void main() {
              gl_FragColor = qt_Opacity*texture2D(source,qt_TexCoord0-vec2(displacement,0.0));
            }"
        }
      }
    }
    

    (runs in Qt 5.9.1's qmlscene). Not sure if that's overkill and there's a simpler way. (I did try something using sourceRect instead of layer but it seems to be applied on the wrong side of the tiling to be useful).



  • Thanks for the quick reply. That was what my goal was when I used animating x, was to move the image around but wrapped around.

    I just tried your code with my image and it worked great!
    Just a question using my image or the sample image it doesn't line up correctly a certain point. Is there anyway to fix this?

    Also I would like to mirror the image then tile is this possible with the shaders?



  • @rmds Not sure what you mean about it not lining up correctly at a certain point... there is some mention in the docs about layer.wrapMode: ShaderEffectSource.Repeat might need a power-of-two sized image on some HW.... I'd be surprised to run into that restriction still on modern HW though.

    To make a background using alternating regular & mirrored images, that's easily done with Image's mirror property:

    import QtQuick 2.7
    
    Rectangle {
      width: 400
      height: 300
      color: 'black'
    
      Row {
        anchors.fill: parent
    
        Image {
          source: 'http://www.placecage.com/c/200/300'
          fillMode: Image.Tile
        }
        Image {
          source: 'http://www.placecage.com/c/200/300'
          fillMode: Image.Tile
          mirror: true
        }
        
        layer.enabled: true
        layer.wrapMode: ShaderEffectSource.Repeat
        layer.effect: ShaderEffect {
          NumberAnimation on displacement {
            duration: 2500
            from: 0.0
            to: 1.0
            loops: Animation.Infinite
          }
          property variant displacement: 0.0
          fragmentShader: "
            uniform highp float displacement;
            uniform lowp sampler2D source;
            uniform lowp float qt_Opacity; // inherited opacity of this item
            varying highp vec2 qt_TexCoord0;
            void main() {
              gl_FragColor = qt_Opacity*texture2D(source,qt_TexCoord0-vec2(displacement,0.0));
            }"
        }
      }
    }
    

    The same effect could probably also be achieved in the original version by using a more complex expression in the shader, but repeating the pair of images seems a simple enough enough.



  • Hey Tim

    I tried your mirroring example and it works how ever I still get the problem mentioned earlier.

    If you look at the image below, in red you the image over laps with itself at a certain point, how do I prevent this? Thats what I meant by the not lining up correctly at a certain point (ignore the screen tearing)
    alt text

    I tried it with an image which the size was 1024x1024 (power of 2) and same result

    Thanks for the additional examples



  • @rmds Strange... it didn't do that for me. What graphics hardware are you using? I forget which machine I was running my code on... but it was probably an NVidia card or relatively recent Intel embedded graphics.



  • I tried it on a machine with a Nvidia GeForce 310, and on a virtual machine running on another machine running an i7-6600u (laptop). Same result on both



  • Hi,
    You can also have a look at V-Play Engine for qt-based mobile app and game development.

    It offers a ParallaxScrollingBackground component which can create endless loops by mirroring an image, or by alternating two images.

    import VPlay 2.0
    
    GameWindow {
    
      ParallaxScrollingBackground {
        movementVelocity: Qt.point(10,0)
        sourceImage: Qt.resolvedUrl("../assets/vplay-logo.png")
      }
    
    }
    

    Best,
    GTDev


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.