0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Skiaの基本:シェーダーの基本

Last updated at Posted at 2025-11-08

Skiaでは、シェーダーを使用して様々なグラフィックス効果を実現できます。非常に奥の深い強力な機能ですが、ここではその基本について説明します。

シェーダーの種類

Skiaには、以下のようなシェーダーが用意されています。

  1. グラデーションシェーダー: 線形または放射状のグラデーションを描画するためのシェーダーです。
  2. 画像シェーダー: 画像をテクスチャとして使用し、描画するためのシェーダーです。
  3. ノイズシェーダー: Perlinノイズによるパターンを生成するためのシェーダーです。
  4. カスタムシェーダー: シェーダー記述言語(SkSL)を使用して独自のシェーダーを作成できます。

とりあえず描いてみる

とりあえず、一番簡単なグラデーションシェーダーで、線形グラデーションを描画してみましょう。

座標(0,0)から(200,0)までの範囲で、赤、緑、青の3色のグラデーションを描画します。

シェーダーはアンマネージドリソースです。使い終わったら適切に破棄してください。

// 線形グラデーションシェーダーを作成
using var shader = SKShader.CreateLinearGradient(
    new SKPoint( 0, 0 ),    // 開始座標
    new SKPoint( 200, 0 ),  // 終了座標
    new SKColor[] {         // 色経由点の色の配列
        SKColors.Red,
        SKColors.Lime, 
        SKColors.Blue 
    },
    new float[] {           // 色経由点の位置の配列(0.0~1.0)
        0.1f,   // 10%の位置にRed
        0.5f,   // 50%の位置にLime
        0.9f    // 90%の位置にBlue
    },          
    SKShaderTileMode.Clamp  // タイルモード
);
// ペイントを作成
using var paint = new SKPaint {
    Style = SKPaintStyle.Fill,
    Shader = shader
};
// 四角形を描画
canvas.DrawRect( new SKRect( 0, 0, 200, 50 ), paint );

実行すると、以下のように、左上にグラデーションが描画されます。

gradation1.png

シェーダーと座標

先程のグラデーションの四角形を、真ん中にもう一つ描画してみましょう。

// 四角形を描画
canvas.DrawRect( new SKRect( 0, 0, 200, 50 ), paint );
// もう一つ描画
canvas.DrawRect( new SKRect( 50, 75, 250, 125 ), paint );

実行すると、以下のように、真ん中にもう一つ四角形が描画されますが、グラデーションの位置がずれていることがわかります。

gradation2.png

これは、シェーダーがキャンバス全体の座標系に基づいてグラデーションを計算しているためです。
シェーダーの座標系を変更して、グラデーションの位置を調整するには、以下の二つの方法があります。

シェーダーのローカル座標系を使用する

シェーダーのローカル座標系を使用して、グラデーションの位置を調整することができます。これには、座標変換行列を渡してシェーダーを作成する方法と、既存のシェーダーを元に変換行列を適用する方法があります。

// シェーダーを作成する際に変換行列を渡す方法
using var shaderMoved = SKShader.CreateLinearGradient(
    new SKPoint( 0, 0 ),
    new SKPoint( 200, 0 ),
    new SKColor[] {
        SKColors.Red,
        SKColors.Lime, 
        SKColors.Blue 
    },
    new float[] {
        0.1f,
        0.5f,
        0.9f
    },          
    SKShaderTileMode.Clamp,
    SKMatrix.CreateTranslation( 50, 75 ) // ローカル座標系のオフセットを設定
);
// 既存のシェーダーを元に変換行列を適用する方法
using var shaderMoved = shaderOrigin.WithLocalMatrix( SKMatrix.CreateTranslation( 50, 75 ) );

キャンバスの座標系を変更する

もう一つの方法は、キャンバスの座標系を変更することです。これには、キャンバスのTranslateメソッドを使用して、描画前にキャンバスの座標系を移動しておきます。

// 四角形を描画
canvas.DrawRect( new SKRect( 0, 0, 200, 50 ), paint );
// キャンバスの座標系を移動
canvas.Translate( 50, 75 );
// もう一つ描画
canvas.DrawRect( new SKRect( 0, 0, 200, 50 ), paint );

いずれの方法も、実行すると、以下のように、真ん中にもう一つ四角形が描画され、グラデーションの位置も一致します。

gradation3.png

カスタムシェーダー

深淵の世界へようこそ。
Skiaでは、SkSL(Skia Shading Language)を使用してカスタムシェーダーを作成できます。SkSLは、GLSLに似たシェーダー記述言語で、Skiaのレンダリングパイプラインで使用されます。

あまりにも奥が深いので、ここでは簡単な例だけ紹介します。

// SKSLコード
string sksl = @"
    // メイン関数
    half4 main(float2 coord) {
        float red = coord.x / 300.0;            // 横方向に赤が強くなる
        float green = 0.5;                      // 緑は一定
        float blue = coord.y / 200.0;           // 縦方向に青が強くなる
        return half4( red, green, blue, 1.0 );  // 結果をRGBA形式にまとめて返す
    }
";

// シェーダーをコンパイル
var effect = SKRuntimeEffect.CreateShader( sksl, out var errorText );
// コンパイルに失敗した場合、errorTextにエラーメッセージが入る
if ( effect == null ) {
    Debug.WriteLine( errorText );
    return;
}
// シェーダーを生成
using var shader = effect.ToShader();
// ペイントを作成
using var paint = new SKPaint {
    Style = SKPaintStyle.Fill,
    Shader = shader
};
// 四角形を描画
canvas.DrawRect( new SKRect( 0, 0, 300, 200 ), paint );

実行すると、以下のように、二次元のグラデーションが描画されます。

shader1.png

画像を使用して、座標を変化させるなど、様々な応用が可能です。

// SKSLコード
string sksl = @"
    // 元画像のシェーダーを受け取るユニフォーム変数
    uniform shader src;

    // メイン関数
    half4 main(float2 coord) {
        // 横方向に波打つ関数
        float s = 0.5 * ( 1 + sin( coord.x * 0.5 ) );
        // Y座標を変位させる
        coord.y += s * 5.0;
        // 元画像の色をsrcシェーダーから取得
        half4 c = src.eval( coord );
        // 色を少し変える(緑を強調)
        c += half4( 0, 0.2, 0, 0 );
        // 結果を返す
        return c;
    }
";

// シェーダーをコンパイル
var effect = SKRuntimeEffect.CreateShader( sksl, out var errorText );
// コンパイルに失敗した場合、errorTextにエラーメッセージが入る
if ( effect == null ) {
    Debug.WriteLine( errorText );
    return;
}
// ユニフォーム変数(今回は特に使わない)
using var uniforms = new SKRuntimeEffectUniforms( effect );
// 子シェーダー設定
using var children = new SKRuntimeEffectChildren( effect );
using var srcShader = bmpSrc.ToShader();
children[ "src" ] = srcShader; // 元画像のシェーダー"src"
// シェーダー生成
using var shader = effect.ToShader( uniforms, children );
// ペイントを作成
using var paint = new SKPaint {
    Style = SKPaintStyle.Fill,
    Shader = shader
};
// 円を描画
canvas.DrawCircle( 150, 100, 80, paint );

実行すると、以下のように、画像が波打つように変形されて描画されます。

shader2.jpg

まとめ

Skiaのシェーダーは非常に強力で、多様なグラフィックス効果を実現できます。基本的なグラデーションシェーダーから始めて、カスタムシェーダーまで、段階的に学んでいくことをお勧めします。シェーダーの座標系や変換についても理解を深めることで、より高度な描画が可能になります。

参考資料


総合目次

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?