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 oflayer
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?
-
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)
I tried it with an image which the size was 1024x1024 (power of 2) and same result
Thanks for the additional examples
-
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)
I tried it with an image which the size was 1024x1024 (power of 2) and same result
Thanks for the additional examples
-
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 -
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
@rmds Try this :
import QtQuick 2.13 import QtQuick.Window 2.13 Window { id: root visible: true width: 800 height: 600 title: qsTr("Scrolling background !") Row { // don't use anchors.fill ! Image { source: "http://www.placecage.com/c/200/300" fillMode: Image.PreserveAspectFit } layer.enabled: true layer.wrapMode: ShaderEffectSource.Repeat layer.effect: ShaderEffect { NumberAnimation on displacement { duration: 2500; from: 1.0; to: 0.0; loops: Animation.Infinite } property variant displacement: 0.0 fragmentShader: " uniform highp float displacement; uniform lowp sampler2D source; uniform lowp float qt_Opacity; varying highp vec2 qt_TexCoord0; void main() { gl_FragColor = qt_Opacity*texture2D(source,qt_TexCoord0-vec2(displacement,0.0)); }" } // End ShaderEffect } // End Row } // End Window
-
@rmds Try this :
import QtQuick 2.13 import QtQuick.Window 2.13 Window { id: root visible: true width: 800 height: 600 title: qsTr("Scrolling background !") Row { // don't use anchors.fill ! Image { source: "http://www.placecage.com/c/200/300" fillMode: Image.PreserveAspectFit } layer.enabled: true layer.wrapMode: ShaderEffectSource.Repeat layer.effect: ShaderEffect { NumberAnimation on displacement { duration: 2500; from: 1.0; to: 0.0; loops: Animation.Infinite } property variant displacement: 0.0 fragmentShader: " uniform highp float displacement; uniform lowp sampler2D source; uniform lowp float qt_Opacity; varying highp vec2 qt_TexCoord0; void main() { gl_FragColor = qt_Opacity*texture2D(source,qt_TexCoord0-vec2(displacement,0.0)); }" } // End ShaderEffect } // End Row } // End Window