Table of Contents

シェーダークラス、ミックスイン、継承

Stride シェーディング言語(SDSL)は、HLSL を拡張し、より C# の構文や概念に近いものになっています。この言語はオブジェクト指向です。

  • シェーダークラスはコードの基礎となるものです。
  • シェーダークラスにはメソッドとメンバーが含まれます。
  • シェーダークラスは継承可能で、メソッドはオーバーライド可能です。
  • メンバーの型をシェーダークラスにすることができます。

SDSL では、独自の方法で多重継承を実現しています。継承はミックスインで行われるので、継承の順番が重要になります。

  • 継承の順番によってメソッドの実際の実装を定義します(最後のオーバーライド)。
  • ミックスインが継承の中で何度も現れた場合は、最初に現れたものだけを考慮します(メンバーやメソッドも考慮します)。
  • メソッドの直前の実装を呼び出すには、base.<メソッド名>(<引数>) を使います。

キーワード

SDSL では、HLSL のキーワードに新たなキーワードを追加しています。

  • stage: メソッドとメンバーのキーワードです。このキーワードは、メソッドやメンバが一度だけ定義され、コンポジション内で同一であることを確認します。
  • stream: メンバーのキーワードです。このメンバーは、シェーダーのすべてのステージでアクセス可能になります。詳細については、シェーダーステージ入出力の自動管理を参照してください。
  • streams: シェーダーのいくつかのステージにまたがって必要とされる変数を格納するグローバル構造体のようなものです。詳細については、シェーダーステージ入出力の自動管理を参照してください。
  • override: メソッドのキーワードです。このキーワードがない場合、コンパイラはエラーを返します。
  • abstract: メソッド宣言の前で使用されます(メソッドの本体はありません)。
  • clone: メソッドのキーワードです。シェーダークラスの継承ツリーにこのキーワードを持つメソッドが複数回現れている場合、継承の各レベルでメソッドのインスタンスを、1つではなく複数作成することを強制します。詳細については、コンポジションを参照してください。
  • Input: ジオメトリシェーダーとテッセレーションシェーダーのためのキーワードです。詳細については、シェーダー ステージを参照してください。
  • Output: ジオメトリシェーダーとテッセレーションシェーダーのためのキーワードです。詳細については、シェーダー ステージを参照してください。
  • Input2: テッセレーションシェーダーのためのキーワードです。詳細については、シェーダー ステージ.
  • Constants: テッセレーションシェーダーのためのキーワードです。詳細については、シェーダー ステージ.

抽象メソッド(abstract)

SDSL では、抽象メソッドが利用できます。抽象メソッドには abstract キーワードを付ける必要があります。抽象メソッドは、実装しなくても、シェーダークラスから継承することができます。この場合、コンパイラはシンプルで無害な警告を出すことでしょう。ただし、コンパイルエラーを防ぐためには、最終的なシェーダーでそれを実装しなければなりません。

アノテーション

HLSL と同様に、SDSL でもアノテーションが利用できます。最も役立つものをいくつか挙げます。

  • [Color]:float4 変数に付けます。このエフェクトパラメータのキーの型は、Vector4 ではなく Color4 になります。また、この変数を色として扱うよう Game Studio に指示することで、Game Studio 上で編集できるようになります。
  • [Link(...)]:値を設定するために使用するエフェクトパラメータのキーを指定します。ただし、独立したデフォルトのキーが作成されます。
  • [Map(...)]:値を設定するために使用するエフェクトパラメータのキーを指定します。新しいパラメーターキーは作成されません。
  • [RenameLink]:エフェクトパラメータのキーの作成を回避します。[Link()] と一緒に使ってください。

サンプルコード:アノテーション

shader BaseShader
{
	[Color] float4 myColor;
 
	[Link("ProjectKeys.MyTextureKey")]
	[RenameLink]
	Texture2D texture;
 
	[Map("Texturing.Texture0")] Texture2D defaultTexture;
};

サンプルコード:継承

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);
	}
};

サンプルコード: 継承順序の重要性

ShaderAShaderB の継承順序を変えるとどうなるかに注目してください。

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
	}
};

静的呼び出し

シェーダーを継承せずに、そのシェーダーの変数を使ったり、メソッドを呼び出したりすることもできます。これを行うには、<shader_name>.<変数またはメソッド名>を使用します。これは静的呼び出しと同じように動作します。

シェーダークラスの変数を使うメソッドを静的に呼び出すと、シェーダーはコンパイルされないということに注意してください。これはシェーダーの一部だけを使用するのに便利な方法ですが、最適化ではありません。シェーダーコンパイラは、すでに不要な変数を自動的に削除しています。

サンプルコード:静的呼び出し

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();
	}
};

関連項目