Item.layer.wrapMode

2025-06-06

このプロパティは Qt.WrapMode 列挙型によって定義され、以下の値を取ることができます。

  • Qt.MirroredRepeat: Qt.Repeat と似ていますが、テクスチャが繰り返される際に、隣接するテクスチャがミラーリング(反転)されます。これにより、タイルとタイルの境界で不連続な見た目になるのを軽減できる場合があります。

  • Qt.ClampToEdge: テクスチャの端のピクセルが拡張されて、アイテムの境界まで埋められます。テクスチャが繰り返されることはなく、最後のピクセルが端まで引き伸ばされます。これにより、テクスチャの端で不連続な見た目になるのを防ぐことができます。

  • Qt.Repeat (デフォルト値): テクスチャがアイテムの境界を超えて繰り返されます。例えば、小さい画像で大きな背景を埋めたい場合などに使用されます。テクスチャがタイル状に敷き詰められるイメージです。

使用例

import QtQuick 2.0
import QtQuick.Window 2.0

Window {
    width: 400
    height: 300
    visible: true
    title: "WrapMode Example"

    Rectangle {
        width: 200
        height: 200
        color: "lightgray"
        anchors.centerIn: parent

        Image {
            id: myImage
            source: "qrc:/images/myTexture.png" // 適切な画像パスに置き換えてください
            width: parent.width
            height: parent.height

            // レイヤーを有効にする
            layer.enabled: true

            // ここでwrapModeを設定
            // layer.wrapMode: Qt.Repeat // デフォルト
            // layer.wrapMode: Qt.ClampToEdge
            layer.wrapMode: Qt.MirroredRepeat
        }
    }
}


一般的なエラーと問題

    • 問題点
      テクスチャが意図しない場所で繰り返される、または繰り返すべきでない場所で繰り返される。
    • 原因
      • layer.wrapMode: Qt.Repeat が設定されているにもかかわらず、テクスチャのサイズがアイテムのサイズと合っていない。
      • アイテムのサイズがテクスチャのサイズよりも小さい場合、テクスチャが途中で途切れて繰り返される。
      • テクスチャ座標 (UV座標) の計算に誤りがある場合、Qt.Repeat が予期せぬパターンを生成することがあります。特にカスタムシェーダーを使用している場合に発生しやすいです。
    • トラブルシューティング
      • テクスチャが繰り返される必要がない場合は、layer.wrapMode: Qt.ClampToEdge を使用します。
      • テクスチャを繰り返したい場合は、アイテムのサイズとテクスチャのサイズ、またはテクスチャ座標が正しく整合しているか確認します。
      • デバッグ時に、Rectanglecolor プロパティなどを利用して、アイテムの実際のサイズと位置を確認します。
  1. パフォーマンスの問題

    • 問題点
      Item.layer.enabled: true を多用すると、パフォーマンスが低下する可能性があります。
    • 原因
      • layer.enabled: true は、QML アイテムをオフスクリーンテクスチャにレンダリングするため、追加の描画コストが発生します。
      • 多数のレイヤー化されたアイテムがあると、Qt の内部レンダリングパスが最適化されにくくなる場合があります(バッチ処理の妨げになるなど)。
    • トラブルシューティング
      • layer.enabled は必要な場合にのみ使用します。特に、アニメーションや複雑なエフェクトを適用する際にのみ有効にし、それ以外の時は無効にすることを検討します。
      • Qt Quick のプロファイリングツールを使用して、パフォーマンスのボトルネックを特定します。
      • レイヤー化するアイテムの数を減らすか、より大きなアイテムのサブツリー全体を1つのレイヤーとして扱うことを検討します。
  2. シェーダーとの相互作用における問題

    • 問題点
      カスタムシェーダーと Item.layer.wrapMode を組み合わせた際に、予期せぬ描画結果になる。
    • 原因
      • シェーダー内でテクスチャ座標がどのように計算・利用されているか、wrapMode の設定と整合性が取れていない。
      • シェーダーがテクスチャのバウンディングボックス外のピクセルをサンプリングしようとした場合、wrapMode の影響が直接現れる。
    • トラブルシューティング
      • シェーダーコード内のテクスチャ座標(UV座標)の計算ロジックを確認し、wrapMode の意図と一致しているか検証します。
      • シンプルなシェーダーで wrapMode の挙動をテストし、問題がシェーダー側にあるのか、QML の設定側にあるのかを切り分けます。
      • Qt.Repeat を使用する場合、テクスチャ座標が [0, 1] の範囲を超えても正しくラップされるようにシェーダーを記述します。
  • グラフィックドライバー
    使用しているシステムのグラフィックドライバーが最新であるか、または問題のあるバージョンではないか確認します。グラフィックドライバーの問題が原因で、レンダリングアーティファクトが発生することが稀にあります。
  • デバッグツール
    Qt Creator の QML Debugger や Qt Quick Analyzer などのツールを活用し、描画パスやテクスチャの状態を視覚的に確認します。
  • Qt のバージョン
    使用している Qt のバージョンによって、グラフィックスレンダリングの挙動が異なる場合があります。古い Qt バージョンでのバグや、新しいバージョンでの改善がないか、公式ドキュメントやフォーラムを確認します。
  • 最小限のコードで再現
    問題が発生した場合、できるだけ最小限のコードでその問題を再現してみてください。これにより、原因を特定しやすくなります。
  • 画像のサイズとアスペクト比
    使用している画像のサイズやアスペクト比が、表示しようとしている Item のサイズと一致しているか確認します。
  • layer.enabled を確認する
    wrapModelayer.enabledtrue の場合にのみ効果を発揮します。layer.enabledfalse の場合、wrapMode を設定しても何も起こりません。


