ポストエフェクトのインタフェース

スクリーンスペース アンビエント オクルージョン(SSAO)コントロール

MPassContext 内の情報は、SSAO (スクリーンスペース アンビエント オクルージョン)をサポートする必要があるパスをレンダリングするためにプラグインが呼び出されているかを示すための十分な情報を提供します。

SSAO の内部アルゴリズムには、中間結果を生成するための特定の法線の深度のパスが必要です。既定では、レンダラは、このパスに使用される特定のシェーダを設定します。プラグイン シェーダによってジオメトリがディスプレイスされる、または法線が変更される場合は、この既定値シェーダをオーバーライドすることができます。

この法線の深度パスは、シャドウ マップのパスを検出するのと同様の方法で MPassContext 情報を照会することによって検出できます(セクション 4.2.1 「 シャドーイング コントロール」を参照)。**このパスでは、パス識別子は MPassContext::kNormalDepthPassSemantic となります。

テッセレーション シェーダが必要な場合、オーバーライドを MShaderInstance ではなく MPxShaderOverride に追加する必要があります。

サポートを追加するには、カスタム シェーダは以下の条件を考慮する必要があります。

以下に、HLSL で記述された、このパスで使用されるシェーダのサンプルを示します。

// Check if the back-facing normal needs to be flipped.
extern bool isSingleSided = false;
extern float mayaNormalMultiplier = 1.0f;

// Shader semantic supported by Viewport 2.0 to indicate whether
// the projection matrix flips the Z component of a point when transformed
// -1.0 if so, otherwise 1.0.
float gProjZSense : ProjectionZSense;

// Vertex shader input structure.
struct VS_INPUT_NormalDepth
{
    float3 Pos : POSITION;
    float3 Normal: NORMAL;
};

// Vertex shader output structure.
struct VS_TO_PS_NormalDepth
{
    float4 HPos : SV_Position;
    float4 NormalDepth : TEXCOORD0;
};

// Vertex shader.
VS_TO_PS_NormalDepth VS_NormalDepth(VS_INPUT_NormalDepth In)
{
    VS_TO_PS_NormalDepth Out;

    // Transform the vertex from object space to clip space.
    Out.HPos = mul(float4(In.Pos, 1.0f), gWVPXf);

    // Record the normal and depth components for the pixel shader.
    // Note:  This depends on whether the view direction is along the +Z or -Z axis.     
    // The projection matrix "Z sense" determines this.
    Out.NormalDepth.xyz = mul(In.Normal, gWVITXf);
    Out.NormalDepth.z = gProjZSense * Out.NormalDepth.z;     
    Out.NormalDepth.w = gProjZSense * mul(float4(In.Pos, 1.0f), gWVXf).z;

    return Out;
}

// Pixel shader output structure.
struct PS_OUT
{
    float4 Normal : SV_Target0;
    float4 Depth : SV_Target1;
};

// Pixel shader.
PS_OUT PS_NormalDepth(VS_TO_PS_NormalDepth In, bool isFrontFace : SV_IsFrontFace)
{
    PS_OUT Out;

    float3 normal = normalize(In.NormalDepth.xyz);     

    if ( !isSingleSided )     
    {         
        float normalMul = isFrontFace ? mayaNormalMultiplier : -mayaNormalMultiplier;
        normal *= normalMul;     
    }     

    // Set the normal for an unsigned normalized integer target, and depth for a floating-point target.     
    Out.Normal = float4((normal + 1.0f) * 0.5f, 0.0f);
    Out.Depth  = In.NormalDepth.wwww;

    return Out;
}

注: 上記の説明は、Maya 2016 での内部パスの動作です。

モーション ブラー コントロール

MPassContext 内の情報は、モーション ブラーをサポートする必要があるパスをレンダリングするためにプラグインが呼び出されているかを示すための十分な情報を提供します。

モーション ブラーの内部アルゴリズムには、中間結果を生成する特定のモーション ベクトル パスが必要です。既定では、レンダラは、このパスに使用される特定のシェーダを設定します。プラグイン シェーダによってジオメトリがディスプレイスされる場合は、この既定値シェーダをオーバーライドできます。

このモーション ベクトル パスは、MPassContext::kMotionVectorPassSemantic 情報を照会し、文字列 MPassContext または motionVectorPass に一致するパス セマンティックをチェックすることで検出できます。

テッセレーション シェーダが必要な場合、オーバーライドを MShaderInstance ではなく MPxShaderOverride に追加する必要があります。

サポートを追加するには、カスタム シェーダで以下の条件を考慮する必要があります。

以下に、HLSL で記述された、このパスで使用されるシェーダのサンプルを示します。

// Shader semantics supported by Viewport 2.0.
extern float4x4 World : world;
extern float4x4 previousWorld : previousWorld;
extern float4x4 WorldViewProj : worldviewprojection;
extern float4x4 viewProjection : viewProjection;
extern float4x4 previousViewProjection : previousViewProjection;
extern float2 viewportSize : viewportPixelSize;

