# シェーダークラス、ミックスイン、継承 Stride シェーディング言語(SDSL)は、HLSL を拡張し、より C# の構文や概念に近いものになっています。この言語はオブジェクト指向です。 - シェーダークラスはコードの基礎となるものです。 - シェーダークラスにはメソッドとメンバーが含まれます。 - シェーダークラスは継承可能で、メソッドはオーバーライド可能です。 - メンバーの型をシェーダークラスにすることができます。 SDSL では、独自の方法で多重継承を実現しています。継承は[ミックスイン](https://ja.wikipedia.org/wiki/Mixin)で行われるので、継承の順番が重要になります。 - 継承の順番によってメソッドの実際の実装を定義します(最後のオーバーライド)。 - ミックスインが継承の中で何度も現れた場合は、最初に現れたものだけを考慮します(メンバーやメソッドも考慮します)。 - メソッドの直前の実装を呼び出すには、`base.<メソッド名>(<引数>)` を使います。 ## キーワード SDSL では、HLSL のキーワードに新たなキーワードを追加しています。 - `stage`: メソッドとメンバーのキーワードです。このキーワードは、メソッドやメンバが一度だけ定義され、コンポジション内で同一であることを確認します。 - `stream`: メンバーのキーワードです。このメンバーは、シェーダーのすべてのステージでアクセス可能になります。詳細については、[シェーダーステージ入出力の自動管理](automatic-shader-stage-input-output.md)を参照してください。 - `streams`: シェーダーのいくつかのステージにまたがって必要とされる変数を格納するグローバル構造体のようなものです。詳細については、[シェーダーステージ入出力の自動管理](automatic-shader-stage-input-output.md)を参照してください。 - `override`: メソッドのキーワードです。このキーワードがない場合、コンパイラはエラーを返します。 - `abstract`: メソッド宣言の前で使用されます(メソッドの本体はありません)。 - `clone`: メソッドのキーワードです。シェーダークラスの継承ツリーにこのキーワードを持つメソッドが複数回現れている場合、継承の各レベルでメソッドのインスタンスを、1つではなく複数作成することを強制します。詳細については、[コンポジション](composition.md)を参照してください。 - `Input`: ジオメトリシェーダーとテッセレーションシェーダーのためのキーワードです。詳細については、[シェーダー ステージ](shader-stages.md)を参照してください。 - `Output`: ジオメトリシェーダーとテッセレーションシェーダーのためのキーワードです。詳細については、[シェーダー ステージ](shader-stages.md)を参照してください。 - `Input2`: テッセレーションシェーダーのためのキーワードです。詳細については、[シェーダー ステージ](shader-stages.md). - `Constants`: テッセレーションシェーダーのためのキーワードです。詳細については、[シェーダー ステージ](shader-stages.md). ## 抽象メソッド(abstract) SDSL では、抽象メソッドが利用できます。抽象メソッドには `abstract` キーワードを付ける必要があります。抽象メソッドは、実装しなくても、シェーダークラスから継承することができます。この場合、コンパイラはシンプルで無害な警告を出すことでしょう。ただし、コンパイルエラーを防ぐためには、最終的なシェーダーでそれを実装しなければなりません。 ## アノテーション HLSL と同様に、SDSL でもアノテーションが利用できます。最も役立つものをいくつか挙げます。 - `[Color]`:float4 変数に付けます。このエフェクトパラメータのキーの型は、`Vector4` ではなく `Color4` になります。また、この変数を色として扱うよう Game Studio に指示することで、Game Studio 上で編集できるようになります。 - `[Link(...)]`:値を設定するために使用するエフェクトパラメータのキーを指定します。ただし、独立したデフォルトのキーが作成されます。 - `[Map(...)]`:値を設定するために使用するエフェクトパラメータのキーを指定します。新しいパラメーターキーは作成されません。 - `[RenameLink]`:エフェクトパラメータのキーの作成を回避します。`[Link()]` と一緒に使ってください。 ### サンプルコード:アノテーション ```cs shader BaseShader { [Color] float4 myColor; [Link("ProjectKeys.MyTextureKey")] [RenameLink] Texture2D texture; [Map("Texturing.Texture0")] Texture2D defaultTexture; }; ``` ## サンプルコード:継承 ```cs shader BaseInterface { abstract float Compute(); }; shader BaseShader : BaseInterface { float Compute() { return 1.0f; } }; shader ShaderA : BaseShader { override void Compute() { return 2.0f; } }; shader ShaderB : BaseShader { override void Compute() { float prevValue = base.Compute(); return (5.0f + prevValue); } }; ``` ### サンプルコード: 継承順序の重要性 `ShaderA` と `ShaderB` の継承順序を変えるとどうなるかに注目してください。 ```cs shader MixAB : ShaderA, ShaderB { }; shader MixBA : ShaderB, ShaderA { }; // 結果コード(イメージ表現) // Resulting code (representation) shader MixAB : BaseInterface, BaseShader, ShaderA, ShaderB { float Compute() { // BaseShader から取得 // code from BaseShader float v0 = 1.0f; // ShaderA から取得 // code from ShaderA float v1 = 2.0f; // ShaderB から取得 // code from ShaderB float prevValue = v1; float v2 = 5.0f + prevValue; return v2; // = 7.0f } }; shader MixBA : BaseInterface, BaseShader, ShaderA, ShaderB { float Compute() { // BaseShader から取得 // code from BaseShader float v0 = 1.0f; // ShaderB から取得 // code from ShaderB float prevValue = v0; float v1 = 5.0f + prevValue; // ShaderA から取得 // code from ShaderA float v2 = 2.0f; return v2; // = 2.0f } }; ``` ## 静的呼び出し シェーダーを継承せずに、そのシェーダーの変数を使ったり、メソッドを呼び出したりすることもできます。これを行うには、`.<変数またはメソッド名>`を使用します。これは静的呼び出しと同じように動作します。 シェーダークラスの変数を使うメソッドを静的に呼び出すと、シェーダーはコンパイルされないということに注意してください。これはシェーダーの一部だけを使用するのに便利な方法ですが、最適化ではありません。シェーダーコンパイラは、すでに不要な変数を自動的に削除しています。 ### サンプルコード:静的呼び出し ```cs shader StaticClass { float StaticValue; float StaticMethod(float a) { return 2.0f * a; } // このメソッドは a を使う // this method uses a float NonStaticMethod() { return 2.0f * StaticValue; } }; // このシェーダークラスは問題ありません。 // this shader class is fine shader CorrectStaticCallClass { float Compute() { return StaticClass.StaticValue * StaticMethod(5.0f); } }; // 呼び出しが静的でないため、このシェーダークラスはコンパイルされません。 // this shader class won't compile since the call is not static shader IncorrectStaticCallClass { float Compute() { return StaticClass.NonStaticMethod(); } }; // 修正方法のひとつ // one way to fix this shader IncorrectStaticCallClassFixed : StaticClass { float Compute() { return NonStaticMethod(); } }; ``` ## 関連項目 * [エフェクト言語](../effect-language.md) * [シェーディング言語](index.md) - [コンポジション](composition.md) - [テンプレート](templates.md) - [シェーダー ステージ入出力の自動管理](automatic-shader-stage-input-output.md) - [シェーダー ステージ](shader-stages.md)