基本的な構造

Item.layer.wrapMode を使用するには、まず Item.layer.enabledtrue に設定して、アイテムをレイヤーとしてレンダリングするようにQtに指示する必要があります。

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 600
    height: 400
    visible: true
    title: "Item.layer.wrapMode Examples"

    // 画像ファイルをプロジェクトに追加してください (例: images/texture.png)
    // 小さめの画像(例: 64x64ピクセル)を使うと、繰り返しが分かりやすいです。
    // qrc:/images/texture.png
}

上記の Window の中に、以下の例を追加していきます。

例1: Qt.Repeat (デフォルト)

Qt.Repeat は、テクスチャがアイテムの境界を超えて繰り返される最も一般的なモードです。壁紙のようにテクスチャをタイル状に敷き詰めたい場合に適しています。

    // 例1: Qt.Repeat (デフォルト)
    Rectangle {
        width: 250
        height: 150
        color: "lightgray"
        x: 20
        y: 20

        Text {
            text: "Qt.Repeat (Default)"
            font.pixelSize: 16
            color: "black"
            anchors.bottom: parent.top
            anchors.left: parent.left
            anchors.bottomMargin: 5
        }

        Image {
            source: "qrc:/images/texture.png" // 実際の画像パスに置き換えてください
            width: parent.width
            height: parent.height

            layer.enabled: true
            layer.wrapMode: Qt.Repeat // これはデフォルトなので省略可能
            // layer.wrapMode: Qt.RepeatHorizontally // X軸のみ繰り返す
            // layer.wrapMode: Qt.RepeatVertically   // Y軸のみ繰り返す
        }
    }

解説
Imagesource に指定した画像が、Rectangle のサイズに合わせて繰り返して表示されます。もし texture.png64x64 ピクセルで、Rectangle250x150 ピクセルなら、テクスチャが複数回繰り返されているのが分かります。

例2: Qt.ClampToEdge

Qt.ClampToEdge は、テクスチャの端のピクセルを拡張して、アイテムの境界まで埋めます。テクスチャが繰り返されることなく、端のピクセルが引き伸ばされるため、テクスチャアトラスなどで隣接するテクスチャのブリーディングを防ぎたい場合や、単一のテクスチャをきっちりフィットさせたい場合に有用です。

    // 例2: Qt.ClampToEdge
    Rectangle {
        width: 250
        height: 150
        color: "lightgray"
        x: 20
        y: 190 // 位置を調整

        Text {
            text: "Qt.ClampToEdge"
            font.pixelSize: 16
            color: "black"
            anchors.bottom: parent.top
            anchors.left: parent.left
            anchors.bottomMargin: 5
        }

        Image {
            source: "qrc:/images/texture.png" // 実際の画像パスに置き換えてください
            // テクスチャのサイズよりもImageのサイズを大きくすると、引き伸ばしが分かりやすい
            width: parent.width
            height: parent.height

            layer.enabled: true
            layer.wrapMode: Qt.ClampToEdge
        }
    }

解説
Image のサイズが texture.png の元のサイズよりも大きい場合、テクスチャの端の1ピクセルが引き伸ばされて、残りの領域が埋められます。画像が繰り返されることはありません。

例3: Qt.MirroredRepeat

