Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix HardLight & SoftLight & Overlay & Multiply blend modes #2583

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 59 additions & 53 deletions framework/Source/GPUImageHardLightBlendFilter.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,44 @@
(
varying highp vec2 textureCoordinate;
varying highp vec2 textureCoordinate2;

uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;

const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);


mediump vec4 unpremultiply(mediump vec4 s) {
return vec4(s.rgb/max(s.a,0.00001), s.a);
}

mediump vec4 premultiply(mediump vec4 s) {
return vec4(s.rgb * s.a, s.a);
}

mediump float overlaySingleChannel(mediump float b, mediump float s) {
return b < 0.5 ? (2.0 * s * b) : (1.0 - 2.0 * (1.0 - b) * (1.0 - s));
}

mediump vec4 normalBlend(mediump vec4 Cb, mediump vec4 Cs) {
mediump vec4 dst = premultiply(Cb);
mediump vec4 src = premultiply(Cs);
return unpremultiply(src + dst * (1.0 - src.a));
}

mediump vec4 blendBaseAlpha(mediump vec4 Cb, mediump vec4 Cs, mediump vec4 B) {
mediump vec4 Cr = vec4((1.0 - Cb.a) * Cs.rgb + Cb.a * clamp(B.rgb, 0.0, 1.0), Cs.a);
return normalBlend(Cb, Cr);
}

// HardLight (simliar to Overlay , swap Cs and Cb)
void main()
{
mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);
mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);

highp float ra;
if (2.0 * overlay.r < overlay.a) {
ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
} else {
ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
}
mediump vec4 Cs = texture2D(inputImageTexture, textureCoordinate);
mediump vec4 Cb = texture2D(inputImageTexture2, textureCoordinate2);

highp float ga;
if (2.0 * overlay.g < overlay.a) {
ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
} else {
ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
}
mediump vec4 B = vec4(overlaySingleChannel(Cb.r, Cs.r),overlaySingleChannel(Cb.g, Cs.g),overlaySingleChannel(Cb.b,Cs.b),Cs.a);

highp float ba;
if (2.0 * overlay.b < overlay.a) {
ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
} else {
ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
}

gl_FragColor = vec4(ra, ga, ba, 1.0);
gl_FragColor = blendBaseAlpha(Cb, Cs, B);
}
);
);
#else
NSString *const kGPUImageHardLightBlendFragmentShaderString = SHADER_STRING
(
Expand All @@ -49,37 +52,40 @@ void main()
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;

const vec3 W = vec3(0.2125, 0.7154, 0.0721);
vec4 unpremultiply(vec4 s) {
return vec4(s.rgb/max(s.a,0.00001), s.a);
}

vec4 premultiply(vec4 s) {
return vec4(s.rgb * s.a, s.a);
}

float overlaySingleChannel(float b, float s) {
return b < 0.5 ? (2.0 * s * b) : (1.0 - 2.0 * (1.0 - b) * (1.0 - s));
}

vec4 normalBlend(vec4 Cb, vec4 Cs) {
vec4 dst = premultiply(Cb);
vec4 src = premultiply(Cs);
return unpremultiply(src + dst * (1.0 - src.a));
}

vec4 blendBaseAlpha(vec4 Cb, vec4 Cs, vec4 B) {
vec4 Cr = vec4((1.0 - Cb.a) * Cs.rgb + Cb.a * clamp(B.rgb, 0.0, 1.0), Cs.a);
return normalBlend(Cb, Cr);
}

// HardLight (simliar to Overlay , swap Cs and Cb)
void main()
{
vec4 base = texture2D(inputImageTexture, textureCoordinate);
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);

float ra;
if (2.0 * overlay.r < overlay.a) {
ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
} else {
ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
}

float ga;
if (2.0 * overlay.g < overlay.a) {
ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
} else {
ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
}
vec4 Cs = texture2D(inputImageTexture, textureCoordinate);
vec4 Cb = texture2D(inputImageTexture2, textureCoordinate2);

float ba;
if (2.0 * overlay.b < overlay.a) {
ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
} else {
ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
}
vec4 B = vec4(overlaySingleChannel(Cb.r, Cs.r),overlaySingleChannel(Cb.g, Cs.g),overlaySingleChannel(Cb.b,Cs.b),Cs.a);

gl_FragColor = vec4(ra, ga, ba, 1.0);
gl_FragColor = blendBaseAlpha(Cb, Cs, B);
}
);
);
#endif


