0

私が今やろうとしているのは、COLLADA インポーターを透明な COLLADA モデルで動作させることです。モデルのブレンディングは、COLLADA 仕様の第 7 章、「レンダリング/透明度の決定」の段落で指定されています。

つまり、ブレンド方程式には 2 つの入力があります。TrasparentTrasparencyです。前者は RGBA カラーまたはテクスチャにすることができ、後者は浮動小数点値のみにすることができます。さらに、Transparentは 2 つのブレンド方程式 ( ColladaFxOpaqueType.AlphaOneおよびColladaFxOpaqueType.RgbZero )を指定できます。

2 つのブレンド方程式を次に示します。

// AlphaOne 
//
// result.r = fb.r * (1.0f - transparent.a * transparency) + mat.r * (transparent.a * transparency)
// result.g = fb.g * (1.0f - transparent.a * transparency) + mat.g * (transparent.a * transparency)
// result.b = fb.b * (1.0f - transparent.a * transparency) + mat.b * (transparent.a * transparency)
// result.a = fb.a * (1.0f - transparent.a * transparency) + mat.a * (transparent.a * transparency)

// RgbZero
//
// result.r = fb.r * (transparent.r * transparency) + mat.r * (1.0f -transparent.r * transparency)
// result.g = fb.g * (transparent.g * transparency) + mat.g * (1.0f -transparent.g * transparency)
// result.b = fb.b * (transparent.b * transparency) + mat.b * (1.0f -transparent.b * transparency)
// result.a = fb.a * (luminance(transparent.rgb) * transparency) + mat.a * (1.0f - luminance(transparent.rgb) * transparency)

where
- result: draw framebuffer
- fb: destination blend color
- mat: source blend color
- transparent: COLLADA parameter described above
- transparency: COLLADA parameter described above
- luminance: function to average color following ITU-R Recommendation BT.709-4

私が今実装したのは、Transparentが色を表す場合にジオメトリをブレンドすることです (両方のブレンド方程式)。以下は、この機能を実装する固有のコードです。

internal void CompileBlendStateParameters(ColladaShaderParameters shaderParameters, ColladaFxCommonContext commonContext)
{
    if (shaderParameters == null)
        throw new ArgumentNullException("shaderParameters");
    if (commonContext == null)
        throw new ArgumentNullException("commonContext");

    // Apply alpha blending, if required
    if ((Transparent != null) || (Transparency != null)) {
        BlendState blendState = null;
        ColorRGBAF blendFactors = new ColorRGBAF(1.0f); // No effect value
        float trasparency = 1.0f;                       // No effect value

        if (Transparency != null)
            trasparency = Transparency.GetValue(commonContext);

        if ((Transparent != null) && (Transparent.IsFixedColor(commonContext) == true)) {
            switch (Transparent.Opaque) {
                case ColladaFxOpaqueType.AlphaOne:

                    // Equation from COLLADA specification:
                    //
                    // result.r = fb.r * (1.0f - transparent.a * transparency) + mat.r * (transparent.a * transparency)
                    // result.g = fb.g * (1.0f - transparent.a * transparency) + mat.g * (transparent.a * transparency)
                    // result.b = fb.b * (1.0f - transparent.a * transparency) + mat.b * (transparent.a * transparency)
                    // result.a = fb.a * (1.0f - transparent.a * transparency) + mat.a * (transparent.a * transparency)

                    // Determine blend factor constant color
                    blendFactors = new ColorRGBAF(Transparent.GetFixedColor(commonContext).Alpha);
                    // Modulate constant color
                    blendFactors = blendFactors * trasparency;
                    // Create blend state
                    blendState = new BlendState(BlendState.BlendEquation.Add, BlendState.BlendFactor.ConstColor, BlendState.BlendFactor.ConstColorComplement, blendFactors);
                    break;
                case ColladaFxOpaqueType.RgbZero:

                    // Equation from COLLADA specification:
                    //
                    // result.r = fb.r * (transparent.r * transparency) + mat.r * (1.0f -transparent.r * transparency)
                    // result.g = fb.g * (transparent.g * transparency) + mat.g * (1.0f -transparent.g * transparency)
                    // result.b = fb.b * (transparent.b * transparency) + mat.b * (1.0f -transparent.b * transparency)
                    // result.a = fb.a * (luminance(transparent.rgb) * transparency) + mat.a * (1.0f - luminance(transparent.rgb) * transparency)

                    // Determine blend factor constant color
                    blendFactors = new ColorRGBAF(Transparent.GetFixedColor(commonContext));
                    // Define alpha blend factor as luminance
                    blendFactors.Alpha = blendFactors.Red * 0.212671f + blendFactors.Green * 0.715160f + blendFactors.Blue * 0.072169f;
                    // Modulate constant color
                    blendFactors = blendFactors * trasparency;
                    // Create blend state
                    blendState = new BlendState(BlendState.BlendEquation.Add, BlendState.BlendFactor.ConstColorComplement, BlendState.BlendFactor.ConstColor, blendFactors);
                    break;
            }
        } else if ((Transparent != null) && (Transparent.IsTextureColor(commonContext) == true)) {

            throw new NotSupportedException();

        } else {
            // Modulate constant color
            blendFactors = blendFactors * trasparency;
            // Create blend state
            blendState = new BlendState(BlendState.BlendEquation.Add, BlendState.BlendFactor.ConstColor, BlendState.BlendFactor.ConstColorComplement, blendFactors);
        }

        if (blendState != null)
            shaderParameters.RenderState.DefineState(blendState);
    }
}

