New Blending with pre-multiplied alpha

Finally found how to improve blending modes by pre-multiplying color by alpha in the shader, so that the blending equations can be applied on top of the apha manipulation.
This commit is contained in:
Bruno
2021-02-18 23:36:01 +01:00
parent 64071a4a55
commit f51bc1f1f4
7 changed files with 61 additions and 25 deletions

View File

@@ -171,7 +171,7 @@ void ImGuiVisitor::visit(Shader &n)
// ImGui::SameLine(0, 5);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int mode = n.blending;
if (ImGui::Combo("Blending", &mode, "Normal\0Screen\0Inverse\0Addition\0Subtract\0") ) {
if (ImGui::Combo("Blending", &mode, "Normal\0Screen\0Subtract\0Multiply\0Soft light\0Soft subtract\0") ) {
n.blending = Shader::BlendMode(mode);
std::ostringstream oss;
@@ -180,18 +180,21 @@ void ImGuiVisitor::visit(Shader &n)
case Shader::BLEND_OPACITY:
oss<<"Normal";
break;
case Shader::BLEND_ADD:
case Shader::BLEND_SCREEN:
oss<<"Screen";
break;
case Shader::BLEND_SUBSTRACT:
oss<<"Inverse";
break;
case Shader::BLEND_LAYER_ADD:
oss<<"Addition";
break;
case Shader::BLEND_LAYER_SUBSTRACT:
oss<<"Subtract";
break;
case Shader::BLEND_MULTIPLY:
oss<<"Multiply";
break;
case Shader::BLEND_SOFT_LIGHT:
oss<<"Soft light";
break;
case Shader::BLEND_SOFT_SUBTRACT:
oss<<"Soft subtract";
break;
case Shader::BLEND_CUSTOM:
oss<<"Custom";
break;

View File

@@ -274,7 +274,7 @@ void SessionGroupSource::init()
{
if ( resolution_.x > 0.f && resolution_.y > 0.f ) {
session_->setResolution( resolution_ );
session_->setResolution( resolution_, true );
// update to draw framebuffer
session_->update( dt_ );
@@ -283,7 +283,7 @@ void SessionGroupSource::init()
texturesurface_->setTextureIndex( session_->frame()->texture() );
// create Frame buffer matching size of session
FrameBuffer *renderbuffer = new FrameBuffer( session_->frame()->resolution() );
FrameBuffer *renderbuffer = new FrameBuffer( session_->frame()->resolution(), true );
// set the renderbuffer of the source and attach rendering nodes
attach(renderbuffer);

View File

@@ -23,11 +23,32 @@
ShadingProgram *ShadingProgram::currentProgram_ = nullptr;
ShadingProgram simpleShadingProgram("shaders/simple.vs", "shaders/simple.fs");
// Blending presets for matching with Shader::BlendMode
GLenum blending_equation[6] = { GL_FUNC_ADD, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD};
GLenum blending_source_function[6] = { GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA};
GLenum blending_destination_function[6] = {GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE, GL_DST_COLOR, GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA};
// Blending presets for matching with Shader::BlendModes:
GLenum blending_equation[7] = { GL_FUNC_ADD, // normal
GL_FUNC_ADD, // screen
GL_FUNC_REVERSE_SUBTRACT, // subtract
GL_FUNC_ADD, // multiply
GL_FUNC_ADD, // soft light
GL_FUNC_REVERSE_SUBTRACT, // soft subtract
GL_FUNC_ADD};
GLenum blending_source_function[7] = { GL_ONE, // normal
GL_ONE, // screen
GL_SRC_COLOR, // subtract (can be GL_ONE)
GL_DST_COLOR, // multiply : src x dst color
GL_DST_COLOR, // soft light : src x dst color
GL_DST_COLOR, // soft subtract
GL_ONE};
GLenum blending_destination_function[7] = {GL_ONE_MINUS_SRC_ALPHA,// normal
GL_ONE, // screen
GL_ONE, // subtract
GL_ONE_MINUS_SRC_ALPHA, // multiply
GL_ONE, // soft light
GL_ONE, // soft subtract
GL_ONE_MINUS_SRC_ALPHA};
//GLenum blending_equation[6] = { GL_FUNC_ADD, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD};
//GLenum blending_source_function[6] = { GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA};
//GLenum blending_destination_function[6] = {GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE, GL_DST_COLOR, GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA};
ShadingProgram::ShadingProgram(const std::string& vertex_file, const std::string& fragment_file) : vertex_id_(0), fragment_id_(0), id_(0)
@@ -223,18 +244,28 @@ void Shader::use()
glEnable(GL_BLEND);
// glBlendEquation(blending_equation[BLEND_OPACITY]);
// glBlendFunc(blending_source_function[BLEND_OPACITY], blending_destination_function[BLEND_OPACITY]);
glBlendEquationSeparate(blending_equation[BLEND_OPACITY], GL_MAX);
glBlendFuncSeparate(blending_source_function[BLEND_OPACITY], blending_destination_function[BLEND_OPACITY], GL_SRC_ALPHA, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
}
else if ( blending != BLEND_CUSTOM ) {
glEnable(GL_BLEND);
// glBlendEquation(blending_equation[blending]);
// glBlendFunc(blending_source_function[blending], blending_destination_function[blending]);
// different blending for alpha and color
glBlendEquationSeparate(blending_equation[blending], GL_MAX);
glBlendFuncSeparate(blending_source_function[blending], blending_destination_function[blending], GL_SRC_ALPHA, GL_ONE);
// different blending for alpha and color
// glBlendColor(1.f, 1.f, 1.f, 1.f);
glBlendEquationSeparate(blending_equation[blending], GL_FUNC_ADD);
glBlendFuncSeparate(blending_source_function[blending], blending_destination_function[blending], GL_ONE, GL_ZERO);
// glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
// glBlendFuncSeparate( GL_SRC_ALPHA, GL_CONSTANT_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// glBlendEquation(GL_FUNC_ADD);
// glBlendFunc(GL_DST_COLOR, GL_ZERO);
// glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
// glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
}
else
glDisable(GL_BLEND);

View File

@@ -60,10 +60,11 @@ public:
typedef enum {
BLEND_OPACITY = 0,
BLEND_ADD,
BLEND_SCREEN,
BLEND_SUBSTRACT,
BLEND_LAYER_ADD,
BLEND_LAYER_SUBSTRACT,
BLEND_MULTIPLY,
BLEND_SOFT_LIGHT,
BLEND_SOFT_SUBTRACT,
BLEND_CUSTOM
} BlendMode;
BlendMode blending;

View File

@@ -257,7 +257,7 @@ MixingView::MixingView() : View(MIXING), limbo_scale_(1.3f)
// Mixing scene background
Mesh *tmp = new Mesh("mesh/disk.ply");
tmp->scale_ = glm::vec3(limbo_scale_, limbo_scale_, 1.f);
tmp->shader()->color = glm::vec4( COLOR_LIMBO_CIRCLE, 0.6f );
tmp->shader()->color = glm::vec4( COLOR_LIMBO_CIRCLE, 0.7f );
scene.bg()->attach(tmp);
mixingCircle_ = new Mesh("mesh/disk.ply");

View File

@@ -31,8 +31,9 @@ void main()
// alpha is a mix of texture alpha, vertex alpha, and uniform alpha affected by stippling
float A = textureColor.a * vertexColor.a * color.a * maskIntensity;
A += textureColor.a * stipple * ( int(gl_FragCoord.x + gl_FragCoord.y) % 2 );
A = clamp(A, 0.0, 1.0);
// output RGBA
FragColor = vec4(RGB, clamp(A, 0.0, 1.0) );
FragColor = vec4(RGB * A, A);
// FragColor = texture(iChannel1, vertexUV);
}

View File

@@ -366,7 +366,7 @@ void main(void)
transformedRGB = LevelsControl(transformedRGB, levels.x, gamma.rgb * gamma.a, levels.y, levels.z, levels.w);
// apply base color and alpha for final fragment color
FragColor = vec4(transformedRGB * vertexColor.rgb * color.rgb, clamp(alpha, 0.0, 1.0) );
FragColor = vec4(transformedRGB * vertexColor.rgb * color.rgb * alpha, clamp(alpha, 0.0, 1.0) );
}