Qt.MirroredRepeatQt.Repeat と似ていますが、テクスチャが繰り返される際に、隣接するテクスチャがミラーリング(反転)されます。これにより、特に模様が連続するテクスチャにおいて、タイル間の境目での不連続感を軽減できることがあります。

    // 例3: Qt.MirroredRepeat
    Rectangle {
        width: 250
        height: 150
        color: "lightgray"
        x: 330 // 位置を調整
        y: 20

        Text {
            text: "Qt.MirroredRepeat"
            font.pixelSize: 16
            color: "black"
            anchors.bottom: parent.top
            anchors.left: parent.left
            anchors.bottomMargin: 5
        }

        Image {
            source: "qrc:/images/texture.png" // 実際の画像パスに置き換えてください
            width: parent.width
            height: parent.height

            layer.enabled: true
            layer.wrapMode: Qt.MirroredRepeat
        }
    }

解説
テクスチャが繰り返されるたびに、偶数回目では通常通り、奇数回目では反転されて描画されます。模様によっては、Qt.Repeat よりも自然な繰り返しに見えることがあります。

例4: ShaderEffect との組み合わせ

Item.layer.wrapMode は、ShaderEffect と組み合わせて、カスタムシェーダーでテクスチャを扱う際にも重要になります。

    // 例4: ShaderEffect との組み合わせ
    Rectangle {
        width: 250
        height: 150
        color: "lightgray"
        x: 330
        y: 190 // 位置を調整

        Text {
            text: "ShaderEffect with ClampToEdge"
            font.pixelSize: 16
            color: "black"
            anchors.bottom: parent.top
            anchors.left: parent.left
            anchors.bottomMargin: 5
        }

        ShaderEffect {
            id: myShaderEffect
            width: parent.width
            height: parent.height

            // シェーダーに渡すソース
            property var sourceTexture: Image { source: "qrc:/images/texture.png" }

            // レイヤーを有効にする
            layer.enabled: true
            layer.wrapMode: Qt.ClampToEdge // シェーダーでテクスチャをクランプする例

            // フラグメントシェーダー (簡略化された例)
            fragmentShader: "
                #version 150 // Qt 5.x では #version 150 を推奨
                uniform sampler2D sourceTexture;
                varying highp vec2 qt_TexCoord0; // QMLが提供するテクスチャ座標

                void main() {
                    // テクスチャ座標を直接使用
                    gl_FragColor = texture2D(sourceTexture, qt_TexCoord0);
                }
            "
        }
    }

解説
ここでは、ShaderEffect を利用して Image からテクスチャを取得し、それを描画しています。layer.wrapMode: Qt.ClampToEdge を設定することで、シェーダーがテクスチャの端を超えてサンプリングしようとした場合に、端のピクセルが引き伸ばされる挙動になります。もし qt_TexCoord0[0, 1] の範囲外にマップするような計算をシェーダー内で行う場合、この wrapMode がその外側のピクセルにどう影響するかを決定します。

  • Qt.WrapMode
    Item.layer.wrapMode には Qt.RepeatQt.ClampToEdgeQt.MirroredRepeat の3つの値が利用可能です。
  • 画像のサイズ
    小さな画像を大きなアイテムにマッピングする場合に wrapMode の効果が最も分かりやすいです。
  • パフォーマンス
    layer.enabled を多用するとパフォーマンスに影響を与える可能性があります。必要な場合にのみ使用し、不必要にレイヤー化しないように注意してください。
  • layer.enabled: true の重要性
    Item.layer.wrapMode は、layer.enabledtrue の場合にのみ効果があります。これは、アイテムがオフスクリーンのテクスチャとしてレンダリングされるために、このプロパティが適用されるからです。


Image の fillMode プロパティ

これは Item.layer.wrapMode の直接的な代替ではありませんが、Image 要素で画像を「繰り返す」または「引き伸ばす」という似たような視覚効果を実現するために使用できます。fillMode は、画像が Image アイテムの境界に収まらない場合にどのように表示されるかを決定します。

  • Image.PreserveAspectCrop: 画像のアスペクト比を維持しつつ、アイテムを埋めるようにスケーリングし、余分な部分を切り抜きます。
  • Image.PreserveAspectFit: 画像のアスペクト比を維持しつつ、アイテム内に収まるようにスケーリングします。
  • Image.Stretch: 画像をアイテムのサイズに合わせて引き伸ばします。Item.layer.wrapMode: Qt.ClampToEdge に似た効果です。
  • Image.Tile: 画像を繰り返し描画します。Item.layer.wrapMode: Qt.Repeat に似た効果です。