Expand Down
62 changes: 50 additions & 12 deletions framework/Source/GPUImageMultiplyBlendFilter.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,37 @@
(
varying highp vec2 textureCoordinate;
varying highp vec2 textureCoordinate2;

uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;

mediump vec4 unpremultiply(mediump vec4 s) {
return vec4(s.rgb/max(s.a,0.00001), s.a);
}

mediump vec4 premultiply(mediump vec4 s) {
return vec4(s.rgb * s.a, s.a);
}

mediump vec4 normalBlend(mediump vec4 Cb, mediump vec4 Cs) {
mediump vec4 dst = premultiply(Cb);
mediump vec4 src = premultiply(Cs);
return unpremultiply(src + dst * (1.0 - src.a));
}

mediump vec4 blendBaseAlpha(mediump vec4 Cb, mediump vec4 Cs, mediump vec4 B) {
mediump vec4 Cr = vec4((1.0 - Cb.a) * Cs.rgb + Cb.a * clamp(B.rgb, 0.0, 1.0), Cs.a);
return normalBlend(Cb, Cr);
}

void main()
{
lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);
lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);
gl_FragColor = overlayer * base + overlayer * (1.0 - base.a) + base * (1.0 - overlayer.a);
lowp vec4 Cb = texture2D(inputImageTexture, textureCoordinate);
lowp vec4 Cs = texture2D(inputImageTexture2, textureCoordinate2);
lowp vec4 B = vec4(Cb.rgb * Cs.rgb, Cs.a);
gl_FragColor = blendBaseAlpha(Cb, Cs, B);
}
);
);
#else
NSString *const kGPUImageMultiplyBlendFragmentShaderString = SHADER_STRING
(
Expand All @@ -26,14 +45,33 @@ void main()
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;

vec4 unpremultiply(vec4 s) {
return vec4(s.rgb/max(s.a,0.00001), s.a);
}

vec4 premultiply(vec4 s) {
return vec4(s.rgb * s.a, s.a);
}

vec4 normalBlend(vec4 Cb, vec4 Cs) {
vec4 dst = premultiply(Cb);
vec4 src = premultiply(Cs);
return unpremultiply(src + dst * (1.0 - src.a));
}

vec4 blendBaseAlpha(vec4 Cb, vec4 Cs, vec4 B) {
vec4 Cr = vec4((1.0 - Cb.a) * Cs.rgb + Cb.a * clamp(B.rgb, 0.0, 1.0), Cs.a);
return normalBlend(Cb, Cr);
}

void main()
{
vec4 base = texture2D(inputImageTexture, textureCoordinate);
vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);

gl_FragColor = overlayer * base + overlayer * (1.0 - base.a) + base * (1.0 - overlayer.a);
vec4 Cb = texture2D(inputImageTexture, textureCoordinate);
vec4 Cs = texture2D(inputImageTexture2, textureCoordinate2);
vec4 B = vec4(Cb.rgb * Cs.rgb, Cs.a);
gl_FragColor = blendBaseAlpha(Cb, Cs, B);
}
);
);
#endif

