マルチプルレンダーターゲット
2020年4月8日 (水) 07:00時点におけるAdministrator (トーク | 投稿記録)による版
対応状況
概要
遅延レンダリングでは「色」や「法線」、「深度」などを複数のレンダーターゲットに出力する。ならば出力先のレンダーターゲットを複数指定できるようにすれば1回のシェーダー呼び出しで完結できるじゃないか、という代物である。
遅延レンダリングが大流行しだした時期にXbox 360とPS3が発売した。 これらには遅延レンダリングを高速化する目的でMRTが搭載された。
メリット
デメリット
当然ながらMRT向けにシェーダーを書き直さなければならない。
COBOLやJavaやPHPを愛するIT土方的な考えであれば「既存のシェーダーを2回呼び出せばいいじゃん」となるところである。この世界では「車輪の再発明だ」と批判されることであろう。
一方、ゲーム業界はそこへ突撃して「このゲームのここがすごい!」と宣伝材料にしようとする。なおゲームの面白さには一切関係ない。
彼らは相見えない。「プログラマー」と一括にはできないほど根本的な思想に違いがある。
記述例
ピクセルシェーダーの戻り値を構造体にして一度に複数の色を返す感じになる。 HLSLの記述例。
// Rec. 709グレースケール変換定数
const float3 luma = float3(0.2126, 0.7152, 0.0722);
// ピクセルシェーダー出力
struct PS_OUTPUT
{
float4 rgba:COLOR0; //RendarTargetの0番目に出力
float4 gray:COLOR1; //RendarTargetの1番目に出力
};
// ピクセルシェーダー本体
// 一般的なピクセルシェーダーの戻り値はRGBAを表す「float4」だが、
// マルチプルレンダーターゲットでは構造体で複数の色を返す。
PS_OUTPUT psMain( float2 texCoord:TEXCOORD )
{
PS_OUTPUT psout;
// そのまま出力
float4 color = tex2D(ScreenTexSampler,texCoord);
psout.rgba = color;
// グレースケールに変換して出力
float gray = dot(color.rgb, luma);
psout.gray = float4(gray,gray,gray,1);
return psout;
}
OpenGLやOpenGL ESでも似たような感じである。通常はシステム予約の変数「gl_FragColor」に色を設定するが、MRTの場合は「gl_FragData」配列に各種の値を設定する。
vec4 ps_c0 = vec4(0.0, 0.5, 1.0, 0.0);
gl_FragData[0] = ps_c0.xxxx;
gl_FragData[1] = ps_c0.yyyx;
gl_FragData[2] = ps_c0.zzzz;
OpenGL ES 3.0(GLSL ES 3.0)では「gl_FragColor」も「gl_FragData」も廃止された。 代わりにlayoutを使う。これによりgl_FragDataは問答無用でvec4の配列であり無駄が多かったのが改善された。ただHLSLのstructの方がわかりやすいね。
layout (location = 0) out vec3 position;
layout (location = 1) out vec3 normal;
layout (location = 2) out vec4 color;