利点

  • 特に単純な画像表示には最適な方法です。
  • Item.layer.enabled: true を明示的に設定する必要がないため、シンプルでパフォーマンスに優しい場合があります。

欠点

  • Qt.MirroredRepeat のようなミラーリング機能は直接提供されません。
  • Image アイテムに限定されます。他のQMLアイテム(Rectangleにテクスチャを貼るなど)には直接適用できません。

コード例

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 400
    height: 300
    visible: true
    title: "Image.fillMode Example"

    Rectangle {
        width: 200
        height: 200
        color: "lightgray"
        anchors.centerIn: parent

        Image {
            source: "qrc:/images/texture.png" // 小さな画像を使用
            width: parent.width
            height: parent.height
            fillMode: Image.Tile // 画像をタイル状に繰り返し描画
            // fillMode: Image.Stretch // 画像を引き伸ばして領域を埋める
        }
    }
}

ShaderEffect またはカスタムシェーダーでのUV座標操作

最も柔軟性の高い方法であり、Item.layer.wrapMode の機能を完全に再現したり、それを超えるカスタムなテクスチャマッピングを実現したりできます。 ShaderEffect は、QMLアイテムをテクスチャとしてカスタムシェーダーに渡し、そのシェーダー内でテクスチャ座標(UV座標)を直接操作することで、テクスチャの繰り返し方やマッピング方法を制御します。

利点

  • 任意のQMLアイテムの描画結果をテクスチャとして使用し、それにシェーダーを適用できます(ShaderEffectSource を介して)。
  • テクスチャのスケール、オフセット、回転など、より複雑な変換を同時に適用できます。
  • 完全にカスタマイズ可能。RepeatClampToEdgeMirroredRepeat のすべてをシェーダー内で実装できます。

欠点

  • Item.layer.enabled: true と同様に、追加のレンダリングパスが発生するため、パフォーマンスに影響を与える可能性があります。
  • GLSL(OpenGL Shading Language)の知識が必要です。

実装の考え方

シェーダー内でテクスチャ座標 uv[0, 1] の範囲外になった場合に、以下のように操作します。

  • Mirrored Repeat (ミラー繰り返し): uv = 1.0 - abs(mod(uv, 2.0) - 1.0); (やや複雑な数学ですが、テクスチャ座標を [0, 1][1, 0] の間でミラーリングします)

  • Clamp to Edge (端にクランプ): uv = clamp(uv, 0.0, 1.0); (GLSLの clamp 関数は値を指定された範囲に制限します)

  • Repeat (繰り返し): uv = fract(uv); (GLSLの fract 関数は小数部を返します)

コード例 (ShaderEffect での繰り返し)

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 600
    height: 400
    visible: true
    title: "ShaderEffect for Custom WrapMode"

    Rectangle {
        width: 250
        height: 150
        color: "lightgray"
        anchors.centerIn: parent
        anchors.horizontalCenterOffset: -150

        Text {
            text: "ShaderEffect: Manual Repeat"
            font.pixelSize: 16
            color: "black"
            anchors.bottom: parent.top
            anchors.left: parent.left
            anchors.bottomMargin: 5
        }

        ShaderEffect {
            width: parent.width
            height: parent.height

            // ImageアイテムをShaderEffectのテクスチャソースとして渡す
            property var sourceTexture: Image { source: "qrc:/images/texture.png" }

            // シェーダーにテクスチャの繰り返し回数を伝えるユニフォーム変数
            property real repeatX: parent.width / sourceTexture.width
            property real repeatY: parent.height / sourceTexture.height

            fragmentShader: "
                #version 150
                uniform sampler2D sourceTexture;
                varying highp vec2 qt_TexCoord0; // QMLから提供されるテクスチャ座標 (0-1)

                uniform highp float repeatX;
                uniform highp float repeatY;

                void main() {
                    // アイテムのサイズに基づいてテクスチャ座標をスケーリング
                    // これにより、テクスチャがアイテム全体に広がるように見せかけ、
                    // fract() で繰り返しの効果を出す
                    highp vec2 scaledTexCoord = qt_TexCoord0 * vec2(repeatX, repeatY);

                    // fract() を使ってテクスチャを繰り返す (Repeatモード)
                    gl_FragColor = texture2D(sourceTexture, fract(scaledTexCoord));
                }
            "
        }
    }

    // ShaderEffectSource を使って複雑なアイテムをテクスチャ化し、それを繰り返す例
    Rectangle {
        width: 250
        height: 150
        color: "lightgray"
        anchors.centerIn: parent
        anchors.horizontalCenterOffset: 150

        Text {
            text: "ShaderEffect: Source from Rect"
            font.pixelSize: 16
            color: "black"
            anchors.bottom: parent.top
            anchors.left: parent.left
            anchors.bottomMargin: 5
        }

        ShaderEffect {
            width: parent.width
            height: parent.height

            // Rectangle をテクスチャとしてShaderEffectに渡す
            property var sourceTexture: ShaderEffectSource {
                sourceItem: sourceRectItem
                // レイヤーのテクスチャサイズと sourceRect の調整も可能
                textureSize: Qt.size(sourceRectItem.width, sourceRectItem.height)
            }

            // シェーダーにテクスチャの繰り返し回数を伝えるユニフォーム変数
            property real repeatX: parent.width / sourceTexture.textureSize.width
            property real repeatY: parent.height / sourceTexture.textureSize.height

            fragmentShader: "
                #version 150
                uniform sampler2D sourceTexture;
                varying highp vec2 qt_TexCoord0;

                uniform highp float repeatX;
                uniform highp float repeatY;

                void main() {
                    highp vec2 scaledTexCoord = qt_TexCoord0 * vec2(repeatX, repeatY);
                    gl_FragColor = texture2D(sourceTexture, fract(scaledTexCoord));
                }
            "
        }

        // ShaderEffectSource の元となるアイテム(非表示でOK)
        Rectangle {
            id: sourceRectItem
            width: 50 // 元のテクスチャとなるサイズ
            height: 50
            color: "red"
            visible: false // 描画はShaderEffectが行うため非表示
            // このRectangleに他のQML要素を追加して複雑なパターンを作成できる
            Text {
                text: "Q"
                anchors.centerIn: parent
                font.pixelSize: 30
                color: "white"
            }
        }
    }
}

