はじめに
QML では ShaderEffect という要素を利用して、表示している要素をソースにシェーダでいじることが出来ます。
そこで WebView で表示した Web ページをソースに色々と遊んでみました。
Fragment Shader
デモ
波打たせてみます。
これで Vim ガールさんがセクシーにうねんうねんします。
解説
驚きのコード量の少なさです。
import QtQuick 2.0 import QtWebKit 3.0 Rectangle { width: 720 height: 480 WebView { id: webview anchors.fill: parent url: 'http://b.hatena.ne.jp' } ShaderEffect { anchors.fill: parent property real time: 0 NumberAnimation on time { loops: Animation.Infinite from: 0 to: Math.PI * 2 duration: 1000 } property var source: ShaderEffectSource { sourceItem: webview hideSource: true } fragmentShader: " uniform highp float time; uniform sampler2D source; varying highp vec2 qt_TexCoord0; void main() { float a = 0.01 * (0.5 * (sin(time) + 1.0)); highp vec2 uv = qt_TexCoord0.xy; highp vec2 delta = a * sin((vec2(uv.y, uv.x) * 30.0 + time)); gl_FragColor = texture2D(source, uv + delta); }" } }
QML のプロパティの値を uniform 変数として何もせずとも渡せてしまうお手軽感パないです。
Vertex Shader
デモ
頂点シェーダも使えます。こっちはもう少し実用感も見据えてスクロール速度に応じてミョーンと伸びるエフェクトを作ってみました。
たまにガタつくのは何故か不明ですが、結構気持ち良いです。
解説
import QtQuick 2.0 import QtWebKit 3.0 Rectangle { width: 720 height: 480 WebView { id: webview anchors.fill: parent url: 'http://b.hatena.ne.jp' } MouseArea { id: scroll anchors.fill: parent property double value: 0 property double stretch: 0.0005 property double elastic: 0.9 propagateComposedEvents: true onWheel: { value -= Math.abs(wheel.pixelDelta.y * stretch); wheel.accepted = false; } Timer { interval: 10; running: true; repeat: true onTriggered: { scroll.value *= scroll.elastic; } } } ShaderEffect { anchors.fill: parent property double speed: scroll.value property real time: 0 NumberAnimation on time { loops: Animation.Infinite from: 0 to: Math.PI * 2 duration: 1000 } property var source: ShaderEffectSource { sourceItem: webview hideSource: true } vertexShader: " uniform highp float time; uniform highp float speed; uniform highp mat4 qt_Matrix; attribute highp vec4 qt_Vertex; attribute highp vec2 qt_MultiTexCoord0; varying highp vec2 qt_TexCoord0; void main() { highp vec4 pos = qt_Vertex; highp float d = 0.5 * smoothstep(0.0, 1.0, qt_MultiTexCoord0.y); gl_Position = qt_Matrix * pos; highp vec2 coord = qt_MultiTexCoord0; if (coord.y == 1.0) coord.y += speed; qt_TexCoord0 = coord; }" } }
MouseArea で propagateComposedEvents をすればイベントをスティールされてしまうのを防げるのを初めて知りました:
おわりに
もちろん頂点シェーダとフラグメントシェーダの組み合わせも可能です。色々遊んでみて下さい。
QML が楽過ぎて生きるのが辛い。