Light Filters(ライトフィルター)

ライトフィルター

ライトフィルターは、光源がサンプリングされた後に光源のカラーを変更します。ライトフィルターは、bxdfがジオメトリに紐付けられているように、光源に紐付けられています。つまり、アトリビュートのスコーピングに従い、最後に指定したアトリビュートを取得します。

LightFilter "PxrGobo" "gobo1"  "string coordSys" ["Gobo1"] "string map" ["ratGrid.tx"] AreaLightSource "PxrArealight" "light1"

光源と同様に、ライトフィルターはデフォルトで有効化されています。以下を使用すると、特定のジオメトリックプリミティブでライトフィルターを無効化することができます。

EnableLightFilter "light1" "gobo1" 0

これにより、光源light1に紐付けられたフィルターgobo1が無効になります。単一の光源で、2個以上のフィルターを実行する方法を以下で説明します。

フィルタリング

ライトフィルターのプラグインは、以下のメソッドを実行します:

virtual void Filter(RixLightFilterContext const *lfCtx,
                    RtConstPointer instanceData,
                    RtInt const numSamples,
                    RtInt const * shadingCtxIndex,
                    RtVector3 const * toLight,
                    RtFloat const * dist,
                    RtFloat const * lightPdfIllum,
                    RixBXLobeWeights *contribution
                    );

パターンプラグインと同様に、ライトフィルターはコンテキストとして指定されます。RixLightFilterContextは、RixShadingContextのサブセットで、パターン生成を完全にはサポートしていません(EvalParam()がありません)。この機能については、今後のリリースで検討予定です。

光源のフィルタリングは、ライティングのサービスが、シェーディングコンテキストで各ポイントに対してサンプリングする光源を選んだ後に発生します。RixLightFilterContextのメンバー変数numPtsは、基本的なシェーディングコンテキストでのポイント数です。ライトフィルターは、光源毎にコールされるため、シェーディングコンテキストのすべてのポイントが、指定した光源からサンプルを取得するとは限りません。取得するサンプルが0のポイントもあれば、複数のサンプルを取得するポイントもあります。従って、Filterのコールはサンプル中心になります: つまり、Filterは、指定した光源に対して生成されたサンプルに対して働きます。

shadingCtxIndexは、生成元のシェーディングコンテキストのポイントに、特定のサンプルをマッピングして戻します。

toLight, dist, lightPdfIllumの3個のライティング配列は、長さ単位のnumSamplesです。これらは、それぞれ、光源に対するベクトル、シェーディングコンテキストのポイントから光源のサンプルポイントまでの距離、そして光源上のサンプルのpdfです。

入力/出力配列のcontributionには、数個のディフューズおよびスペキュラーのローブへ分配するライティング寄与が含まれます。各ローブには、numSamplesのエントリがあります。例えば、赤チャンネルのみを通過するフィルターでライティングを調整するには:

 

for(int j = 0; j < contribution->GetNumSpecularLobes(); ++j) {
    for(int i = 0; i < numSamples; ++i) {
       contribution->GetSpecularLobe(j)[i] *= RtColorRGB(1.0,0.0f,0.0f);
    }
}

for(int j = 0; j < contribution->GetNumDiffuseLobes(); ++j) {
    for(int i = 0; i < numSamples; ++i) {
       contribution->GetDiffuseLobe(j)[i] *= RtColorRGB(1.0,0.0f,0.0f);
    }
}

インスタンスデータ

オプションのインスタンスデータには、RIのストリームで最初にプラグインに当たった時にプラグインにより生成されるデータが含まれます。CreateInstanceDataのルーティンがコールされると、プラグインは、ライトフィルターのパラメータリストを利用できるようになり、任意のデータを作成することができます。このデータは、レンダラーにより保存され、フィルタリングの間、instanceDataのポインターとして指定されます。これは、同時に複数のスレッドが利用することができる均一のデータである必要があります。

以下のサンプルは、PxrLightFilterCombinerに対するCreateInstanceDataのメソッドです。bxdfと同様に、ライトフィルターは、他のライトフィルターに対して、引数で参照することができます。複数のライトフィルターを実行するには、EvalParamをコールして、上流のライトフィルターとそのインスタンスに対するポインターを取得します。これらのポインターは保存され、その後、フィルタリングの間、使用されます。
struct myData
{
    int arrayLen;
    RixLightFilter** filters;
    RtConstPointer* instances;
};

static
void releaseInstanceData(RtPointer data)
{
    myData* md = (myData*) data;
    delete[] md->filters;
    delete[] md->instances;
    delete md;
}

int
PxrLightFilterCombiner::CreateInstanceData(RixContext &ctx,
                  char const *handle,
                  RixParameterList const *plist,
                  RixシェーディングPlugin::InstanceData *idata)
{
    RixSCType typ;
    bool isconnected;
    int arraylen;
    plist->GetParamInfo(k_mult, &typ, &isconnected, &arraylen);

    myData* mydata = new myData;
    mydata->arrayLen = arraylen;
    mydata->filters = new RixLightFilter* [arraylen];
    mydata->instances = new RtConstPointer [arraylen];

    for (int i=0; i<arraylen; ++i)
        plist->EvalParam(k_mult, i, &mydata->filters[i], &mydata->instances[i]);

    idata->data = (void *) mydata;
    idata->freefunc = releaseInstanceData;
    return 0;
}

複数のフィルターの実行

bxdfと同様に、ライトフィルターは、他のライトフィルターに対するパラメータとして機能することができます。AreaLightSourceコール(フィルターのツリーのルートフィルター)の前で指定された最後のフィルターは、そのパラメータリストのフィルターへ権限を委託する必要があります。さらに、ライトフィルターはgprimベースで無効化することができます。これを考慮するために、フィルターは、RixLightFilterContext::IsEnabled()をコールする必要があります。上流のフィルターが有効になっていない場合は、実行しないでください。IsEnabledは、そのFilterメソッドに渡す必要のある上流フィルターのinstanceDataへのポインターも返します。

void combiner::Filter(RixLightFilterContext const *lfCtx,
                  RtConstPointer instanceData,
                  RtInt const numSamples,
                  RtInt const * shadingCtxIndex,
                  RtVector3 const * toLight,
                  RtFloat const * dist,
                  RtFloat const * lightPdfIllum,
                  RixBXLobeWeights *contribution
                 )
{
  myData const * mydata = (myData const *) instanceData;

  for (int i=0; i<mydata->arrayLen; ++i) {
      RtConstPointer nextInstanceData;
      if (lfCtx->IsEnabled(mydata->instances[i], &nextInstanceData))
      {
          mydata->filters[i]->Filter(
              lfCtx, nextInstanceData,
              numSamples, shadingCtxIndex,
              toLight, dist, lightPdfIllum, contribution);
      }
  }
}