以下の内容はhttps://tips.hecomi.com/entry/20130621/1371815729より取得しました。


QML で表示した WebView をシェーダでいじって遊んでみた

はじめに

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 が楽過ぎて生きるのが辛い。




以上の内容はhttps://tips.hecomi.com/entry/20130621/1371815729より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14