Skip to content

Commit de394be

Browse files
authored
Merge pull request #8354 from Piyushrathoree/blur-filter-issue-with-alpha-blending
fixed the issue with alpha blending - fixing blur remaining
2 parents c48237b + 90ecf68 commit de394be

File tree

10 files changed

+87
-18
lines changed

10 files changed

+87
-18
lines changed

src/core/filterShaders.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,20 @@ export function makeFilterShader(renderer, operation, p5) {
102102
const sampleCoord = uv + p5.vec2(sample, sample) / inputs.canvasSize * direction;
103103
const weight = quadWeight(sample, (numSamples - 1.0) * 0.5 * spacing);
104104

105-
avg += weight * p5.getTexture(canvasContent, sampleCoord);
105+
const texSample = p5.getTexture(canvasContent, sampleCoord);
106+
avg += weight * texSample * p5.vec4(
107+
texSample.a, texSample.a, texSample.a, 1
108+
);
106109
total += weight;
107110
}
108111

109-
return avg / total;
112+
const blended = avg / total;
113+
return p5.vec4(
114+
blended.r / blended.a,
115+
blended.g / blended.a,
116+
blended.b / blended.a,
117+
blended.a
118+
);
110119
});
111120
}, { p5 });
112121

src/core/p5.Renderer3D.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,9 @@ export class Renderer3D extends Renderer {
16691669
//// TEXT SUPPORT METHODS
16701670
//////////////////////////////
16711671

1672+
_beforeDrawText() {}
1673+
_afterDrawText() {}
1674+
16721675
textCanvas() {
16731676
if (!this._textCanvas) {
16741677
this._textCanvas = document.createElement('canvas');

src/strands/strands_for.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ export class StrandsFor {
297297
const scopeEndBlock = CFG.createBasicBlock(cfg, BlockType.SCOPE_END);
298298
CFG.addEdge(cfg, updateBlock, scopeEndBlock);
299299

300-
// Loop back to break check
301-
CFG.addEdge(cfg, scopeEndBlock, breakCheckBlock);
300+
// Connect end of for loop to the merge agter the loop
301+
CFG.addEdge(cfg, scopeEndBlock, mergeBlock);
302302

303303
// Break condition exits to merge
304304
CFG.addEdge(cfg, breakCheckBlock, mergeBlock);

src/webgl/p5.RendererGL.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,17 @@ class RendererGL extends Renderer3D {
312312
}
313313
}
314314

315+
//////////////////////////////////////////////
316+
// Text
317+
//////////////////////////////////////////////
318+
319+
_beforeDrawText() {
320+
this.GL.pixelStorei(this.GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
321+
}
322+
_afterDrawText() {
323+
this.GL.pixelStorei(this.GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
324+
}
325+
315326
//////////////////////////////////////////////
316327
// Setting
317328
//////////////////////////////////////////////
@@ -413,9 +424,10 @@ class RendererGL extends Renderer3D {
413424
gl.enable(gl.DEPTH_TEST);
414425
gl.depthFunc(gl.LEQUAL);
415426
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
416-
// Make sure all images are loaded into the canvas non-premultiplied so that
417-
// they can be handled consistently in shaders.
418-
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
427+
// Make sure all images are loaded into the canvas premultiplied so that
428+
// they match the way we render colors. This will make framebuffer textures
429+
// be encoded the same way as textures from everything else.
430+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
419431
this._viewport = this.drawingContext.getParameter(
420432
this.drawingContext.VIEWPORT
421433
);

src/webgl/shaders/light_texture.frag

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ void main(void) {
1414
}
1515
else {
1616
vec4 baseColor = isTexture
17-
// Textures come in with non-premultiplied alpha. Apply tint.
18-
? TEXTURE(uSampler, vVertTexCoord) * (uTint/255.)
19-
// Colors come in with non-premultiplied alpha.
20-
: vColor;
21-
// Convert to premultiplied alpha for consistent output
22-
baseColor.rgb *= baseColor.a;
17+
// Textures come in with premultiplied alpha. To apply tint and still have
18+
// premultiplied alpha output, we need to multiply the RGB channels by the
19+
// tint RGB, and all channels by the tint alpha.
20+
? TEXTURE(uSampler, vVertTexCoord) * vec4(uTint.rgb/255., 1.) * (uTint.a/255.)
21+
// Colors come in with unmultiplied alpha, so we need to multiply the RGB
22+
// channels by alpha to convert it to premultiplied alpha.
23+
: vec4(vColor.rgb * vColor.a, vColor.a);
2324
OUT_COLOR = vec4(baseColor.rgb * vDiffuseColor + vSpecularColor, baseColor.a);
2425
}
2526
}

src/webgl/shaders/phong.frag

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,13 @@ void main(void) {
4747
inputs.texCoord = vTexCoord;
4848
inputs.ambientLight = uAmbientColor;
4949
inputs.color = isTexture
50-
? TEXTURE(uSampler, vTexCoord) * (uTint/255.)
50+
? TEXTURE(uSampler, vTexCoord) * (vec4(uTint.rgb/255., 1.) * uTint.a/255.)
5151
: vColor;
52+
if (isTexture && inputs.color.a > 0.0) {
53+
// Textures come in with premultiplied alpha. Temporarily unpremultiply it
54+
// so hooks users don't have to think about premultiplied alpha.
55+
inputs.color.rgb /= inputs.color.a;
56+
}
5257
inputs.shininess = uShininess;
5358
inputs.metalness = uMetallic;
5459
inputs.ambientMaterial = uHasSetAmbient ? uAmbientMatColor.rgb : inputs.color.rgb;

src/webgl/shaders/webgl2Compatibility.glsl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,9 @@ out vec4 outColor;
2626
#endif
2727

2828
#ifdef FRAGMENT_SHADER
29-
#define getTexture TEXTURE
29+
vec4 getTexture(in sampler2D content, vec2 coord) {
30+
vec4 color = TEXTURE(content, coord);
31+
if (color.a > 0.) color.rgb /= color.a;
32+
return color;
33+
}
3034
#endif

src/webgl/text.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ function text(p5, fn) {
766766

767767
// this will have to do for now...
768768
sh.setUniform('uMaterialColor', curFillColor);
769-
769+
this._beforeDrawText();
770770
this.glyphDataCache = this.glyphDataCache || new Set();
771771

772772
try {
@@ -827,6 +827,7 @@ function text(p5, fn) {
827827
this.states.setValue('strokeColor', doStroke);
828828
this.states.setValue('drawMode', drawMode);
829829

830+
this._afterDrawText();
830831
this.pop();
831832
}
832833
};

src/webgpu/p5.RendererWebGPU.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,12 +1818,12 @@ function rendererWebGPU(p5, fn) {
18181818
}
18191819

18201820
// Find the input parameter name from the main function signature (anchored to start)
1821-
const inputMatch = postMain.match(/^\s*\((\w+):\s*\w+\)/);
1821+
const inputMatch = main.match(/fn main\s*\((\w+):\s*\w+\)/);
18221822
if (inputMatch) {
18231823
const inputVarName = inputMatch[1];
18241824
initStatements = initStatements.replace(/INPUT_VAR/g, inputVarName);
18251825
// Insert after the main function parameter but before any other code (anchored to start)
1826-
postMain = postMain.replace(/^(\s*\(\w+:\s*\w+\)\s*[^{]*\{)/, `$1\n${initStatements}`);
1826+
postMain = initStatements + postMain;
18271827
}
18281828
}
18291829
}

test/unit/webgl/p5.Shader.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,40 @@ suite('p5.Shader', function() {
11281128
const pixelColor = myp5.get(25, 25);
11291129
assert.approximately(pixelColor[0], 127, 5); // 0.5 * 255 ≈ 127
11301130
});
1131+
1132+
test('handle statements after for loop before return', () => {
1133+
myp5.createCanvas(50, 50, myp5.WEBGL);
1134+
1135+
const testShader = myp5.baseMaterialShader().modify(() => {
1136+
myp5.getPixelInputs(inputs => {
1137+
let avg = myp5.vec3(0.0);
1138+
let total = 0.0;
1139+
1140+
// Simulate blur-like accumulation in for loop
1141+
for (let i = 0; i < 3; i++) {
1142+
const sample = myp5.vec3(0.2, 0.1, 0.3);
1143+
const weight = 1.0;
1144+
avg += weight * sample;
1145+
total += weight;
1146+
}
1147+
1148+
const blended = avg / total;
1149+
1150+
inputs.color = [blended.x, blended.y, blended.z, 1.0];
1151+
return inputs;
1152+
});
1153+
}, { myp5 });
1154+
1155+
myp5.noStroke();
1156+
myp5.shader(testShader);
1157+
myp5.plane(myp5.width, myp5.height);
1158+
1159+
// Expected result: (3 * [0.2, 0.1, 0.3]) / 3 = [0.2, 0.1, 0.3]
1160+
const pixelColor = myp5.get(25, 25);
1161+
assert.approximately(pixelColor[0], 51, 5); // 0.2 * 255 ≈ 51
1162+
assert.approximately(pixelColor[1], 25, 5); // 0.1 * 255 ≈ 25
1163+
assert.approximately(pixelColor[2], 77, 5); // 0.3 * 255 ≈ 77
1164+
});
11311165
});
11321166

11331167
suite('passing data between shaders', () => {

0 commit comments

Comments
 (0)