预乘 alpha 混合的问题
Trouble with pre-multiplied alpha blending
我创建了一个复合渲染器,它简单地对两个纹理进行 alpha 混合,一个在另一个之上。混合工作不正常。
这里是渲染器的代码,只渲染背景:
RenderFunction layer_render = [&]() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(layer_shader_.get_program_id());
// ----- Fetch shader uniform locations
layer_shader_.SetUniform("tex", 0);
layer_shader_.SetUniform("create_alpha_mask", false);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
layer_shader_.SetUniform("model", background_model_);
background_mesh_.Bind();
glDrawElements(GL_TRIANGLES, background_mesh_.GetIndicesCount(), GL_UNSIGNED_INT, (void*)0);
background_mesh_.Unbind();
};
layer_framebuffer_.RenderToTexture(layer_render);
我传递的背景纹理是完整的 rgba -> {1.0, 0.0, 0.0, 0.5}。结果是 -> {0.5, 0.0, 0.0, 0.5}。由于某些我没有看到的原因,在计算混合时,alpha 混合没有正确考虑源 alpha。
我所期待的一些伪代码:
source_alpha = 0.5
dest_alpha = 0.0 * (1.0 - source_alpha) = 0.0
output_alpha = source_alpha + dest_alpha = 0.5
out_r = (source_r * source_alpha + dest_r * dest_alpha) / output_alpha = (1.0 * 0.5 + 0.0 * 0.0) / 0.5 = 1.0
out_g = (source_g * source_alpha + dest_g * dest_alpha) / output_alpha = (0.0 * 0.5 + 0.0 * 0.0) / 0.5 = 0.0
out_b = (source_b * source_alpha + dest_b * dest_alpha) / output_alpha = (0.0 * 0.5 + 0.0 * 0.0) / 0.5 = 0.0
out_a = output_alpha = 0.5
我不知道你从哪里得到伪代码,但这不是它的工作原理。为什么要除以 (source_alpha + dest_alpha)?
如果你想使用预乘 alpha,你所做的就是将混合函数设置为:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
因此它不会将源与 alpha 相乘,然后在最后的片段着色器中将 rgb 与 alpha 相乘,这意味着:
color.rgb *= color.a;
就是这样。
我创建了一个复合渲染器,它简单地对两个纹理进行 alpha 混合,一个在另一个之上。混合工作不正常。
这里是渲染器的代码,只渲染背景:
RenderFunction layer_render = [&]() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(layer_shader_.get_program_id());
// ----- Fetch shader uniform locations
layer_shader_.SetUniform("tex", 0);
layer_shader_.SetUniform("create_alpha_mask", false);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
layer_shader_.SetUniform("model", background_model_);
background_mesh_.Bind();
glDrawElements(GL_TRIANGLES, background_mesh_.GetIndicesCount(), GL_UNSIGNED_INT, (void*)0);
background_mesh_.Unbind();
};
layer_framebuffer_.RenderToTexture(layer_render);
我传递的背景纹理是完整的 rgba -> {1.0, 0.0, 0.0, 0.5}。结果是 -> {0.5, 0.0, 0.0, 0.5}。由于某些我没有看到的原因,在计算混合时,alpha 混合没有正确考虑源 alpha。
我所期待的一些伪代码:
source_alpha = 0.5
dest_alpha = 0.0 * (1.0 - source_alpha) = 0.0
output_alpha = source_alpha + dest_alpha = 0.5
out_r = (source_r * source_alpha + dest_r * dest_alpha) / output_alpha = (1.0 * 0.5 + 0.0 * 0.0) / 0.5 = 1.0
out_g = (source_g * source_alpha + dest_g * dest_alpha) / output_alpha = (0.0 * 0.5 + 0.0 * 0.0) / 0.5 = 0.0
out_b = (source_b * source_alpha + dest_b * dest_alpha) / output_alpha = (0.0 * 0.5 + 0.0 * 0.0) / 0.5 = 0.0
out_a = output_alpha = 0.5
我不知道你从哪里得到伪代码,但这不是它的工作原理。为什么要除以 (source_alpha + dest_alpha)?
如果你想使用预乘 alpha,你所做的就是将混合函数设置为:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
因此它不会将源与 alpha 相乘,然后在最后的片段着色器中将 rgb 与 alpha 相乘,这意味着:
color.rgb *= color.a;
就是这样。