@implementation GPUImageMultiplyBlendFilter
Expand All @@ -42,7 +80,7 @@ - (id)init;
{
if (!(self = [super initWithFragmentShaderFromString:kGPUImageMultiplyBlendFragmentShaderString]))
{
return nil;
return nil;
}

return self;
Expand Down
118 changes: 63 additions & 55 deletions framework/Source/GPUImageOverlayBlendFilter.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,43 @@
(
varying highp vec2 textureCoordinate;
varying highp vec2 textureCoordinate2;

uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;

mediump vec4 unpremultiply(mediump vec4 s) {
return vec4(s.rgb/max(s.a,0.00001), s.a);
}

mediump vec4 premultiply(mediump vec4 s) {
return vec4(s.rgb * s.a, s.a);
}

mediump float overlaySingleChannel(mediump float b, mediump float s) {
return b < 0.5 ? (2.0 * s * b) : (1.0 - 2.0 * (1.0 - b) * (1.0 - s));
}

mediump vec4 normalBlend(mediump vec4 Cb, mediump vec4 Cs) {
mediump vec4 dst = premultiply(Cb);
mediump vec4 src = premultiply(Cs);
return unpremultiply(src + dst * (1.0 - src.a));
}

mediump vec4 blendBaseAlpha(mediump vec4 Cb, mediump vec4 Cs, mediump vec4 B) {
mediump vec4 Cr = vec4((1.0 - Cb.a) * Cs.rgb + Cb.a * clamp(B.rgb, 0.0, 1.0), Cs.a);
return normalBlend(Cb, Cr);
}

void main()
{
mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);
mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);

mediump float ra;
if (2.0 * base.r < base.a) {
ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
} else {
ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
}
mediump vec4 Cb = texture2D(inputImageTexture, textureCoordinate);
mediump vec4 Cs = texture2D(inputImageTexture2, textureCoordinate2);

mediump float ga;
if (2.0 * base.g < base.a) {
ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
} else {
ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
}
mediump vec4 B = vec4(overlaySingleChannel(Cb.r, Cs.r),overlaySingleChannel(Cb.g, Cs.g),overlaySingleChannel(Cb.b,Cs.b),Cs.a);

mediump float ba;
if (2.0 * base.b < base.a) {
ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
} else {
ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
}

gl_FragColor = vec4(ra, ga, ba, 1.0);
gl_FragColor = blendBaseAlpha(Cb, Cs, B);
}
);
);
#else
NSString *const kGPUImageOverlayBlendFragmentShaderString = SHADER_STRING
(
Expand All @@ -47,47 +51,51 @@ void main()
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;

vec4 unpremultiply(vec4 s) {
return vec4(s.rgb/max(s.a,0.00001), s.a);
}

vec4 premultiply(vec4 s) {
return vec4(s.rgb * s.a, s.a);
}

float overlaySingleChannel(float b, float s) {
return b < 0.5 ? (2.0 * s * b) : (1.0 - 2.0 * (1.0 - b) * (1.0 - s));
}

vec4 normalBlend(vec4 Cb, vec4 Cs) {
vec4 dst = premultiply(Cb);
vec4 src = premultiply(Cs);
return unpremultiply(src + dst * (1.0 - src.a));
}

vec4 blendBaseAlpha(vec4 Cb, vec4 Cs, vec4 B) {
vec4 Cr = vec4((1.0 - Cb.a) * Cs.rgb + Cb.a * clamp(B.rgb, 0.0, 1.0), Cs.a);
return normalBlend(Cb, Cr);
}

void main()
{
vec4 base = texture2D(inputImageTexture, textureCoordinate);
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);

float ra;
if (2.0 * base.r < base.a) {
ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
} else {
ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
}

float ga;
if (2.0 * base.g < base.a) {
ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
} else {
ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
}
vec4 Cb = texture2D(inputImageTexture, textureCoordinate);
vec4 Cs = texture2D(inputImageTexture2, textureCoordinate2);

float ba;
if (2.0 * base.b < base.a) {
ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
} else {
ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
}
vec4 B = vec4(overlaySingleChannel(Cb.r, Cs.r),overlaySingleChannel(Cb.g, Cs.g),overlaySingleChannel(Cb.b,Cs.b),Cs.a);

gl_FragColor = vec4(ra, ga, ba, 1.0);
gl_FragColor = blendBaseAlpha(Cb, Cs, B);
}
);
);
#endif

@implementation GPUImageOverlayBlendFilter

- (id)init;
{
if (!(self = [super initWithFragmentShaderFromString:kGPUImageOverlayBlendFragmentShaderString]))
{
return nil;
}

return self;
if (!(self = [super initWithFragmentShaderFromString:kGPUImageOverlayBlendFragmentShaderString]))
{
return nil;
}
return self;
}

@end
Expand Down
Loading