4.2 ライティング インタフェース

プラグイン エフェクトを使用して、またはレンダリング ループをオーバーライドして実装する場合、API ではサポートされているライト パラメータ/アトリビュートにアクセスできます。これには、各ライト タイプの基本的なアトリビュートおよびシャドウ マップ アクセスが含まれます。

情報は、描画コンテキスト(MDrawContext)の一部として提供されます。コンテキストは粒状性の可能な限り最低のレベルで利用できます。レンダリングに向けたハードウェア シェーダ設定の直前のポイントです。必要に応じて、シェーダを呼び出す前に、ライト パラメータ データを使用してシェーダ パラメータを更新できます。

インタフェースは使用上の制限がないデータ プロバイダでしかないので、必要に応じて、固定機能シェーディングにライトとシャドウの情報を使用できます。

ライト プロパティ情報を返す基本的な構造は MLightParameterInformation です。

これらのリストは、シーン内のアクティブなライトのセットを表します。どのライトがアクティブかを判別するには、インタラクティブ レンダリングの 3D ビューポート パラメータと、バッチ レンダリングのレンダー グローバル設定を考慮します。数も、表示されると考えられるシーン内のライトの数およびアクティブな GPU デバイスによってサポートできるライトの数によって制限されます。

アンビエント ライトは、ディレクショナル プロパティを持たない単一のグローバル周囲光とみなされます。これはレンダリング フレームワークのプロパティであり、この API のプロパティではありません。

ライト情報のインタフェースは、シェーダ インスタンスの場合と同様にパラメータ ベースです。すべてのライトが同じプロパティを共有するのではなく、ライトのタイプによって異なるパラメータにアクセスできます。セマンティックはパラメータ値の背後にある意味を提供します。

レンダリング フレームワークによって生成されるシャドウ マップにアクセスできます。これらはテクスチャ(MTexture)として返されます。適切な変換によるテクスチャのルックアップに使用されるマトリックスが、パラメータの 1 つとして提供されます。テクスチャのサンプラはサンプラの説明として返されます。シャドウ マップは、ビューポートまたはバッチ レンダー設定およびライトごとの設定に基づいて返されます(たとえば、シャドウ マッピングがライトに対して有効である場合)。

次の図は、レンダリング時に MDrawContextMPxShaderOverrideMSceneRenderMUserOperation の各オペレーションおよび MShaderInstance インスタンスで使用できることを示します。

図 66: ライティング情報へのアクセスは、描画コンテキストへのアクセスに基づきます。

サンプル:

次のサンプルコードでは、OpenGL で使用するためにシャドウ マップ パラメータを抽出する方法を示します。

// Get the number of active lights 
unsigned int lightCount = context.numberOfActiveLights();
for (unsigned int i=0; i<lightCount; i++) 
{
    // Get light parameter information for a given light
    MHWRender::MLightParameterInformation *lightParam = 
        context.getLightParameterInformation( i );
    if (lightParam) {
        
        MStringArray params;
        lightParam->parameterList(params);

        // Scan through all the parameters for this light. They may be differ for different 
        // light types.
        for (unsigned int p=0; p<params.length(); p++) {
            MHWRender::MSamplerStateDesc samplerDesc;
            if (ptype == MHWRender::MLightParameterInformation::kTexture2) {
                // OpenGL specific extraction of the GPU handle for a shadow map texture
                void *handle = lightParam->getParameterTextureHandle( pname );
                if (handle)
                    int openGLHandle = *((int *)handle));
                break;
            }
            else if (ptype == MHWRender::MLightParameterInformation::kSampler) {
                // Get a sampler description.
                lightParam->getParameter( pname, samplerDesc );
            }                                         
        }
    }
}

4.2.1 シャドーイング コントロール

MPassContext の情報は、シャドウ マップ作成の間にプラグインがレンダリング用に呼び出されるときに示す十分な情報を提供します。MPxShaderOverride および MPxDrawOverride インタフェースはこの情報を使用して複雑なレンダリングを実行できます。既定では、レンダラ自体が既定の状態および/または使用する既定のシェーダを設定します。

MPxDrawOverride の場合、描画コードを最適化して、カラー パス レンダリングにのみ必要なコードを実行しないようにすることができます。たとえば、すべてのブレンド操作を無効にできます。