// The uniform variable will be set by Viewport 2.0 with the value of the
// hardwareRenderingGlobals.motionBlurShutterOpenFraction attribute,
// which denotes the percentage of frame time for which the shutter
// is open, with 0 denoting that the shutter is not open at all, and 1
// denoting that the shutter is open for 100% of the frame time.
extern float shutterOpenFraction = 0.200000f;

// Vertex Shader
VS_TO_PS_MotionVector VS_MotionVector(VS_INPUT_MotionVector In )
{
    VS_TO_PS_MotionVector Out;
    Out.Pw = mul( float4(In.pm,1), World).xyz;
    Out.OtherFramePw = mul( float4(In.pm,1), previousWorld).xyz;
    Out.Pc = mul( float4(In.pm,1), WorldViewProj );
    return Out;
}

// Pixel Shader
float4 PS_MotionVector(VS_TO_PS_MotionVector In ) : SV_Target
{
    float k = shutterOpenFraction * 100.0f;
    float4 Pc = mul( float4(In.Pw, 1.0f), viewProjection );
    float4 prevPc = mul( float4(In.OtherFramePw, 1.0f), previousViewProjection );
    float2 curUV  = Pc.xy / Pc.w;
    float2 prevUV = prevPc.xy / prevPc.w;
    float2 vec = (curUV - prevUV) * shutterOpenFraction * 0.5f;
    vec *= viewportSize;
    float vecLength = length(vec);
    vec *= min(k / vecLength, 1.0f);
    vec /= viewportSize;
    return float4( vec.x, -vec.y, 1.0f - (Pc.z / Pc.w), vecLength );
}

注: Maya 2016 に適用される上記のアルゴリズムは、モーション ベクトルの計算方法の唯一のサンプルです。カスタム シェーダは、任意の方法で適切にモーション ブラーを実装できます。

特定のリリースへのこの実装の XML ラッパーは、MEL コマンドを使用して検索できます。

ogs -xml mayaMotionVector;

API の MFragmentManager:: getFragmentXML() メソッドを使用して、このシェーディング フラグメントを照会できます。 サンプル プラグイン fragmentDumper は、このメソッドを使用してフラグメントをダンプする方法を示します。

dumpFragment -fn mayaMotionVector;

被写界深度のコントロール

MPassContext 内の情報は、被写界深度(DOF)をサポートする必要があるパスをレンダリングするためにプラグインが呼び出されているかを示すための十分な情報を提供します。

DOF の内部アルゴリズムには、中間結果を生成するための特定のパスが必要です。既定では、レンダラはこのパスに対して、特定のシェーダを設定します。

このパスは、MPassContext 情報を照会し、文字列 dofPass または MPassContext::kDOFPassSemantic に一致するパス セマンティックをチェックすることで検出できます。

プラグイン シェーダによってジオメトリがディスプレイスされる場合は、この既定値シェーダをオーバーライドできます。

このシェーダは、錯乱円(CoC)値とピクセルあたりの深度値を計算する必要があります。これらの値は、カラー ターゲット 0 としてバインドされている、浮動小数点の出力ターゲット(R32G32)の R チャネルと G チャネルに書き込まれます。深度テストはローカルにバインドされた深度ターゲットを使用して実行されます。

計算は次のようになります。

0.5 * alpha * abs( Z - Zf ) / Z, where alpha = F*F/(A*(Zf-F))

この場合:

以下に、HLSL で記述された、このパスで使用されるシェーダのサンプルを示します。

float4 mayaCoCDepth( float alpha, float focusDist, float3 Pw, float4x4 view )
{
    float z = abs( mul( float4(Pw, 1), view ).z );
    float CoC = 0.5f * alpha * (z - focusDist) / z;
    // Write to R, G channels of output
    return float4( CoC, z, 0, 1 );
}

この場合、Pw はワールド空間の位置で、view はマトリクスです。

アルファと焦点距離の現在の内部計算を以下に示します。

float ItoM = 0.0254f; // inches converted to m
float CMtoM = 0.01f; // cm converted to m

// Obtain the hyperfocal distance from the camera in m.
//
float focus = <camera shape’s focusDistance> * CMtoM;
focusDist = focus * 100; // Convert back to cm.

// Compute alpha, the COC at infinity, in m
//
float fStop = <camera shape’s fStop> * <camera shape’s focus region scale> // Apply region scale
float F = <camera shape’s camera scale> * <camera shape’s focal length> * 0.001f; // in m
float alpha = F * F / (fStop * (focus - F));

// Convert to UV space
float apertureX = <camera shape’s horizontal film aperture> * 0.001f;
float apertureY = <camera shape’s vertical film aperture> * 0.001f;
alpha /= min( apertureX, apertureY );

カメラのシェイプ パラメータは、上記の疑似コードでは、区切り文字 <> で示されています。

注: Maya 2016 に適用される上記のアルゴリズムは、COC の計算方法の唯一のサンプルです。カスタム シェーダは、任意の方法で適切に COC を実装することができ、Maya のカメラ ノードのアトリビュートを使用する必要がありません。

合成のコントロール

