Qtブログ(日本語)

万能な QML Scene Graph

作成者: 朝木卓見|Mar 24, 2011 4:58:36 AM

この記事は Qt Blog の ”The convenient power of QML Scene Graph" を翻訳したものです。
執筆: Kim Kalland 2011年3月22日

[qt QGraphicsView] 上の QML では素晴らしい UI を作成するために必要十分な速度が得られるように、その機能が制限されています。コンポジションモードや [qt QPainterPath]、[qt QGraphicsEffect]、複雑なブラシのような遅くなりうる機能はサポートされていません。速くてレスポンスの良い UI が作りやすく、遅いものは作りにくくなるように設計しています。

また、OpenGL を活用した新しい シーングラフ ベースの QML バックエンド の開発も進めています。QGraphicsView 上では遅すぎるものでも、シーングラフ上ではハードウェアアクセラレーションの力を借りて高速化できます。例えば、QGraphicsEffect(ぼかし、色変換、陰影付け、半透明処理)で実装されているフィルターはフラグメントシェーダで実装することが出来ます。ページめくり(Page Curl)のエフェクトやジーニーエフェクト(Genie Effect)はバーテックスシェーダで実装できます。C++ でのシェーダエフェクトの実装は退屈な時間でした。その後 Qt/3D に触発されて、シェーダエフェクトをより簡単に実装できる新しい QML の要素 ShaderEffectItem を追加しました。

ShaderEffectItem はカスタムバーテックスシェーダとカスタムフラグメントシェーダを持つ単なる矩形です。その矩形の "width" と ”height" プロパティによって求められる各頂点はバーテックスシェーダに渡されます。(矩形をさらに複数の行と列に分割するためのプロパティもありますが、デフォルトでは四つの頂点を持ちます。) ShaderEffectItem の素晴らしい特徴は、QML の要素に独自に定義したプロパティをシェーダの uniform 変数として利用できるということです。例えば、QML で "color" 型でアニメーションしている "tint" というプロパティを定義したとします。シェーダでは "uniform vec4 tinit" と記述してそのプロパティを取り込みます。real, point, size, color, vector3d, それからシェーダのコードでは ”sampler2D" に割り当てられる新しい型 ShaderEffectSource が型として利用できます。ShaderEffectSouce では QML の要素をテクスチャに描画して、それを ShaderEffectItem に渡すことが出来ます。ShaderEffectSource は折り返しのモードやミップマップのようなプロパティと、テクスチャに書き込む QML 要素のリファレンスを持ちます。ShaderEffectItem では、ある ShaderEffectItem を他の ShaderEffectItem のソースとすることによって、互いを関連づけることが出来ます。ShaderEffectItem は非常に強力な要素なので、注意して使用する必要があります。お粗末なシェーダや多すぎるエフェクトを一度に動作させようとすると、特にデバイスでは簡単にパフォーマンスが低下してしまいます。

下記のコードはゆらめくエフェクト(wobble effect)の実装例です。

import QtQuick 2.0

Image {
width: 180
height: 180
source: "winter.jpg"
Text {
id: theItem
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 120
font.family: "Times"
color: "blue"
text: "Qt"
}
ShaderEffectItem {
anchors.fill: parent
property variant source: ShaderEffectSource {
sourceItem: theItem
smooth: true
hideSource: true
}
property real amplitude: 0.02
property real frequency: 20
property real time: 0
NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 }
fragmentShader: "
uniform highp float amplitude;
uniform highp float frequency;
uniform highp float time;
uniform sampler2D source;
uniform lowp float qt_Opacity;
varying highp vec2 qt_TexCoord0;
void main() {
highp vec2 p = sin(time + frequency * qt_TexCoord0);
gl_FragColor = qt_Opacity * texture2D(source, qt_TexCoord0 + amplitude * vec2(p.y, -p.x));
}"
}
}

QML Scene Graph のソースコードは http://qt.gitorious.org/+qt-developers/qt/staging/ の qml-team/qtquick2 ブランチにあります。