C# COLLADA混合:基于纹理的透明度
我现在想做的是让我的COLLADA进口商在一些透明的COLLADA模型上工作。模型混合由第7章“渲染/确定透明度”一段规定 简而言之,混合方程有两个输入:透射率和透射率;前者可以是RGBA颜色或纹理,后者只能是浮点值。此外,Transparent可以指定两个混合方程(ColladaFxOpaqueType.AlphaOne和ColladaFxOpaqueType.RgbZero): 以下是两个混合方程式:C# COLLADA混合:基于纹理的透明度,c#,opengl,opengl-3,collada,C#,Opengl,Opengl 3,Collada,我现在想做的是让我的COLLADA进口商在一些透明的COLLADA模型上工作。模型混合由第7章“渲染/确定透明度”一段规定 简而言之,混合方程有两个输入:透射率和透射率;前者可以是RGBA颜色或纹理,后者只能是浮点值。此外,Transparent可以指定两个混合方程(ColladaFxOpaqueType.AlphaOne和ColladaFxOpaqueType.RgbZero): 以下是两个混合方程式: // AlphaOne // // result.r = fb.r * (1.0f -
// 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
我现在实现的是在透明表示颜色的情况下混合几何体(以及两个混合方程)。下面是实现此功能的特殊代码:
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);
}
}
Rougly,上面的代码抽象了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!!
我想要的是支持基于纹理的trasparencies(确实移除了可怕的NotSupportedException)。通常,这将通过将纹理附加到输出的片段alpha组件来实现,并像往常一样设置混合(alpha和OneMinusAlpha混合因子),但遗憾的是,这在上述等式中是不可能的(alpha组件不会被混合,不是吗?)
另外,您可以注意到,我通过使用一个简单的解决方案实现了混合,但是基于恒定的混合颜色(blendFactors
代码中的变量)(确实使用GL_EXT_blend_color extension)。如何使用普通混合函数删除此依赖关系?我认为上一个问题的解决方案可以帮助我了解基于纹理的混合…我不太确定我是否理解你的意图,但我会尝试一下(请随时在评论中跟进)
您希望使用标准opengl混合实现AlphaOne和RgbZero方程,并且希望对图像的每个纹理计算混合函数,而不是使用恒定颜色。透明度的典型混合函数(SRC_ALPHA,一个_减去_SRC_ALPHA)使用传入片段的ALPHA值,计算结果如下:
result = dst * (1-src_alpha) + src * src_alpha
一次看一个你想要实现的两个方程(为了简洁起见,只看红色和alpha):
AlphaOne:
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\u 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函数对我来说更难,我不相信有任何混合函数可以实现这一点。我有一个奇怪的想法,就是一次画一个彩色通道(锁定G、B、A进行编辑,只需绘制R,输出alpha作为R混合因子,然后对其他3个颜色通道重复。对我来说,这看起来有点奇怪的混合函数,但我想不出它会用于什么。我认为,如果不使用多通道渲染,即使是AlphaOne混合,也无法解决这个问题:您的解决方案覆盖“mat.a”信息(来自上一次计算)。解决方案将是两次混合:第一次用于RGB值,第二次仅用于alpha值(通过掩蔽颜色缓冲区渲染occour)通过使用GL_blend_equation_separate extension并应用不同的alpha混合函数,RGBZero混合适用。