Skip to content

Commit 4232546

Browse files
authored
Merge pull request #5794 from davepagurek/fix/webgl-blend
Fix WebGL blending bugs
2 parents e8eef67 + e937fc2 commit 4232546

File tree

4 files changed

+74
-4
lines changed

4 files changed

+74
-4
lines changed

src/core/rendering.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ p5.prototype.createGraphics = function(w, h, renderer) {
252252
* min(A*factor, B).</li>
253253
* <li><code>LIGHTEST</code> - only the lightest colour succeeds: C =
254254
* max(A*factor, B).</li>
255-
* <li><code>DIFFERENCE</code> - subtract colors from underlying image.</li>
255+
* <li><code>DIFFERENCE</code> - subtract colors from underlying image.
256+
* <em>(2D)</em></li>
256257
* <li><code>EXCLUSION</code> - similar to <code>DIFFERENCE</code>, but less
257258
* extreme.</li>
258259
* <li><code>MULTIPLY</code> - multiply the colors, result will always be

src/webgl/material.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,10 @@ p5.RendererGL.prototype._applyColorBlend = function(colors) {
10541054

10551055
const isTexture = this.drawMode === constants.TEXTURE;
10561056
const doBlend =
1057-
isTexture || colors[colors.length - 1] < 1.0 || this._isErasing;
1057+
isTexture ||
1058+
this.curBlendMode !== constants.BLEND ||
1059+
colors[colors.length - 1] < 1.0 ||
1060+
this._isErasing;
10581061

10591062
if (doBlend !== this._isBlending) {
10601063
if (
@@ -1085,10 +1088,13 @@ p5.RendererGL.prototype._applyBlendMode = function() {
10851088
const gl = this.GL;
10861089
switch (this.curBlendMode) {
10871090
case constants.BLEND:
1088-
case constants.ADD:
10891091
gl.blendEquation(gl.FUNC_ADD);
10901092
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
10911093
break;
1094+
case constants.ADD:
1095+
gl.blendEquation(gl.FUNC_ADD);
1096+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
1097+
break;
10921098
case constants.REMOVE:
10931099
gl.blendEquation(gl.FUNC_REVERSE_SUBTRACT);
10941100
gl.blendFunc(gl.SRC_ALPHA, gl.DST_ALPHA);

src/webgl/p5.RendererGL.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,7 @@ p5.RendererGL.prototype.push = function() {
10321032
properties.drawMode = this.drawMode;
10331033

10341034
properties._currentNormal = this._currentNormal;
1035+
properties.curBlendMode = this.curBlendMode;
10351036

10361037
return style;
10371038
};

test/unit/webgl/p5.RendererGL.js

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ suite('p5.RendererGL', function() {
437437
test('blendModes change pixel colors as expected', function(done) {
438438
myp5.createCanvas(10, 10, myp5.WEBGL);
439439
myp5.noStroke();
440-
assert.deepEqual([133, 69, 191, 255], mixAndReturn(myp5.ADD, 255));
440+
assert.deepEqual([122, 0, 122, 255], mixAndReturn(myp5.ADD, 0));
441441
assert.deepEqual([0, 0, 255, 255], mixAndReturn(myp5.REPLACE, 255));
442442
assert.deepEqual([133, 255, 133, 255], mixAndReturn(myp5.SUBTRACT, 255));
443443
assert.deepEqual([255, 0, 255, 255], mixAndReturn(myp5.SCREEN, 0));
@@ -447,6 +447,68 @@ suite('p5.RendererGL', function() {
447447
assert.deepEqual([0, 0, 0, 255], mixAndReturn(myp5.DARKEST, 255));
448448
done();
449449
});
450+
451+
test('blendModes match 2D mode', function(done) {
452+
myp5.createCanvas(10, 10, myp5.WEBGL);
453+
myp5.setAttributes({ alpha: true });
454+
const ref = myp5.createGraphics(myp5.width, myp5.height);
455+
ref.translate(ref.width / 2, ref.height / 2); // Match WebGL mode
456+
457+
const testBlend = function(target, colorA, colorB, mode) {
458+
target.clear();
459+
target.push();
460+
target.background(colorA);
461+
target.blendMode(mode);
462+
target.noStroke();
463+
target.fill(colorB);
464+
target.rectMode(target.CENTER);
465+
target.rect(0, 0, target.width, target.height);
466+
target.pop();
467+
return target.get(0, 0);
468+
};
469+
470+
const assertSameIn2D = function(colorA, colorB, mode) {
471+
const refColor = testBlend(myp5, colorA, colorB, mode);
472+
const webglColor = testBlend(ref, colorA, colorB, mode);
473+
if (refColor[3] === 0) {
474+
assert.equal(webglColor[3], 0);
475+
} else {
476+
assert.deepEqual(
477+
refColor,
478+
webglColor,
479+
`Blending ${colorA} with ${colorB} using ${mode}`
480+
);
481+
}
482+
};
483+
484+
const red = '#F53';
485+
const blue = '#13F';
486+
assertSameIn2D(red, blue, myp5.BLEND);
487+
assertSameIn2D(red, blue, myp5.ADD);
488+
assertSameIn2D(red, blue, myp5.DARKEST);
489+
assertSameIn2D(red, blue, myp5.LIGHTEST);
490+
assertSameIn2D(red, blue, myp5.EXCLUSION);
491+
assertSameIn2D(red, blue, myp5.MULTIPLY);
492+
assertSameIn2D(red, blue, myp5.SCREEN);
493+
assertSameIn2D(red, blue, myp5.REPLACE);
494+
assertSameIn2D(red, blue, myp5.REMOVE);
495+
done();
496+
});
497+
498+
test('blendModes are included in push/pop', function(done) {
499+
myp5.createCanvas(10, 10, myp5.WEBGL);
500+
myp5.blendMode(myp5.MULTIPLY);
501+
myp5.push();
502+
myp5.blendMode(myp5.ADD);
503+
assert.equal(myp5._renderer.curBlendMode, myp5.ADD, 'Changed to ADD');
504+
myp5.pop();
505+
assert.equal(
506+
myp5._renderer.curBlendMode,
507+
myp5.MULTIPLY,
508+
'Resets to MULTIPLY'
509+
);
510+
done();
511+
});
450512
});
451513

452514
suite('BufferDef', function() {

0 commit comments

Comments
 (0)