大まかに言うと、上記のコードは OpenGL レイヤーを抽象化しており、次と同等です。

 // AlphaOne equation
 glEnable(GL_BLEND);
 glBlendEquation(GL_FUNC_ADD);
 glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR);
 glBlendColor(blendFactors.Red, blendFactors.Green, blendFactors.Blue, blendFactors.Alpha);

 // RgbZero equation
 glEnable(GL_BLEND);
 glBlendEquation(GL_FUNC_ADD);
 glBlendFunc(GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_COLOR);
 glBlendColor(blendFactors.Red, blendFactors.Green, blendFactors.Blue, blendFactors.Alpha);

 // Having calculated blendFactor appropriately!!

私が望むのは、テクスチャに基づいて透過性をサポートすることです (実際、その恐ろしいNotSupportedExceptionを削除します)。通常、これは、出力されたフラグメント アルファ コンポーネントにテクスチャをアタッチし、通常どおりブレンドをセットアップすることによって実装されます (アルファおよび OneMinusAlpha ブレンド ファクター)。ですよね?)。

PS簡単なソリューションを使用してブレンドを実装したことに注意してください。ただし、一定のブレンドカラー(blendFactorsコード内の変数)に基づいています(実際にはGL_EXT_blend_color拡張を使用しています)。通常のブレンディング関数を使用して、この依存関係を削除するにはどうすればよいですか? 最後の質問の解決策は、テクスチャに基づくブレンドについて役立つと思います...

4

1 に答える 1

0

私はあなたが何をしようとしているのかよくわかりませんが、私はそれを突き刺します (コメントでフォローアップしてください)

標準の opengl ブレンディングを使用して AlphaOne および RgbZero 式を実装し、一定の色を使用する代わりに、画像のテクセルごとにブレンド関数を評価する必要があります。透明度の一般的なブレンド関数 (SRC_ALPHA、ONE_MINUS_SRC_ALPHA) は、着信フラグメントのアルファ値を使用し、次のように評価されます。

result = dst * (1-src_alpha) + src * src_alpha

実装したい 2 つの方程式を 1 つずつ見ていきます (簡潔にするために赤とアルファのみ)。

アルファワン:

result.r = fb.r * (1.0f - transparent.a * transparency) + mat.r * (transparent.a * transparency);
result.a = fb.a * (1.0f - transparent.a * transparency) + mat.a * (transparent.a * transparency);

この方程式を見ると、投稿された最初の方程式と非常によく似ていることがわかります。を代用するだけtransparent.a*transparencyですsrc_alpha

これは、ピクセル シェーダーをtransparent.aテクスチャ サンプルから取得した値で取得transparencyし、一様なフロートとして使用する場合、AlphaOne 関数を実装することを意味します。

sampler2D tex;
uniform transparency;

main() {
   vec4 texel = texture2D(tex,uv);
   vec3 out_rgb = texel.rgb;
   float out_alpha = texel.a * transparency;
   gl_FragColor = vec4(out_rgb, out_alpha);
}

このシェーダtransparent.a * transparencyは、ブレンド方程式で使用される src_alpha 値として送信されます。

これは、典型的な opengl ブレンドでこのアルゴリズムを簡単に実装できることを示していると思います。

ただし、RGBZero 関数は私には難しいように見えます。それを実現するブレンド関数はないと思います。私が持っている奇妙なアイデアの 1 つは、4 つのカラー チャネルを 1 つずつ描画することです (編集用に G、B、A をロックし、R ブレンド ファクターとして出力アルファを使用して R を描画し、他の 3 つのカラー チャネルについて繰り返します)。それは私には奇妙なブレンド機能のように見えますが、それが何に使用されるかはわかりません。

于 2012-08-22T05:18:17.013 に答える