From cc476858b53f58f1627502bf082dfd8a2480bd09 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sat, 21 Dec 2024 16:08:45 -0500 Subject: [PATCH 1/8] Fix MTL color loading when vertices are shared across different faces --- src/webgl/loading.js | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/webgl/loading.js b/src/webgl/loading.js index 28c6099432..4cf2f46b1d 100755 --- a/src/webgl/loading.js +++ b/src/webgl/loading.js @@ -556,7 +556,6 @@ function loading(p5, fn){ // Map from source index → Map of material → destination index const usedVerts = {}; // Track colored vertices let currentMaterial = null; - const coloredVerts = new Set(); //unique vertices with color let hasColoredVertices = false; let hasColorlessVertices = false; for (let line = 0; line < lines.length; ++line) { @@ -622,8 +621,15 @@ function loading(p5, fn){ if (currentMaterial && materials[currentMaterial] && materials[currentMaterial].diffuseColor) { - // Mark this vertex as colored - coloredVerts.add(loadedVerts.v[vertParts[0]]); //since a set would only push unique values + hasColoredVertices = true; + const materialDiffuseColor = + materials[currentMaterial].diffuseColor; + model.vertexColors.push(materialDiffuseColor[0]); + model.vertexColors.push(materialDiffuseColor[1]); + model.vertexColors.push(materialDiffuseColor[2]); + model.vertexColors.push(1); + } else { + hasColorlessVertices = true; } } else { face.push(usedVerts[vertString][currentMaterial]); @@ -636,24 +642,6 @@ function loading(p5, fn){ face[1] !== face[2] ) { model.faces.push(face); - //same material for all vertices in a particular face - if (currentMaterial - && materials[currentMaterial] - && materials[currentMaterial].diffuseColor) { - hasColoredVertices = true; - //flag to track color or no color model - hasColoredVertices = true; - const materialDiffuseColor = - materials[currentMaterial].diffuseColor; - for (let i = 0; i < face.length; i++) { - model.vertexColors.push(materialDiffuseColor[0]); - model.vertexColors.push(materialDiffuseColor[1]); - model.vertexColors.push(materialDiffuseColor[2]); - model.vertexColors.push(1); - } - } else { - hasColorlessVertices = true; - } } } } From 40ed4a6c75a46f3a0fa895ee554a5bd86cfd5af9 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sat, 21 Dec 2024 17:19:49 -0500 Subject: [PATCH 2/8] Fix noErase() breaking in WebGL --- src/webgl/material.js | 4 +-- src/webgl/p5.RendererGL.js | 1 + test/unit/visual/cases/webgl.js | 29 ++++++++++++++++++ .../WebGL/erase()/on a framebuffer/000.png | Bin 0 -> 319 bytes .../erase()/on a framebuffer/metadata.json | 3 ++ .../WebGL/erase()/on the main canvas/000.png | Bin 0 -> 367 bytes .../erase()/on the main canvas/metadata.json | 3 ++ 7 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 test/unit/visual/screenshots/WebGL/erase()/on a framebuffer/000.png create mode 100644 test/unit/visual/screenshots/WebGL/erase()/on a framebuffer/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/erase()/on the main canvas/000.png create mode 100644 test/unit/visual/screenshots/WebGL/erase()/on the main canvas/metadata.json diff --git a/src/webgl/material.js b/src/webgl/material.js index 3fdb3733cd..28d6174a79 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -3683,9 +3683,7 @@ function material(p5, fn){ ); break; } - if (!this._isErasing) { - this._cachedBlendMode = this.states.curBlendMode; - } + this._cachedBlendMode = this.states.curBlendMode; }; RendererGL.prototype.shader = function(s) { diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index b6b90984af..33b72bb464 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -1329,6 +1329,7 @@ class RendererGL extends Renderer { // Restore blend mode this.states.curBlendMode = this.preEraseBlend; this.blendMode(this.preEraseBlend); + console.log(this.preEraseBlend, this._cachedBlendMode) // Ensure that _applyBlendMode() sets preEraseBlend back to the original blend mode this._isErasing = false; this._applyBlendMode(); diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index e503f80981..14d354d500 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -533,4 +533,33 @@ visualSuite('WebGL', function() { screenshot(); }); }); + + visualSuite('erase()', () => { + visualTest('on the main canvas', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + p5.background(0); + p5.fill('red'); + p5.rect(-20, -20, 40, 40); + p5.erase(); + p5.circle(0, 0, 10); + p5.noErase(); + screenshot(); + }); + + visualTest('on a framebuffer', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + p5.background(0); + const fbo = p5.createFramebuffer(); + fbo.begin(); + p5.fill('red'); + p5.rect(-20, -20, 40, 40); + p5.erase(); + p5.circle(0, 0, 10); + p5.noErase(); + fbo.end(); + p5.imageMode(p5.CENTER); + p5.image(fbo, 0, 0); + screenshot(); + }); + }); }); diff --git a/test/unit/visual/screenshots/WebGL/erase()/on a framebuffer/000.png b/test/unit/visual/screenshots/WebGL/erase()/on a framebuffer/000.png new file mode 100644 index 0000000000000000000000000000000000000000..39c1f8259713e95cb48cb17a26918874c16fd7cf GIT binary patch literal 319 zcmV-F0l@x=P)Px#`AI}URA@u(nn4l*Aq)iBm#Z&Vb4V2jD4DPfks8jC(9@u}dX-Y%<$!SsB$-7S zNhYK;jXblhvRY4XZC#K@Qkd6wT`d@a>=Gs;yOQtql@S?Plz_I@qF}?*%1Ai6MK6?* znP4qFA9r0ssYV>2bxWOnKtKcOHLA_dz@!2(s3;5tWWIR?bePvi|CosrZawr%XY z^T;>`B=s3_6ThrPZP@&jGg5D<7L0#DMh>~pO$VtP-+4{h1~PK+ks5&@X)$VLgpo4R zLq?Fa7_~CONEzuNBS>0|S{Y%ajP!tv*u?+#6Se;NfNTdwt&A{IMtU4$Px$DM>^@RA@u(nqdxtFbsv?PNtkpIhlB}xhf=zi*&`6WqD2bH`w0$YD0?wKtu-- zD5NopB+?iVWQm*s$kk#@>1=YXBP-;ZD!`>h6#&L`E;%2Cv;v4kS|PEVgG5NAk^@Yw zO2(QWOCo0LD&0sTJB<|smpJ|7rP`aw6o6rELVR@x@?vf75SuGc}?VQdoYwNi7-6$Ux&~%w Date: Sat, 21 Dec 2024 17:25:02 -0500 Subject: [PATCH 3/8] Remove log --- src/webgl/p5.RendererGL.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index 33b72bb464..b6b90984af 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -1329,7 +1329,6 @@ class RendererGL extends Renderer { // Restore blend mode this.states.curBlendMode = this.preEraseBlend; this.blendMode(this.preEraseBlend); - console.log(this.preEraseBlend, this._cachedBlendMode) // Ensure that _applyBlendMode() sets preEraseBlend back to the original blend mode this._isErasing = false; this._applyBlendMode(); From 6d9c4e9cfa1d04f3b68baa5342a1cd2182700a61 Mon Sep 17 00:00:00 2001 From: rishab Date: Mon, 23 Dec 2024 20:26:01 +0530 Subject: [PATCH 4/8] added loadFilterShader --- src/webgl/material.js | 106 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/webgl/material.js b/src/webgl/material.js index 28d6174a79..76245de4ec 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -513,6 +513,112 @@ function material(p5, fn){ p5._validateParameters('createShader', arguments); return new Shader(this._renderer, vertSrc, fragSrc, options); }; + /** + * Creates and loads a filter shader from an external file. + * + * @method loadFilterShader + * @param {String} fragFilename path to the fragment shader file + * @param {Function} [successCallback] callback to be called once the shader is + * loaded. Will be passed the + * p5.Shader object. + * @param {Function} [failureCallback] callback to be called if there is an error + * loading the shader. Will be passed the + * error event. + * @return {Promise} a promise that resolves with a shader object + * + * @example + *
+ * + * let myShader; + * + * async function setup() { + * myShader = await loadFilterShader('assets/shader.frag'); + * createCanvas(100, 100, WEBGL); + * noStroke(); + * } + * + * function draw() { + * // shader() sets the active shader with our shader + * shader(myShader); + * + * // rect gives us some geometry on the screen + * rect(0, 0, width, height); + * } + * + *
+ * @alt + * A rectangle with a shader applied to it. + */ + p5.prototype.loadFilterShader = async function (fragFilename, successCallback, failureCallback) { + p5._validateParameters('loadFilterShader', arguments); + + const loadedShader = new p5.Shader(); + + try { + // Define the default vertex shaders for different WebGL versions + const defaultVertV1 = ` + uniform mat4 uModelViewMatrix; + uniform mat4 uProjectionMatrix; + + attribute vec3 aPosition; + attribute vec2 aTexCoord; + varying vec2 vTexCoord; + + void main() { + vTexCoord = aTexCoord; + vec4 positionVec4 = vec4(aPosition, 1.0); + gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4; + } + `; + + const defaultVertV2 = `#version 300 es + uniform mat4 uModelViewMatrix; + uniform mat4 uProjectionMatrix; + + in vec3 aPosition; + in vec2 aTexCoord; + out vec2 vTexCoord; + + void main() { + vTexCoord = aTexCoord; + vec4 positionVec4 = vec4(aPosition, 1.0); + gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4; + } + `; + + // Load the fragment shader + loadedShader._fragSrc = await this.loadStrings(fragFilename); + loadedShader._fragSrc = await loadedShader._fragSrc.join('\n'); + + // Determine if we're using WebGL 2 + const isWebGL2 = this._renderer.GL instanceof WebGL2RenderingContext; + + // Set the appropriate vertex shader based on WebGL version + loadedShader._vertSrc = isWebGL2 ? defaultVertV2 : defaultVertV1; + + // Add version directive to fragment shader if it's not present + if (!loadedShader._fragSrc.match(/^\s*#version\s+/)) { + loadedShader._fragSrc = (isWebGL2 ? '#version 300 es\n' : '#version 100\n') + loadedShader._fragSrc; + } + + // For WebGL 2, ensure we have a precision statement in the fragment shader + if (isWebGL2 && !loadedShader._fragSrc.match(/^\s*precision\s+/)) { + loadedShader._fragSrc = 'precision highp float;\n' + loadedShader._fragSrc; + } + + if (successCallback) { + successCallback(loadedShader); + } + + return loadedShader; + } catch (err) { + if (failureCallback) { + failureCallback(err); + } else { + console.error(err); + } + } + }; /** * Creates a p5.Shader object to be used with the From 7de0a53dd57f61d38820607e70095c747123fbad Mon Sep 17 00:00:00 2001 From: rishab Date: Mon, 23 Dec 2024 23:00:33 +0530 Subject: [PATCH 5/8] reducing redundancy --- src/webgl/material.js | 58 +++++-------------------------------------- 1 file changed, 6 insertions(+), 52 deletions(-) diff --git a/src/webgl/material.js b/src/webgl/material.js index 76245de4ec..f553357b9d 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -551,61 +551,15 @@ function material(p5, fn){ */ p5.prototype.loadFilterShader = async function (fragFilename, successCallback, failureCallback) { p5._validateParameters('loadFilterShader', arguments); - - const loadedShader = new p5.Shader(); - try { // Define the default vertex shaders for different WebGL versions - const defaultVertV1 = ` - uniform mat4 uModelViewMatrix; - uniform mat4 uProjectionMatrix; - - attribute vec3 aPosition; - attribute vec2 aTexCoord; - varying vec2 vTexCoord; - - void main() { - vTexCoord = aTexCoord; - vec4 positionVec4 = vec4(aPosition, 1.0); - gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4; - } - `; - - const defaultVertV2 = `#version 300 es - uniform mat4 uModelViewMatrix; - uniform mat4 uProjectionMatrix; - - in vec3 aPosition; - in vec2 aTexCoord; - out vec2 vTexCoord; - - void main() { - vTexCoord = aTexCoord; - vec4 positionVec4 = vec4(aPosition, 1.0); - gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4; - } - `; - - // Load the fragment shader - loadedShader._fragSrc = await this.loadStrings(fragFilename); - loadedShader._fragSrc = await loadedShader._fragSrc.join('\n'); - - // Determine if we're using WebGL 2 - const isWebGL2 = this._renderer.GL instanceof WebGL2RenderingContext; - - // Set the appropriate vertex shader based on WebGL version - loadedShader._vertSrc = isWebGL2 ? defaultVertV2 : defaultVertV1; - - // Add version directive to fragment shader if it's not present - if (!loadedShader._fragSrc.match(/^\s*#version\s+/)) { - loadedShader._fragSrc = (isWebGL2 ? '#version 300 es\n' : '#version 100\n') + loadedShader._fragSrc; - } - - // For WebGL 2, ensure we have a precision statement in the fragment shader - if (isWebGL2 && !loadedShader._fragSrc.match(/^\s*precision\s+/)) { - loadedShader._fragSrc = 'precision highp float;\n' + loadedShader._fragSrc; - } + const fragSrc = await this.loadStrings(fragFilename); + const fragString = await fragSrc.join('\n'); + + // Create the shader using createFilterShader + const loadedShader = this.createFilterShader(fragString); + if (successCallback) { successCallback(loadedShader); } From 2318e5b56ceb01a17a1d29eaa70067ab34159203 Mon Sep 17 00:00:00 2001 From: rishab Date: Tue, 24 Dec 2024 10:59:27 +0530 Subject: [PATCH 6/8] context error fix --- src/webgl/material.js | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/webgl/material.js b/src/webgl/material.js index f553357b9d..a925023cfb 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -549,17 +549,22 @@ function material(p5, fn){ * @alt * A rectangle with a shader applied to it. */ - p5.prototype.loadFilterShader = async function (fragFilename, successCallback, failureCallback) { + fn.loadFilterShader = async function (fragFilename, successCallback, failureCallback) { p5._validateParameters('loadFilterShader', arguments); try { - // Define the default vertex shaders for different WebGL versions - + // Load the fragment shader const fragSrc = await this.loadStrings(fragFilename); const fragString = await fragSrc.join('\n'); - + // Create the shader using createFilterShader - const loadedShader = this.createFilterShader(fragString); - + const loadedShader = this.createFilterShader(fragString, true); + + if (this._renderer.GL) { + loadedShader.ensureCompiledOnContext(this._renderer); + } else { + loadedShader.ensureCompiledOnContext(this); + } + if (successCallback) { successCallback(loadedShader); } @@ -569,7 +574,7 @@ function material(p5, fn){ if (failureCallback) { failureCallback(err); } else { - console.error(err); + console.error(err); } } }; @@ -664,7 +669,7 @@ function material(p5, fn){ * * */ - fn.createFilterShader = function (fragSrc) { + fn.createFilterShader = function (fragSrc, skipContextCheck = false) { p5._validateParameters('createFilterShader', arguments); let defaultVertV1 = ` uniform mat4 uModelViewMatrix; @@ -708,10 +713,12 @@ function material(p5, fn){ `; let vertSrc = fragSrc.includes('#version 300 es') ? defaultVertV2 : defaultVertV1; const shader = new Shader(this._renderer, vertSrc, fragSrc); - if (this._renderer.GL) { - shader.ensureCompiledOnContext(this._renderer); - } else { - shader.ensureCompiledOnContext(this); + if (!skipContextCheck) { + if (this._renderer.GL) { + shader.ensureCompiledOnContext(this._renderer); + } else { + shader.ensureCompiledOnContext(this); + } } return shader; }; From 4421a0c72c5c8756b009571aa8e7b7b2d585b505 Mon Sep 17 00:00:00 2001 From: rishab Date: Tue, 24 Dec 2024 11:02:57 +0530 Subject: [PATCH 7/8] minor change --- src/webgl/material.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/webgl/material.js b/src/webgl/material.js index a925023cfb..8125fd3716 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -558,13 +558,7 @@ function material(p5, fn){ // Create the shader using createFilterShader const loadedShader = this.createFilterShader(fragString, true); - - if (this._renderer.GL) { - loadedShader.ensureCompiledOnContext(this._renderer); - } else { - loadedShader.ensureCompiledOnContext(this); - } - + if (successCallback) { successCallback(loadedShader); } From ba27ffdf14fcf546b5044524147c5967905888de Mon Sep 17 00:00:00 2001 From: Rishab Kumar Jha Date: Tue, 24 Dec 2024 22:27:08 +0530 Subject: [PATCH 8/8] minor change Co-authored-by: Dave Pagurek --- src/webgl/material.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webgl/material.js b/src/webgl/material.js index 8125fd3716..5e455d50ba 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -532,7 +532,7 @@ function material(p5, fn){ * let myShader; * * async function setup() { - * myShader = await loadFilterShader('assets/shader.frag'); + * myShader = await loadFilterShader('assets/shader.frag'); * createCanvas(100, 100, WEBGL); * noStroke(); * }