イメージ プレーンなどの例外を除き、Maya のほとんどの内部シェイプはポストエフェクトの影響を受けます。対照的に、プラグイン レンダー項目は、既定ではポストエフェクトから除外されます。MPxGeometryOverride および MPxSubSceneOverride の API は、MRenderItem::setExcludedFromPostEffects() から false を返すことで、レンダー項目ごとにこの既定の動作をオーバーライドできます。一方、MPxDrawOverride API はオブジェクトレベルのコントロールを行います。この API をポストエフェクトに含めるには、 false を返すように仮想関数 MPxDrawOverride::excludedFromPostEffect() をオーバーライドするか、登録時に描画分類文字列を drawdb/geometry/includePostEffects/ で開始します。最後に、すべてのサーフェス上の半透明のピクセルは、プラグインによって描画されるネイティブのピクセルであるかどうかに関係なく、ビューポート 2.0 のポストエフェクトから除外されます。

ポストエフェクトの影響を受ける不透明なサーフェスを、ポストエフェクトから除外されているサーフェスと合成するために、ビューポート 2.0 は、オリジナルのビューティ パス出力とポストエフェクト パスの出力との間でフルスクリーン パス ブレンドを実行します。これは、ポストエフェクト パターン パスとそれに続く非ポストエフェクト パターン パスによって生成されるアルファ マスク レンダー ターゲットに基づいています。

ポストエフェクト パターン パスの間、ポストエフェクトに含まれるレンダー項目を描画する場合は、カラー書き込みが無効になり、中間深度バッファを埋めるために深度書き込みが有効になります。プラグインは、PEPatternPass 文字列定数(MPassContext::kPEPatternPassSemantic として定義)と一致するパス セマンティックに対して MPassContext を照会することで、このパスを検出できます。

非ポストエフェクト パターン パスの間、ポストエフェクトから除外されたレンダー項目を描画する場合は、同じ深度バッファが使用されますが、カラー書き込みは有効になり、アルファ マスク レンダー ターゲットが設定されます。プラグインは、MPassContext 文字列定数(nonPEPatternPass として定義)と一致するパス セマンティックに対して MPassContext::kNonPEPatternPassSemantic を照会することで、このパスを検出できます。既定では、レンダー項目はビューティ パスと同じシェーダを使用して非ポストエフェクト パターン パスに描画されますが、8 ビット アルファ形式であるため、アルファ マスク レンダー ターゲットに書き込まれるのはシェーダ出力のアルファ チャネルのみです。同時に、MPxShaderOverride および MPxDrawOverride API を使用するプラグインは上記の情報を使用して、このパスで任意の複雑なレンダリングを実行し、カスタム パターンを生成することができます。便利なように、これらの API のいずれかと MShaderInstance を併用することができます。レンダー ターゲットの詳細は、MDrawContext インスタンスから取得できます。

次のシェーダ疑似コードが示すように、非ポストエフェクト パターン パスが終了すると、スクリーンスペース合成パスが実行されます。このコードの AlphaMask テクスチャはアルファ マスク レンダー ターゲットを表します。SrcTarget はポスト エフェクト パスの出力、DstTarget はポスト エフェクトなしのビューティ パス出力です。結果は DstTargetSrcTarget にブレンドされます。

float4 CompositeWithAlphaMask( float3 UV,
                               texture2D SrcTarget, sampler SrcTargetSampler,
                               texture2D DstTarget, sampler DstTargetSampler,
                               texture2D AlphaMask, sampler AlphaMaskSampler )
{
    float4 srcColor = SrcTarget.Sample( SrcTargetSampler, UV.xy ); // Color with post effects
    float4 dstColor = DstTarget.Sample( DstTargetSampler, UV.xy ); // Color with no post effects
    float alphaMask = AlphaMask.Sample( AlphaMaskSampler, UV.xy ).a;
    return lerp( srcColor, dstColor, alphaMask );
}

特定のリリースへのこの実装の XML ラッパーは、MEL コマンドを使用して検索できます。

ogs -xml maya_CompositeWithAlphaMask;

API の MFragmentManager:: getFragmentXML() メソッドを使用して、このシェーディング フラグメントを照会できます。 Developer Kit の fragmentDumper サンプル プラグインは、このメソッドを使用してフラグメントをダンプする方法を示します。

dumpFragment -fn maya_CompositeWithAlphaMask;

最後に、不透明サーフェスが合成された後、透明なサーフェスがポスト エフェクトなしでレンダリングされます。

フレームと描画コンテキスト

フレームと描画コンテキストの詳細については、「フレームと描画のコンテキスト」を参照してください。

注: 描画時にオーバーライド シェーダを取得するために MPassContext::shaderOverrideInstance() が呼び出される場合、MFrameContext から取得したライトの状態に基づいて、プラグインで isSingleSided パラメータを更新する必要があります。

重要: カスタム シェーダに対するジオメトリ要件については、適切な入力ストリームが提供されない場合、レンダラは内部的にそれらを作成しようと試みます。これはフレームごとに発生し、パフォーマンスに影響する場合があります。たとえば、MPxGeometryOverride がカスタム シェーダに対するジオメトリを提供するように書かれている場合、コードが位置のみを返し、法線ストリームを返さない場合、内部的に法線値を派生させようと試みます。