もし3Dシーンでテクスチャマッピングを行うのであれば、Qt Quick 3Dモジュールが提供する Texture タイプが非常に強力です。これには tilingModeHorizontaltilingModeVertical というプロパティがあり、それぞれ水平方向と垂直方向のラッピングモードを制御できます。

利点

  • scaleU, scaleV, positionU, positionV, rotationUV など、UV変換のためのプロパティが豊富に用意されています。
  • RepeatClampToEdgeMirroredRepeat の全てをサポートしています。
  • 3Dシーンでのテクスチャマッピングに特化しており、より高度な制御が可能です。

欠点

  • モジュールを追加する必要があり、学習コストが若干上がります。
  • 2DのQMLアプリケーションでは直接使用できません。Qt Quick 3Dのシーンが必要です。

コード例 (概念的なもの、Qt Quick 3Dシーンが必要)

import QtQuick 2.15
import QtQuick3D 1.15 // Qt Quick 3Dをインポート
import QtQuick.Window 2.15

Window {
    width: 800
    height: 600
    visible: true
    title: "QtQuick3D Texture Tiling"

    View3D {
        anchors.fill: parent

        // カメラやライト、シーン内のエンティティなどを設定...
        camera: Camera {
            position: Qt.vector3d(0, 0, 500)
            // ...
        }

        // マテリアルにテクスチャを設定
        DefaultMaterial {
            id: myMaterial
            diffuseMap: Texture {
                source: "qrc:/images/texture.png"
                tilingModeHorizontal: Texture.Repeat    // 水平方向の繰り返し
                tilingModeVertical: Texture.MirroredRepeat // 垂直方向のミラー繰り返し
                scaleU: 5 // 水平方向に5回繰り返す
                scaleV: 3 // 垂直方向に3回繰り返す
            }
        }

        // ジオメトリにマテリアルを適用
        Model {
            geometry: RectangleGeometry {} // 2D平面
            material: myMaterial
            scale: Qt.vector3d(200, 200, 1) // モデルのサイズ調整
        }
    }
}

Item.layer.wrapMode は非常に便利ですが、Qt Quick のレンダリングシステムが内部的にどのようにテクスチャを扱っているかを理解すると、これらの代替手段がなぜ存在するのか、そしていつ使うべきかが見えてきます。

  • 3Dシーンでオブジェクトにテクスチャをマッピングし、その繰り返し方を制御したい場合
    QtQuick3DTexture タイプ
  • 任意のQMLアイテムをテクスチャとして利用し、カスタムなテクスチャマッピング(繰り返し、ミラーなど)を厳密に制御したい場合
    ShaderEffect とカスタムシェーダー
  • 最もシンプルに画像を繰り返したり引き伸ばしたりしたい場合
    Image.fillMode