MPxShaderOverride の場合、カラー パス シェーダが何らかの種類のデフォメーションまたはテッセレーションを実行する場合、描画コードでカスタム シャドウ シェーダの使用を選択できます。

便宜上、MShaderInstance はどちらのプラグイン インタフェースでも使用できます。MPxShaderOverride 内から使用する場合、冗長なシェーダの変更を減らすため、バインドおよびバインド解除は、キーのアクティブ化および非アクティブ化のときに行う必要があります。MDrawOverride 内から使用する場合、バインドおよびバインド解除は描画呼び出しの中で行う必要があります。

結果のシャドウ マップは、内部レンダリングに使用され、プラグインのビューティ パス描画に使用できます。

次に示すのは、MPxDrawOverride のカスタム シャドウ投影および描画を設定するためのサンプル コードです。「ビューティ パス」では、MLightParameterInformation インスタンスから使用できるシャドウ マップおよび関連付けられたマトリックスを使用します。

class hwPhongShaderOverride : public MHWRender::MPxShaderOverride
{
protected:
    // Color shader
    MHWRender::MShaderInstance *fColorShaderInstance;
    // Shadow shader
    MHWRender::MShaderInstance *fShadowShaderInstance;
    
public:
    void createShaderInstance()
    {
        MHWRender::MRenderer *renderer = MHWRender::MRenderer::theRenderer();
        const MHWRender::MShaderManager* shaderMgr = renderer->getShaderManager();

        // If no shadow shader instance created yet acquire one. Use
        // the stock shadow shader provided.
        if (!fShadowShaderInstance)
        {
            fShadowShaderInstance = 
                shaderMgr->getStockShader( MHWRender::MShaderManager::k3dShadowerShader );
        }

        // If no color shader instance created yet acquire one. For
        // now it's just using an internal shader for convenience but
        // a custom shader could be written here as well.
        if (!fColorShaderInstance)
        {
            fColorShaderInstance = 
                shaderMgr->getStockShader( MHWRender::MShaderManager::k3dBlinnShader );
        }
    }
    
    /* virtual */ void activateKey(MHWRender::MDrawContext& context, const MString& key)
    {
        // Bind color or shadower shader as appropriate
        if (fInColorPass)
            fColorShaderInstance->bind( context );
        else if (fInShadowPass)
        {
            // Update the parameters on the shadow shader. Use the view projection 
            // matrix from the active context
            MMatrix viewProj =                                     
                context.getMatrix(MHWRender::MDrawContext::kViewProjMtx);
            fShadowShaderInstance->setParameter("shadowViewProj", viewProj );
            fShadowShaderInstance->bind( context );
        }
    }
    
    // Example of using MShaderInstace to draw. Terminate
    // the shader instance here.
    /* virtual */ void terminateKey(MHWRender::MDrawContext& context, const MString& key)
    {
        if (fInColorPass)
            fColorShaderInstance->unbind( context );
        else if (fInShadowPass)
            fShadowShaderInstance->unbind( context );
    }
    
    /* virtual */ bool draw(MHWRender::MDrawContext& context,
                       const MHWRender::MRenderItemList& renderItemList) const
    {
        // Draw for color pass with a blend state change
        if (fInColorPass)
        {
            stateMgr->setBlendState(sBlendState);
            unsigned int passCount = fColorShaderInstance->getPassCount( context );
            for (unsigned int i=0; i<passCount; i++)
            {
                fColorShaderInstance->activatePass( context, i );
                MHWRender::MPxShaderOverride::drawGeometry(context);
            }
            stateMgr->setBlendState(pOldBlendState);
        }
        // Draw for shadow pass
        else if (fInShadowPass)
        {
            unsigned int passCount = fShadowShaderInstance->getPassCount( context );
            for (unsigned int i=0; i<passCount; i++)
            {
                fShadowShaderInstance->activatePass( context, i );
                MHWRender::MPxShaderOverride::drawGeometry(context);
            }
        }
    }
}

dx11Shader の例ではカスタム シェーダを使用します。

4.2.2 「無制限」のライト情報アクセス

内部シェーディングに使用されるライトの数はレンダラのライトの制限数クランプによって制限されますが、ライト情報にアクセスするための API インタフェースを使用すると、このライトの制限数の設定を無視するかどうかを指定できます。

以下のインタフェースには、ライトの制限数をバイパスするための LightFilter パラメータを指定するオプションがあります。

4.2.3 「必要に応じた」シャドウ/ライティングの更新