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::SameLine(0, 5);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int mode = n.blending; 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); n.blending = Shader::BlendMode(mode);
std::ostringstream oss; std::ostringstream oss;
@@ -180,18 +180,21 @@ void ImGuiVisitor::visit(Shader &n)
case Shader::BLEND_OPACITY: case Shader::BLEND_OPACITY:
oss<<"Normal"; oss<<"Normal";
break; break;
case Shader::BLEND_ADD: case Shader::BLEND_SCREEN:
oss<<"Screen"; oss<<"Screen";
break; break;
case Shader::BLEND_SUBSTRACT: case Shader::BLEND_SUBSTRACT:
oss<<"Inverse";
break;
case Shader::BLEND_LAYER_ADD:
oss<<"Addition";
break;
case Shader::BLEND_LAYER_SUBSTRACT:
oss<<"Subtract"; oss<<"Subtract";
break; 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: case Shader::BLEND_CUSTOM:
oss<<"Custom"; oss<<"Custom";
break; break;

View File

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

View File

@@ -23,11 +23,32 @@
ShadingProgram *ShadingProgram::currentProgram_ = nullptr; ShadingProgram *ShadingProgram::currentProgram_ = nullptr;
ShadingProgram simpleShadingProgram("shaders/simple.vs", "shaders/simple.fs"); ShadingProgram simpleShadingProgram("shaders/simple.vs", "shaders/simple.fs");
// Blending presets for matching with Shader::BlendMode // Blending presets for matching with Shader::BlendModes:
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_equation[7] = { GL_FUNC_ADD, // normal
GLenum blending_source_function[6] = { GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA}; GL_FUNC_ADD, // screen
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}; 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) 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); glEnable(GL_BLEND);
// glBlendEquation(blending_equation[BLEND_OPACITY]); // glBlendEquation(blending_equation[BLEND_OPACITY]);
// glBlendFunc(blending_source_function[BLEND_OPACITY], blending_destination_function[BLEND_OPACITY]); // glBlendFunc(blending_source_function[BLEND_OPACITY], blending_destination_function[BLEND_OPACITY]);
glBlendEquationSeparate(blending_equation[BLEND_OPACITY], GL_MAX); glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(blending_source_function[BLEND_OPACITY], blending_destination_function[BLEND_OPACITY], GL_SRC_ALPHA, GL_ONE); glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
} }
else if ( blending != BLEND_CUSTOM ) { else if ( blending != BLEND_CUSTOM ) {
glEnable(GL_BLEND); glEnable(GL_BLEND);
// glBlendEquation(blending_equation[blending]); // glBlendEquation(blending_equation[blending]);
// glBlendFunc(blending_source_function[blending], blending_destination_function[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 else
glDisable(GL_BLEND); glDisable(GL_BLEND);

View File

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

View File

@@ -257,7 +257,7 @@ MixingView::MixingView() : View(MIXING), limbo_scale_(1.3f)
// Mixing scene background // Mixing scene background
Mesh *tmp = new Mesh("mesh/disk.ply"); Mesh *tmp = new Mesh("mesh/disk.ply");
tmp->scale_ = glm::vec3(limbo_scale_, limbo_scale_, 1.f); 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); scene.bg()->attach(tmp);
mixingCircle_ = new Mesh("mesh/disk.ply"); 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 // alpha is a mix of texture alpha, vertex alpha, and uniform alpha affected by stippling
float A = textureColor.a * vertexColor.a * color.a * maskIntensity; float A = textureColor.a * vertexColor.a * color.a * maskIntensity;
A += textureColor.a * stipple * ( int(gl_FragCoord.x + gl_FragCoord.y) % 2 ); A += textureColor.a * stipple * ( int(gl_FragCoord.x + gl_FragCoord.y) % 2 );
A = clamp(A, 0.0, 1.0);
// output RGBA // output RGBA
FragColor = vec4(RGB, clamp(A, 0.0, 1.0) ); FragColor = vec4(RGB * A, A);
// FragColor = texture(iChannel1, vertexUV); // 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); transformedRGB = LevelsControl(transformedRGB, levels.x, gamma.rgb * gamma.a, levels.y, levels.z, levels.w);
// apply base color and alpha for final fragment color // 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) );
} }