From ddb3a3327c5cf8db01a49f683f3357661a58c5d5 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Tue, 17 Dec 2024 19:08:31 -0500 Subject: [PATCH 1/5] Use un-multiplied alpha in shader hooks --- src/webgl/shaders/phong.frag | 15 ++--- test/unit/visual/cases/webgl.js | 54 ++++++++++++++++++ .../000.png | Bin 0 -> 837 bytes .../metadata.json | 3 + .../000.png | Bin 0 -> 837 bytes .../metadata.json | 3 + .../000.png | Bin 0 -> 837 bytes .../metadata.json | 3 + .../000.png | Bin 0 -> 837 bytes .../metadata.json | 3 + .../000.png | Bin 0 -> 837 bytes .../metadata.json | 3 + 12 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/metadata.json diff --git a/src/webgl/shaders/phong.frag b/src/webgl/shaders/phong.frag index e141f62f1f..74c5206d95 100644 --- a/src/webgl/shaders/phong.frag +++ b/src/webgl/shaders/phong.frag @@ -47,13 +47,13 @@ void main(void) { inputs.texCoord = vTexCoord; inputs.ambientLight = vAmbientColor; inputs.color = isTexture - // Textures come in with premultiplied alpha. To apply tint and still have - // premultiplied alpha output, we need to multiply the RGB channels by the - // tint RGB, and all channels by the tint alpha. - ? TEXTURE(uSampler, vTexCoord) * vec4(uTint.rgb/255., 1.) * (uTint.a/255.) - // Colors come in with unmultiplied alpha, so we need to multiply the RGB - // channels by alpha to convert it to premultiplied alpha. - : vec4(vColor.rgb * vColor.a, vColor.a); + ? TEXTURE(uSampler, vTexCoord) * uTint/255. + : vColor; + if (isTexture) { + // Textures come in with premultiplied alpha. Temporarily unpremultiply it + // so hooks users don't have to think about premultiplied alpha. + inputs.color.rgb /= inputs.color.a; + } inputs.shininess = uShininess; inputs.metalness = uMetallic; inputs.ambientMaterial = uHasSetAmbient ? uAmbientMatColor.rgb : inputs.color.rgb; @@ -79,5 +79,6 @@ void main(void) { c.specular = specular; c.emissive = inputs.emissiveMaterial; OUT_COLOR = HOOK_getFinalColor(HOOK_combineColors(c)); + OUT_COLOR.rgb *= OUT_COLOR.a; // Premultiply alpha before rendering HOOK_afterFragment(); } diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index fe676a0e8c..de0c234a2c 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -345,4 +345,58 @@ visualSuite('WebGL', function() { screenshot(); }) }) + + visualSuite('Opacity', function() { + visualTest('Basic colors have opacity applied correctly', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + p5.background(255); + p5.fill(255, 0, 0, 100); + p5.circle(0, 0, 50); + screenshot(); + }); + + visualTest('Colors have opacity applied correctly when lights are used', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + p5.background(255); + p5.ambientLight(255); + p5.fill(255, 0, 0, 100); + p5.circle(0, 0, 50); + screenshot(); + }); + + visualTest('Colors in shader hooks have opacity applied correctly', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const myShader = p5.baseMaterialShader().modify({ + 'Inputs getPixelInputs': `(Inputs inputs) { + inputs.color = vec4(1., 0., 0., 100./255.); + return inputs; + }` + }) + p5.background(255); + p5.shader(myShader); + p5.circle(0, 0, 50); + screenshot(); + }); + + visualTest('Colors in textures have opacity applied correctly', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const tex = p5.createFramebuffer(); + tex.draw(() => p5.background(255, 0, 0, 100)); + p5.background(255); + p5.texture(tex); + p5.circle(0, 0, 50); + screenshot(); + }); + + visualTest('Colors in tinted textures have opacity applied correctly', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const tex = p5.createFramebuffer(); + tex.draw(() => p5.background(255, 0, 0, 255)); + p5.background(255); + p5.texture(tex); + p5.tint(255, 100); + p5.circle(0, 0, 50); + screenshot(); + }); + }); }); diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/000.png b/test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/000.png new file mode 100644 index 0000000000000000000000000000000000000000..b885704e16fabfbff084cdc2031e9ddf253c69bb GIT binary patch literal 837 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 z Date: Tue, 17 Dec 2024 20:10:20 -0500 Subject: [PATCH 2/5] Start to update vertex hooks --- src/webgl/material.js | 51 +++++++++++------------------------ src/webgl/p5.RendererGL.js | 9 +++---- src/webgl/p5.Shader.js | 5 ++-- src/webgl/shaders/phong.vert | 52 +++++++++++++++++++++++++++++------- 4 files changed, 63 insertions(+), 54 deletions(-) diff --git a/src/webgl/material.js b/src/webgl/material.js index d63b9a6b69..0a466a23c3 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -1195,56 +1195,34 @@ function material(p5, fn){ * * * - * `vec3 getLocalPosition` - * - * - * - * Update the position of vertices before transforms are applied. It takes in `vec3 position` and must return a modified version. - * - * - * - * - * `vec3 getWorldPosition` + * `Vertex getObjectInputs` * * * - * Update the position of vertices after transforms are applied. It takes in `vec3 position` and pust return a modified version. - * - * - * - * - * `vec3 getLocalNormal` - * - * - * - * Update the normal before transforms are applied. It takes in `vec3 normal` and must return a modified version. - * - * - * - * - * `vec3 getWorldNormal` - * - * - * - * Update the normal after transforms are applied. It takes in `vec3 normal` and must return a modified version. + * Update the vertex data of the model being drawn before any positioning has been applied. It takes in a `Vertex` struct, which includes: + * - `vec3 position`, the position of the vertex + * - `vec3 normal`, the direction facing out of the surface + * - `vec2 uv`, the texture coordinates associeted with the vertex + * - `vec4 color`, the per-vertex color + * The struct can be modified and returned. * * * * - * `vec2 getUV` + * `Vertex getWorldInputs` * * * - * Update the texture coordinates. It takes in `vec2 uv` and must return a modified version. + * Update the vertex data of the model being drawn after transformations such as `translate()` and `scale()` have been applied, but before the camera has been applied. It takes in a `Vertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. * * * * - * `vec4 getVertexColor` + * `Vertex getCameraInputs` * * * - * Update the color of each vertex. It takes in a `vec4 color` and must return a modified version. + * Update the vertex data of the model being drawn as they appear relative to the camera. It takes in a `Vertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. * * * @@ -1342,9 +1320,10 @@ function material(p5, fn){ * uniforms: { * 'float time': () => millis() * }, - * 'vec3 getWorldPosition': `(vec3 pos) { - * pos.y += 20.0 * sin(time * 0.001 + pos.x * 0.05); - * return pos; + * 'Vertex getWorldInputs': `(Vertex inputs) { + * inputs.position.y += + * 20.0 * sin(time * 0.001 + inputs.position.x * 0.05); + * return inputs; * }` * }); * } diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index c2d97f1a01..f0a244ec39 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -1809,12 +1809,9 @@ class RendererGL extends Renderer { { vertex: { "void beforeVertex": "() {}", - "vec3 getLocalPosition": "(vec3 position) { return position; }", - "vec3 getWorldPosition": "(vec3 position) { return position; }", - "vec3 getLocalNormal": "(vec3 normal) { return normal; }", - "vec3 getWorldNormal": "(vec3 normal) { return normal; }", - "vec2 getUV": "(vec2 uv) { return uv; }", - "vec4 getVertexColor": "(vec4 color) { return color; }", + "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }", + "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }", + "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }", "void afterVertex": "() {}", }, fragment: { diff --git a/src/webgl/p5.Shader.js b/src/webgl/p5.Shader.js index 01256011df..b3d6dfaacd 100644 --- a/src/webgl/p5.Shader.js +++ b/src/webgl/p5.Shader.js @@ -365,6 +365,7 @@ class Shader { if (typeof IS_MINIFIED !== 'undefined') { console.error(glError); } else { + throw(glError); p5._friendlyError( `Yikes! An error occurred compiling the vertex shader:${glError}` ); @@ -629,8 +630,8 @@ class Shader { this.init(); } } - - + + /** * Queries the active attributes for this shader and loads * their names and locations into the attributes array. diff --git a/src/webgl/shaders/phong.vert b/src/webgl/shaders/phong.vert index 0576ccd304..589bc8a84b 100644 --- a/src/webgl/shaders/phong.vert +++ b/src/webgl/shaders/phong.vert @@ -8,6 +8,8 @@ IN vec4 aVertexColor; uniform vec3 uAmbientColor[5]; uniform mat4 uModelViewMatrix; +uniform mat4 uModelMatrix; +uniform mat4 uViewMatrix; uniform mat4 uProjectionMatrix; uniform mat3 uNormalMatrix; uniform int uAmbientLightCount; @@ -21,18 +23,48 @@ OUT vec3 vViewPosition; OUT vec3 vAmbientColor; OUT vec4 vColor; +struct Vertex { + vec3 position; + vec3 normal; + vec2 uv; + vec4 color; +}; + void main(void) { HOOK_beforeVertex(); - vec4 viewModelPosition = vec4(HOOK_getWorldPosition( - (uModelViewMatrix * vec4(HOOK_getLocalPosition(aPosition), 1.0)).xyz - ), 1.); - // Pass varyings to fragment shader - vViewPosition = viewModelPosition.xyz; - gl_Position = uProjectionMatrix * viewModelPosition; + Vertex inputs; + inputs.position = aPosition; + inputs.normal = aNormal; + inputs.uv = aTexCoord; + inputs.color = (uUseVertexColor && aVertexColor.x >= 0.0) ? aVertexColor : uMaterialColor; +#ifdef AUGMENTED_HOOK_getLocalInputs + inputs = HOOK_getObjectInputs(inputs); +#endif + +#ifdef AUGMENTED_HOOK_getWorldInputs + inputs.position = (uModelMatrix * vec4(inputs.position, 1.)).xyz; + inputs = HOOK_getWorldInputs(inputs); +#endif - vNormal = HOOK_getWorldNormal(uNormalMatrix * HOOK_getLocalNormal(aNormal)); - vTexCoord = HOOK_getUV(aTexCoord); +#ifdef AUGMENTED_HOOK_getObjectInputs + // Already multiplied by the object matrix, just apply view + inputs.position = (uViewMatrix * vec4(inputs.position, 1.)).xyz; +#else + // Apply both at once + inputs.position = (uModelViewMatrix * vec4(inputs.position, 1.)).xyz; +#endif + // TODO: do the same as above here? + inputs.normal = uNormalMatrix * inputs.normal; +#ifdef AUGMENTED_HOOK_getCameraInputs + inputs = HOOK_getWorldInputs(inputs); +#endif + + // Pass varyings to fragment shader + vViewPosition = inputs.position; + vTexCoord = inputs.uv; + vNormal = inputs.normal; + vColor = inputs.color; // TODO: this should be a uniform vAmbientColor = vec3(0.0); @@ -41,7 +73,7 @@ void main(void) { vAmbientColor += uAmbientColor[i]; } } - - vColor = HOOK_getVertexColor(((uUseVertexColor && aVertexColor.x >= 0.0) ? aVertexColor : uMaterialColor)); + + gl_Position = uProjectionMatrix * vec4(inputs.position, 1.); HOOK_afterVertex(); } From 631a14d157b3a066be2e941dc1248f8ab858e829 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Wed, 18 Dec 2024 11:36:24 -0500 Subject: [PATCH 3/5] Allow hooks to use split model and view matrices --- src/accessibility/outputs.js | 2 +- src/webgl/GeometryBuilder.js | 4 +- src/webgl/material.js | 263 +++++++++++++----- src/webgl/p5.RendererGL.js | 72 +++-- src/webgl/p5.Shader.js | 18 +- src/webgl/shaders/line.vert | 86 ++++-- src/webgl/shaders/normal.vert | 59 +++- src/webgl/shaders/phong.vert | 24 +- test/unit/visual/cases/webgl.js | 93 +++++++ .../baseColorShader/Camera space/000.png | Bin 0 -> 428 bytes .../Camera space/metadata.json | 3 + .../Combined vs split matrices/000.png | Bin 0 -> 295 bytes .../Combined vs split matrices/001.png | Bin 0 -> 295 bytes .../Combined vs split matrices/002.png | Bin 0 -> 295 bytes .../Combined vs split matrices/metadata.json | 3 + .../baseColorShader/Object space/000.png | Bin 0 -> 469 bytes .../Object space/metadata.json | 3 + .../baseColorShader/World space/000.png | Bin 0 -> 508 bytes .../baseColorShader/World space/metadata.json | 3 + .../baseMaterialShader/Camera space/000.png | Bin 0 -> 917 bytes .../Camera space/metadata.json | 3 + .../Combined vs split matrices/000.png | Bin 0 -> 312 bytes .../Combined vs split matrices/001.png | Bin 0 -> 312 bytes .../Combined vs split matrices/002.png | Bin 0 -> 312 bytes .../Combined vs split matrices/metadata.json | 3 + .../baseMaterialShader/Object space/000.png | Bin 0 -> 1029 bytes .../Object space/metadata.json | 3 + .../baseMaterialShader/World space/000.png | Bin 0 -> 1153 bytes .../World space/metadata.json | 3 + .../baseNormalShader/Camera space/000.png | Bin 0 -> 2208 bytes .../Camera space/metadata.json | 3 + .../Combined vs split matrices/000.png | Bin 0 -> 340 bytes .../Combined vs split matrices/001.png | Bin 0 -> 340 bytes .../Combined vs split matrices/002.png | Bin 0 -> 340 bytes .../Combined vs split matrices/metadata.json | 3 + .../baseNormalShader/Object space/000.png | Bin 0 -> 2672 bytes .../Object space/metadata.json | 3 + .../baseNormalShader/World space/000.png | Bin 0 -> 2239 bytes .../World space/metadata.json | 3 + 39 files changed, 503 insertions(+), 154 deletions(-) create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Camera space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Camera space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/001.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/002.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/World space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/World space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Camera space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Camera space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/001.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/002.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/World space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/World space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Camera space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Camera space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/001.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/002.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Object space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Object space/metadata.json create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/World space/000.png create mode 100644 test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/World space/metadata.json diff --git a/src/accessibility/outputs.js b/src/accessibility/outputs.js index 8d1f399969..97b38712f4 100644 --- a/src/accessibility/outputs.js +++ b/src/accessibility/outputs.js @@ -543,7 +543,7 @@ function outputs(p5, fn){ fn._getPos = function (x, y) { const untransformedPosition = new DOMPointReadOnly(x, y); const currentTransform = this._renderer.isP3D ? - new DOMMatrix(this._renderer.states.uMVMatrix.mat4) : + new DOMMatrix(this._renderer.calculateCombinedMatrix()) : this.drawingContext.getTransform(); const { x: transformedX, y: transformedY } = untransformedPosition .matrixTransform(currentTransform); diff --git a/src/webgl/GeometryBuilder.js b/src/webgl/GeometryBuilder.js index 9d5783dbf9..5cb4862168 100644 --- a/src/webgl/GeometryBuilder.js +++ b/src/webgl/GeometryBuilder.js @@ -37,7 +37,7 @@ class GeometryBuilder { if (!this.hasTransform) return normals; return normals.map( - v => this.renderer.states.uNMatrix.multiplyVec(v) // this is a vec3 + v => this.renderer.scratchMat3.multiplyVec(v) // this is a vec3 ); } @@ -51,7 +51,7 @@ class GeometryBuilder { .every((v, i) => v === this.identityMatrix.mat4[i]); if (this.hasTransform) { - this.renderer.states.uNMatrix.inverseTranspose4x4(this.renderer.states.uModelMatrix); + this.renderer.scratchMat3.inverseTranspose4x4(this.renderer.states.uModelMatrix); } let startIdx = this.geometry.vertices.length; diff --git a/src/webgl/material.js b/src/webgl/material.js index 0a466a23c3..630ccaa1e5 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -1471,19 +1471,86 @@ function material(p5, fn){ * You can call `baseNormalShader().modify()` * and change any of the following hooks: * - * Hook | Description - * -----|------------ - * `void beforeVertex` | Called at the start of the vertex shader. - * `vec3 getLocalPosition` | Update the position of vertices before transforms are applied. It takes in `vec3 position` and must return a modified version. - * `vec3 getWorldPosition` | Update the position of vertices after transforms are applied. It takes in `vec3 position` and pust return a modified version. - * `vec3 getLocalNormal` | Update the normal before transforms are applied. It takes in `vec3 normal` and must return a modified version. - * `vec3 getWorldNormal` | Update the normal after transforms are applied. It takes in `vec3 normal` and must return a modified version. - * `vec2 getUV` | Update the texture coordinates. It takes in `vec2 uv` and must return a modified version. - * `vec4 getVertexColor` | Update the color of each vertex. It takes in a `vec4 color` and must return a modified version. - * `void afterVertex` | Called at the end of the vertex shader. - * `void beforeFragment` | Called at the start of the fragment shader. - * `vec4 getFinalColor` | Update the final color after mixing. It takes in a `vec4 color` and must return a modified version. - * `void afterFragment` | Called at the end of the fragment shader. + * + * + * + * + * + * + * + * + * + * + *
HookDescription
+ * + * `void beforeVertex` + * + * + * + * Called at the start of the vertex shader. + * + *
+ * + * `Vertex getObjectInputs` + * + * + * + * Update the vertex data of the model being drawn before any positioning has been applied. It takes in a `Vertex` struct, which includes: + * - `vec3 position`, the position of the vertex + * - `vec3 normal`, the direction facing out of the surface + * - `vec2 uv`, the texture coordinates associeted with the vertex + * - `vec4 color`, the per-vertex color + * The struct can be modified and returned. + * + *
+ * + * `Vertex getWorldInputs` + * + * + * + * Update the vertex data of the model being drawn after transformations such as `translate()` and `scale()` have been applied, but before the camera has been applied. It takes in a `Vertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. + * + *
+ * + * `Vertex getCameraInputs` + * + * + * + * Update the vertex data of the model being drawn as they appear relative to the camera. It takes in a `Vertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. + * + *
+ * + * `void afterVertex` + * + * + * + * Called at the end of the vertex shader. + * + *
+ * + * `void beforeFragment` + * + * + * + * Called at the start of the fragment shader. + * + *
+ * + * `vec4 getFinalColor` + * + * + * + * Update the final color after mixing. It takes in a `vec4 color` and must return a modified version. + * + *
+ * + * `void afterFragment` + * + * + * + * Called at the end of the fragment shader. + * + *
* * Most of the time, you will need to write your hooks in GLSL ES version 300. If you * are using WebGL 1 instead of 2, write your hooks in GLSL ES 100 instead. @@ -1506,9 +1573,10 @@ function material(p5, fn){ * uniforms: { * 'float time': () => millis() * }, - * 'vec3 getWorldPosition': `(vec3 pos) { - * pos.y += 20. * sin(time * 0.001 + pos.x * 0.05); - * return pos; + * 'Vertex getWorldInputs': `(Vertex inputs) { + * inputs.position.y += + * 20. * sin(time * 0.001 + inputs.position.x * 0.05); + * return inputs; * }` * }); * } @@ -1530,7 +1598,10 @@ function material(p5, fn){ * function setup() { * createCanvas(200, 200, WEBGL); * myShader = baseNormalShader().modify({ - * 'vec3 getWorldNormal': '(vec3 normal) { return abs(normal); }', + * 'Vertex getCameraInputs': `(Vertex inputs) { + * inputs.normal = abs(inputs.normal); + * return inputs; + * }`, * 'vec4 getFinalColor': `(vec4 color) { * // Map the r, g, and b values of the old normal to new colors * // instead of just red, green, and blue: @@ -1566,19 +1637,86 @@ function material(p5, fn){ * You can call `baseColorShader().modify()` * and change any of the following hooks: * - * Hook | Description - * -------|------------- - * `void beforeVertex` | Called at the start of the vertex shader. - * `vec3 getLocalPosition` | Update the position of vertices before transforms are applied. It takes in `vec3 position` and must return a modified version. - * `vec3 getWorldPosition` | Update the position of vertices after transforms are applied. It takes in `vec3 position` and pust return a modified version. - * `vec3 getLocalNormal` | Update the normal before transforms are applied. It takes in `vec3 normal` and must return a modified version. - * `vec3 getWorldNormal` | Update the normal after transforms are applied. It takes in `vec3 normal` and must return a modified version. - * `vec2 getUV` | Update the texture coordinates. It takes in `vec2 uv` and must return a modified version. - * `vec4 getVertexColor` | Update the color of each vertex. It takes in a `vec4 color` and must return a modified version. - * `void afterVertex` | Called at the end of the vertex shader. - * `void beforeFragment` | Called at the start of the fragment shader. - * `vec4 getFinalColor` | Update the final color after mixing. It takes in a `vec4 color` and must return a modified version. - * `void afterFragment` | Called at the end of the fragment shader. + * + * + * + * + * + * + * + * + * + * + *
HookDescription
+ * + * `void beforeVertex` + * + * + * + * Called at the start of the vertex shader. + * + *
+ * + * `Vertex getObjectInputs` + * + * + * + * Update the vertex data of the model being drawn before any positioning has been applied. It takes in a `Vertex` struct, which includes: + * - `vec3 position`, the position of the vertex + * - `vec3 normal`, the direction facing out of the surface + * - `vec2 uv`, the texture coordinates associeted with the vertex + * - `vec4 color`, the per-vertex color + * The struct can be modified and returned. + * + *
+ * + * `Vertex getWorldInputs` + * + * + * + * Update the vertex data of the model being drawn after transformations such as `translate()` and `scale()` have been applied, but before the camera has been applied. It takes in a `Vertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. + * + *
+ * + * `Vertex getCameraInputs` + * + * + * + * Update the vertex data of the model being drawn as they appear relative to the camera. It takes in a `Vertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. + * + *
+ * + * `void afterVertex` + * + * + * + * Called at the end of the vertex shader. + * + *
+ * + * `void beforeFragment` + * + * + * + * Called at the start of the fragment shader. + * + *
+ * + * `vec4 getFinalColor` + * + * + * + * Update the final color after mixing. It takes in a `vec4 color` and must return a modified version. + * + *
+ * + * `void afterFragment` + * + * + * + * Called at the end of the fragment shader. + * + *
* * Most of the time, you will need to write your hooks in GLSL ES version 300. If you * are using WebGL 1 instead of 2, write your hooks in GLSL ES 100 instead. @@ -1601,9 +1739,10 @@ function material(p5, fn){ * uniforms: { * 'float time': () => millis() * }, - * 'vec3 getWorldPosition': `(vec3 pos) { - * pos.y += 20. * sin(time * 0.001 + pos.x * 0.05); - * return pos; + * 'Vertex getWorldInputs': `(Inputs inputs) { + * inputs.position.y += + * 20. * sin(time * 0.001 + inputs.position.x * 0.05); + * return inputs; * }` * }); * } @@ -1642,56 +1781,35 @@ function material(p5, fn){ * * * - * `vec3 getLocalPosition` - * - * - * - * Update the position of vertices before transforms are applied. It takes in `vec3 position` and must return a modified version. - * - * - * - * - * `vec3 getWorldPosition` - * - * - * - * Update the position of vertices after transforms are applied. It takes in `vec3 position` and pust return a modified version. - * - * - * - * - * `float getStrokeWeight` - * - * - * - * Update the stroke weight. It takes in `float weight` and pust return a modified version. - * - * - * - * - * `vec2 getLineCenter` + * `StrokeVertex getObjectInputs` * * * - * Update the center of the line. It takes in `vec2 center` and must return a modified version. + * Update the vertex data of the stroke being drawn before any positioning has been applied. It takes in a `StrokeVertex` struct, which includes: + * - `vec3 position`, the position of the vertex + * - `vec3 tangentIn`, the tangent coming in to the vertex + * - `vec3 tangentOut`, the tangent coming out of the vertex. In straight segments, this will be the same as `tangentIn`. In joins, it will be different. In caps, one of the tangents will be 0. + * - `vec4 color`, the per-vertex color + * - `float weight`, the stroke weight + * The struct can be modified and returned. * * * * - * `vec2 getLinePosition` + * `StrokeVertex getWorldInputs` * * * - * Update the position of each vertex on the edge of the line. It takes in `vec2 position` and must return a modified version. + * Update the vertex data of the model being drawn after transformations such as `translate()` and `scale()` have been applied, but before the camera has been applied. It takes in a `StrokeVertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. * * * * - * `vec4 getVertexColor` + * `StrokeVertex getCameraInputs` * * * - * Update the color of each vertex. It takes in a `vec4 color` and must return a modified version. + * Update the vertex data of the model being drawn as they appear relative to the camera. It takes in a `StrokeVertex` struct like, in the `getObjectInputs` hook above, that can be modified and returned. * * * @@ -1810,20 +1928,15 @@ function material(p5, fn){ * uniforms: { * 'float time': () => millis() * }, - * declarations: 'vec3 myPosition;', - * 'vec3 getWorldPosition': `(vec3 pos) { - * myPosition = pos; - * return pos; - * }`, - * 'float getStrokeWeight': `(float w) { + * 'StrokeVertex getWorldInputs': `(StrokeVertex inputs) { * // Add a somewhat random offset to the weight * // that varies based on position and time * float scale = 0.8 + 0.2*sin(10.0 * sin( * floor(time/250.) + - * myPosition.x*0.01 + - * myPosition.y*0.01 + * inputs.position.x*0.01 + + * inputs.position.y*0.01 * )); - * return w * scale; + * inputs.weight *= scale; * }` * }); * } diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index f0a244ec39..b6b90984af 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -177,10 +177,7 @@ class RendererGL extends Renderer { // Push/pop state this.states.uModelMatrix = new Matrix(4); this.states.uViewMatrix = new Matrix(4); - this.states.uMVMatrix = new Matrix(4); this.states.uPMatrix = new Matrix(4); - this.states.uNMatrix = new Matrix(3); - this.states.curMatrix = new Matrix(3); this.states.curCamera = new Camera(this); @@ -416,6 +413,8 @@ class RendererGL extends Renderer { this._curShader = undefined; this.drawShapeCount = 1; + + this.scratchMat3 = new Matrix(3); } ////////////////////////////////////////////// @@ -1739,11 +1738,11 @@ class RendererGL extends Renderer { if (!this.sphereMapping) { this.sphereMapping = this._pInst.createFilterShader(sphereMapping); } - this.states.uNMatrix.inverseTranspose4x4(this.states.uViewMatrix); - this.states.uNMatrix.invert(this.states.uNMatrix); // uNMMatrix is 3x3 + this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix); + this.scratchMat3.invert(this.scratchMat3); // uNMMatrix is 3x3 this.sphereMapping.setUniform("uFovY", this.states.curCamera.cameraFOV); this.sphereMapping.setUniform("uAspect", this.states.curCamera.aspectRatio); - this.sphereMapping.setUniform("uNewNormalMatrix", this.states.uNMatrix.mat3); + this.sphereMapping.setUniform("uNewNormalMatrix", this.scratchMat3.mat3); this.sphereMapping.setUniform("uSampler", img); return this.sphereMapping; } @@ -1860,12 +1859,9 @@ class RendererGL extends Renderer { { vertex: { "void beforeVertex": "() {}", - "vec3 getLocalPosition": "(vec3 position) { return position; }", - "vec3 getWorldPosition": "(vec3 position) { return position; }", - "vec3 getLocalNormal": "(vec3 normal) { return normal; }", - "vec3 getWorldNormal": "(vec3 normal) { return normal; }", - "vec2 getUV": "(vec2 uv) { return uv; }", - "vec4 getVertexColor": "(vec4 color) { return color; }", + "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }", + "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }", + "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }", "void afterVertex": "() {}", }, fragment: { @@ -1895,12 +1891,9 @@ class RendererGL extends Renderer { { vertex: { "void beforeVertex": "() {}", - "vec3 getLocalPosition": "(vec3 position) { return position; }", - "vec3 getWorldPosition": "(vec3 position) { return position; }", - "vec3 getLocalNormal": "(vec3 normal) { return normal; }", - "vec3 getWorldNormal": "(vec3 normal) { return normal; }", - "vec2 getUV": "(vec2 uv) { return uv; }", - "vec4 getVertexColor": "(vec4 color) { return color; }", + "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }", + "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }", + "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }", "void afterVertex": "() {}", }, fragment: { @@ -1986,12 +1979,9 @@ class RendererGL extends Renderer { { vertex: { "void beforeVertex": "() {}", - "vec3 getLocalPosition": "(vec3 position) { return position; }", - "vec3 getWorldPosition": "(vec3 position) { return position; }", - "float getStrokeWeight": "(float weight) { return weight; }", - "vec2 getLineCenter": "(vec2 center) { return center; }", - "vec2 getLinePosition": "(vec2 position) { return position; }", - "vec4 getVertexColor": "(vec4 color) { return color; }", + "StrokeVertex getObjectInputs": "(StrokeVertex inputs) { return inputs; }", + "StrokeVertex getWorldInputs": "(StrokeVertex inputs) { return inputs; }", + "StrokeVertex getCameraInputs": "(StrokeVertex inputs) { return inputs; }", "void afterVertex": "() {}", }, fragment: { @@ -2188,11 +2178,7 @@ class RendererGL extends Renderer { const modelMatrix = this.states.uModelMatrix; const viewMatrix = this.states.uViewMatrix; const projectionMatrix = this.states.uPMatrix; - const modelViewMatrix = modelMatrix.copy().mult(viewMatrix); - this.states.uMVMatrix = this.calculateCombinedMatrix(); - - const modelViewProjectionMatrix = modelViewMatrix.copy(); - modelViewProjectionMatrix.mult(projectionMatrix); + const modelViewMatrix = this.calculateCombinedMatrix(); shader.setUniform( "uPerspective", @@ -2202,17 +2188,29 @@ class RendererGL extends Renderer { shader.setUniform("uProjectionMatrix", projectionMatrix.mat4); shader.setUniform("uModelMatrix", modelMatrix.mat4); shader.setUniform("uModelViewMatrix", modelViewMatrix.mat4); - shader.setUniform( - "uModelViewProjectionMatrix", - modelViewProjectionMatrix.mat4, - ); + if (shader.uniforms.uModelViewProjectionMatrix) { + const modelViewProjectionMatrix = modelViewMatrix.copy(); + modelViewProjectionMatrix.mult(projectionMatrix); + shader.setUniform( + "uModelViewProjectionMatrix", + modelViewProjectionMatrix.mat4, + ); + } if (shader.uniforms.uNormalMatrix) { - this.states.uNMatrix.inverseTranspose4x4(this.states.uMVMatrix); - shader.setUniform("uNormalMatrix", this.states.uNMatrix.mat3); + this.scratchMat3.inverseTranspose4x4(modelViewMatrix); + shader.setUniform("uNormalMatrix", this.scratchMat3.mat3); + } + if (shader.uniforms.uModelNormalMatrix) { + this.scratchMat3.inverseTranspose4x4(this.states.uModelMatrix); + shader.setUniform("uModelNormalMatrix", this.scratchMat3.mat3); + } + if (shader.uniforms.uCameraNormalMatrix) { + this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix); + shader.setUniform("uCameraNormalMatrix", this.scratchMat3.mat3); } if (shader.uniforms.uCameraRotation) { - this.states.curMatrix.inverseTranspose4x4(this.states.uViewMatrix); - shader.setUniform("uCameraRotation", this.states.curMatrix.mat3); + this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix); + shader.setUniform("uCameraRotation", this.scratchMat3.mat3); } shader.setUniform("uViewport", this._viewport); } diff --git a/src/webgl/p5.Shader.js b/src/webgl/p5.Shader.js index b3d6dfaacd..8d885c7c53 100644 --- a/src/webgl/p5.Shader.js +++ b/src/webgl/p5.Shader.js @@ -54,9 +54,10 @@ class Shader { shaderSrc(src, shaderType) { const main = 'void main'; - const [preMain, postMain] = src.split(main); + let [preMain, postMain] = src.split(main); let hooks = ''; + let defines = ''; for (const key in this.hooks.uniforms) { hooks += `uniform ${key};\n`; } @@ -76,14 +77,22 @@ class Shader { // Add a #define so that if the shader wants to use preprocessor directives to // optimize away the extra function calls in main, it can do so if (this.hooks.modified[shaderType][hookDef]) { - hooks += '#define AUGMENTED_HOOK_' + hookName + '\n'; + defines += '#define AUGMENTED_HOOK_' + hookName + '\n'; } hooks += hookType + ' HOOK_' + hookName + this.hooks[shaderType][hookDef] + '\n'; } - return preMain + hooks + main + postMain; + // Allow shaders to specify the location of hook #define statements. Normally these + // go after function definitions, but one might want to have them defined earlier + // in order to only conditionally make uniforms. + if (preMain.indexOf('#define HOOK_DEFINES') !== -1) { + preMain = preMain.replace('#define HOOK_DEFINES', '\n' + defines + '\n'); + defines = ''; + } + + return preMain + '\n' + defines + hooks + main + postMain; } /** @@ -365,7 +374,7 @@ class Shader { if (typeof IS_MINIFIED !== 'undefined') { console.error(glError); } else { - throw(glError); + throw glError; p5._friendlyError( `Yikes! An error occurred compiling the vertex shader:${glError}` ); @@ -383,6 +392,7 @@ class Shader { if (typeof IS_MINIFIED !== 'undefined') { console.error(glError); } else { + throw glError; p5._friendlyError( `Darn! An error occurred compiling the fragment shader:${glError}` ); diff --git a/src/webgl/shaders/line.vert b/src/webgl/shaders/line.vert index 9609fc38d4..de422ad6b6 100644 --- a/src/webgl/shaders/line.vert +++ b/src/webgl/shaders/line.vert @@ -18,10 +18,18 @@ #define PROCESSING_LINE_SHADER +#define HOOK_DEFINES + precision highp int; precision highp float; +#ifdef AUGMENTED_HOOK_getWorldInputs +uniform mat4 uModelMatrix; +uniform mat4 uViewMatrix; +#else uniform mat4 uModelViewMatrix; +#endif + uniform mat4 uProjectionMatrix; uniform float uStrokeWeight; @@ -33,7 +41,7 @@ uniform vec4 uViewport; uniform int uPerspective; uniform int uStrokeJoin; -IN vec4 aPosition; +IN vec3 aPosition; IN vec3 aTangentIn; IN vec3 aTangentOut; IN float aSide; @@ -66,6 +74,14 @@ vec2 lineIntersection(vec2 aPoint, vec2 aDir, vec2 bPoint, vec2 bDir) { return aPoint + aDir * intersectionDistance; } +struct StrokeVertex { + vec3 position; + vec3 tangentIn; + vec3 tangentOut; + vec4 color; + float weight; +}; + void main() { HOOK_beforeVertex(); @@ -81,12 +97,43 @@ void main() { ) ? 1. : 0.; } - vec4 localPosition = vec4(HOOK_getLocalPosition(aPosition.xyz), 1.); - vec4 posp = vec4(HOOK_getWorldPosition((uModelViewMatrix * localPosition).xyz), 1.); - vec4 posqIn = posp + uModelViewMatrix * vec4(aTangentIn, 0); - vec4 posqOut = posp + uModelViewMatrix * vec4(aTangentOut, 0); - float strokeWeight = HOOK_getStrokeWeight(uStrokeWeight); - vStrokeWeight = strokeWeight; + StrokeVertex inputs; + inputs.position = aPosition.xyz; + inputs.color = uUseLineColor ? aVertexColor : uMaterialColor; + inputs.weight = uStrokeWeight; + inputs.tangentIn = aTangentIn; + inputs.tangentOut = aTangentOut; + +#ifdef AUGMENTED_HOOK_getObjectInputs + inputs = HOOK_getObjectInputs(inputs); +#endif + +#ifdef AUGMENTED_HOOK_getWorldInputs + inputs.position = (uModelMatrix * vec4(inputs.position, 1.)).xyz; + inputs.tangentIn = (uModelMatrix * vec4(aTangentIn, 0.)).xyz; + inputs.tangentOut = (uModelMatrix * vec4(aTangentOut, 0.)).xyz; + inputs = HOOK_getWorldInputs(inputs); +#endif + +#ifdef AUGMENTED_HOOK_getWorldInputs + // Already multiplied by the model matrix, just apply view + inputs.position = (uViewMatrix * vec4(inputs.position, 1.)).xyz; + inputs.tangentIn = (uViewMatrix * vec4(aTangentIn, 0.)).xyz; + inputs.tangentOut = (uViewMatrix * vec4(aTangentOut, 0.)).xyz; +#else + // Apply both at once + inputs.position = (uModelViewMatrix * vec4(inputs.position, 1.)).xyz; + inputs.tangentIn = (uModelViewMatrix * vec4(aTangentIn, 0.)).xyz; + inputs.tangentOut = (uModelViewMatrix * vec4(aTangentOut, 0.)).xyz; +#endif +#ifdef AUGMENTED_HOOK_getCameraInputs + inputs = hook_getCameraInputs(inputs); +#endif + + vec4 posp = vec4(inputs.position, 1.); + vec4 posqIn = vec4(inputs.position + inputs.tangentIn, 1.); + vec4 posqOut = vec4(inputs.position + inputs.tangentOut, 1.); + vStrokeWeight = inputs.weight; float facingCamera = pow( // The word space tangent's z value is 0 if it's facing the camera @@ -130,7 +177,6 @@ void main() { vec4 p = uProjectionMatrix * posp; vec4 qIn = uProjectionMatrix * posqIn; vec4 qOut = uProjectionMatrix * posqOut; - vCenter = HOOK_getLineCenter(p.xy); // formula to convert from clip space (range -1..1) to screen space (range 0..[width or height]) // screen_p = (p.xy/p.w + <1,1>) * 0.5 * uViewport.zw @@ -195,9 +241,9 @@ void main() { // find where the lines intersect to find the elbow of the join vec2 c = (posp.xy/posp.w + vec2(1.,1.)) * 0.5 * uViewport.zw; vec2 intersection = lineIntersection( - c + (side * normalIn * strokeWeight / 2.), + c + (side * normalIn * inputs.weight / 2.), tangentIn, - c + (side * normalOut * strokeWeight / 2.), + c + (side * normalOut * inputs.weight / 2.), tangentOut ); offset = (intersection - c); @@ -207,21 +253,21 @@ void main() { // the magnitude to avoid lines going across the whole screen when this // happens. float mag = length(offset); - float maxMag = 3. * strokeWeight; + float maxMag = 3. * inputs.weight; if (mag > maxMag) { offset *= maxMag / mag; } } else if (sideEnum == 1.) { - offset = side * normalIn * strokeWeight / 2.; + offset = side * normalIn * inputs.weight / 2.; } else if (sideEnum == 3.) { - offset = side * normalOut * strokeWeight / 2.; + offset = side * normalOut * inputs.weight / 2.; } } if (uStrokeJoin == STROKE_JOIN_BEVEL) { vec2 avgNormal = vec2(-vTangent.y, vTangent.x); - vMaxDist = abs(dot(avgNormal, normalIn * strokeWeight / 2.)); + vMaxDist = abs(dot(avgNormal, normalIn * inputs.weight / 2.)); } else { - vMaxDist = strokeWeight / 2.; + vMaxDist = inputs.weight / 2.; } } else { vec2 tangent = aTangentIn == vec3(0.) ? tangentOut : tangentIn; @@ -233,14 +279,16 @@ void main() { // extends out from the line float tangentOffset = abs(aSide) - 1.; offset = (normal * normalOffset + tangent * tangentOffset) * - strokeWeight * 0.5; - vMaxDist = strokeWeight / 2.; + inputs.weight * 0.5; + vMaxDist = inputs.weight / 2.; } - vPosition = HOOK_getLinePosition(vCenter + offset); + + vCenter = p.xy; + vPosition = vCenter + offset; + vColor = inputs.color; gl_Position.xy = p.xy + offset.xy * curPerspScale; gl_Position.zw = p.zw; - vColor = HOOK_getVertexColor(uUseLineColor ? aVertexColor : uMaterialColor); HOOK_afterVertex(); } diff --git a/src/webgl/shaders/normal.vert b/src/webgl/shaders/normal.vert index 63922714b4..9b466b54c6 100644 --- a/src/webgl/shaders/normal.vert +++ b/src/webgl/shaders/normal.vert @@ -3,9 +3,18 @@ IN vec3 aNormal; IN vec2 aTexCoord; IN vec4 aVertexColor; +#define HOOK_DEFINES + +#ifdef AUGMENTED_HOOK_getWorldInputs +uniform mat4 uModelMatrix; +uniform mat4 uViewMatrix; +uniform mat3 uModelNormalMatrix; +uniform mat3 uCameraNormalMatrix; +#else uniform mat4 uModelViewMatrix; -uniform mat4 uProjectionMatrix; uniform mat3 uNormalMatrix; +#endif +uniform mat4 uProjectionMatrix; uniform vec4 uMaterialColor; uniform bool uUseVertexColor; @@ -14,16 +23,50 @@ OUT vec3 vVertexNormal; OUT highp vec2 vVertTexCoord; OUT vec4 vColor; +struct Vertex { + vec3 position; + vec3 normal; + vec2 uv; + vec4 color; +}; + void main(void) { HOOK_beforeVertex(); - vec4 positionVec4 = vec4(HOOK_getWorldPosition( - (uModelViewMatrix * vec4(HOOK_getLocalPosition(aPosition), 1.0)).xyz - ), 1.); - gl_Position = uProjectionMatrix * positionVec4; + Vertex inputs; + inputs.position = aPosition; + inputs.normal = aNormal; + inputs.uv = aTexCoord; + inputs.color = (uUseVertexColor && aVertexColor.x >= 0.0) ? aVertexColor : uMaterialColor; +#ifdef AUGMENTED_HOOK_getObjectInputs + inputs = HOOK_getObjectInputs(inputs); +#endif + +#ifdef AUGMENTED_HOOK_getWorldInputs + inputs.position = (uModelMatrix * vec4(inputs.position, 1.)).xyz; + inputs.normal = uModelNormalMatrix * inputs.normal; + inputs = HOOK_getWorldInputs(inputs); +#endif + +#ifdef AUGMENTED_HOOK_getWorldInputs + // Already multiplied by the model matrix, just apply view + inputs.position = (uViewMatrix * vec4(inputs.position, 1.)).xyz; + inputs.normal = uCameraNormalMatrix * inputs.normal; +#else + // Apply both at once + inputs.position = (uModelViewMatrix * vec4(inputs.position, 1.)).xyz; + inputs.normal = uNormalMatrix * inputs.normal; +#endif +#ifdef AUGMENTED_HOOK_getCameraInputs + inputs = HOOK_getCameraInputs(inputs); +#endif + + // Pass varyings to fragment shader + vVertTexCoord = inputs.uv; + vVertexNormal = normalize(inputs.normal); + vColor = inputs.color; + + gl_Position = uProjectionMatrix * vec4(inputs.position, 1.); - vVertexNormal = HOOK_getWorldNormal(normalize(uNormalMatrix * HOOK_getLocalNormal(aNormal))); - vVertTexCoord = HOOK_getUV(aTexCoord); - vColor = HOOK_getVertexColor((uUseVertexColor && aVertexColor.x >= 0.0) ? aVertexColor : uMaterialColor); HOOK_afterVertex(); } diff --git a/src/webgl/shaders/phong.vert b/src/webgl/shaders/phong.vert index 589bc8a84b..f59c09744a 100644 --- a/src/webgl/shaders/phong.vert +++ b/src/webgl/shaders/phong.vert @@ -1,5 +1,7 @@ precision highp int; +#define HOOK_DEFINES + IN vec3 aPosition; IN vec3 aNormal; IN vec2 aTexCoord; @@ -7,11 +9,16 @@ IN vec4 aVertexColor; uniform vec3 uAmbientColor[5]; -uniform mat4 uModelViewMatrix; +#ifdef AUGMENTED_HOOK_getWorldInputs uniform mat4 uModelMatrix; uniform mat4 uViewMatrix; -uniform mat4 uProjectionMatrix; +uniform mat3 uModelNormalMatrix; +uniform mat3 uCameraNormalMatrix; +#else +uniform mat4 uModelViewMatrix; uniform mat3 uNormalMatrix; +#endif +uniform mat4 uProjectionMatrix; uniform int uAmbientLightCount; uniform bool uUseVertexColor; @@ -38,26 +45,27 @@ void main(void) { inputs.normal = aNormal; inputs.uv = aTexCoord; inputs.color = (uUseVertexColor && aVertexColor.x >= 0.0) ? aVertexColor : uMaterialColor; -#ifdef AUGMENTED_HOOK_getLocalInputs +#ifdef AUGMENTED_HOOK_getObjectInputs inputs = HOOK_getObjectInputs(inputs); #endif #ifdef AUGMENTED_HOOK_getWorldInputs inputs.position = (uModelMatrix * vec4(inputs.position, 1.)).xyz; + inputs.normal = uModelNormalMatrix * inputs.normal; inputs = HOOK_getWorldInputs(inputs); #endif -#ifdef AUGMENTED_HOOK_getObjectInputs - // Already multiplied by the object matrix, just apply view +#ifdef AUGMENTED_HOOK_getWorldInputs + // Already multiplied by the model matrix, just apply view inputs.position = (uViewMatrix * vec4(inputs.position, 1.)).xyz; + inputs.normal = uCameraNormalMatrix * inputs.normal; #else // Apply both at once inputs.position = (uModelViewMatrix * vec4(inputs.position, 1.)).xyz; -#endif - // TODO: do the same as above here? inputs.normal = uNormalMatrix * inputs.normal; +#endif #ifdef AUGMENTED_HOOK_getCameraInputs - inputs = HOOK_getWorldInputs(inputs); + inputs = HOOK_getCameraInputs(inputs); #endif // Pass varyings to fragment shader diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index de0c234a2c..f32f9c2f31 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -399,4 +399,97 @@ visualSuite('WebGL', function() { screenshot(); }); }); + + visualSuite('Hooks coordinate spaces', () => { + for (const base of ['baseMaterialShader', 'baseColorShader', 'baseNormalShader']) { + visualSuite(base, () => { + visualTest('Object space', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const myShader = p5[base]().modify({ + 'Vertex getObjectInputs': `(Vertex inputs) { + inputs.position.x += 0.25; + inputs.normal.x += 0.5 * sin(inputs.position.y * 2.); + inputs.normal = normalize(inputs.normal); + return inputs; + }` + }); + p5.background(255); + p5.lights(); + p5.fill('red'); + p5.noStroke(); + p5.rotateY(p5.PI/2); + p5.camera(-800, 0, 0, 0, 0, 0); + p5.shader(myShader); + p5.sphere(20); + screenshot(); + }); + + visualTest('World space', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const myShader = p5[base]().modify({ + 'Vertex getWorldInputs': `(Vertex inputs) { + inputs.position.x += 10.; + inputs.normal.x += 0.5 * sin(inputs.position.y * 2.); + inputs.normal = normalize(inputs.normal); + return inputs; + }` + }); + p5.background(255); + p5.lights(); + p5.fill('red'); + p5.noStroke(); + p5.rotateY(p5.PI/2); + p5.camera(-800, 0, 0, 0, 0, 0); + p5.shader(myShader); + p5.sphere(20); + screenshot(); + }); + + visualTest('Camera space', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const myShader = p5[base]().modify({ + 'Vertex getCameraInputs': `(Vertex inputs) { + inputs.position.x += 10.; + inputs.normal.x += 0.5 * sin(inputs.position.y * 2.); + inputs.normal = normalize(inputs.normal); + return inputs; + }` + }); + p5.background(255); + p5.lights(); + p5.fill('red'); + p5.noStroke(); + p5.rotateY(p5.PI/2); + p5.camera(-800, 0, 0, 0, 0, 0); + p5.shader(myShader); + p5.sphere(20); + screenshot(); + }); + + visualTest('Combined vs split matrices', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + for (const space of ['Object', 'World', 'Camera']) { + const myShader = p5[base]().modify({ + [`Vertex get${space}Inputs`]: `(Vertex inputs) { + // No-op + return inputs; + }` + }); + p5.background(255); + p5.push(); + p5.lights(); + p5.fill('red'); + p5.noStroke(); + p5.translate(20, -10, 5); + p5.rotate(p5.PI * 0.1); + p5.camera(-800, 0, 0, 0, 0, 0); + p5.shader(myShader); + p5.box(30); + p5.pop(); + screenshot(); + } + }); + }); + } + }); }); diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Camera space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Camera space/000.png new file mode 100644 index 0000000000000000000000000000000000000000..58780753441282fc9cdea88af6abd7bc7223f000 GIT binary patch literal 428 zcmV;d0aN~oP)Px$W=TXrRA@u(nE?)iAPhz2W_mL5WO_4}s@;${!{9?Z!V;r#g1r8=AT`c8H#G1w z9YmRmT@hu1404Jr%VCRcyPn7KW21RKuKjyoELazW22TU$!N-|9p>2(R_ZW}~J=Tel>%;Bs`F$sio5`b W8Y{8|2%dca0000e1$xbN2Y^nP=bq;Yd1V`8*)pODpL3+2SMn>K_O< zi}(e&l!qm(6|0Qk&SsU&oYl}XLD1;Zw*#`0nzFHTivPdAa6(~!nTw;Kh~$kgRRQ;+ zOxtd_SKWJQb37^{`+}3{59KvSO9M{Jo)#*UQTrcqDoP}A0;Aw|-K5z4HPZF%O8t^c z{zz+DRz@e!-=+HEx#a_4Ml0Vo#}>Po35KpQv7DunE(&M490j%aIu(itdTe$IIO4TF rK*p8j(i#DgjhD1V+yxs=w4bo9vk|WnZ|Lg=dX~Y{)z4*}Q$iB}laz0f literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/001.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/001.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9d8c2748bf62b74a9b7c083eb4b5ca3beecdce GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-#^NA%Cx&(BWL^R}4?SHRLo%G- z&Wz=2RuE{JK6$13<=HFM7eCx8>e1$xbN2Y^nP=bq;Yd1V`8*)pODpL3+2SMn>K_O< zi}(e&l!qm(6|0Qk&SsU&oYl}XLD1;Zw*#`0nzFHTivPdAa6(~!nTw;Kh~$kgRRQ;+ zOxtd_SKWJQb37^{`+}3{59KvSO9M{Jo)#*UQTrcqDoP}A0;Aw|-K5z4HPZF%O8t^c z{zz+DRz@e!-=+HEx#a_4Ml0Vo#}>Po35KpQv7DunE(&M490j%aIu(itdTe$IIO4TF rK*p8j(i#DgjhD1V+yxs=w4bo9vk|WnZ|Lg=dX~Y{)z4*}Q$iB}laz0f literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/002.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/002.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9d8c2748bf62b74a9b7c083eb4b5ca3beecdce GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-#^NA%Cx&(BWL^R}4?SHRLo%G- z&Wz=2RuE{JK6$13<=HFM7eCx8>e1$xbN2Y^nP=bq;Yd1V`8*)pODpL3+2SMn>K_O< zi}(e&l!qm(6|0Qk&SsU&oYl}XLD1;Zw*#`0nzFHTivPdAa6(~!nTw;Kh~$kgRRQ;+ zOxtd_SKWJQb37^{`+}3{59KvSO9M{Jo)#*UQTrcqDoP}A0;Aw|-K5z4HPZF%O8t^c z{zz+DRz@e!-=+HEx#a_4Ml0Vo#}>Po35KpQv7DunE(&M490j%aIu(itdTe$IIO4TF rK*p8j(i#DgjhD1V+yxs=w4bo9vk|WnZ|Lg=dX~Y{)z4*}Q$iB}laz0f literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/metadata.json new file mode 100644 index 0000000000..0c316a63ab --- /dev/null +++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/metadata.json @@ -0,0 +1,3 @@ +{ + "numScreenshots": 3 +} \ No newline at end of file diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object space/000.png new file mode 100644 index 0000000000000000000000000000000000000000..96922300999d2aeb4cd24df2aed9341af6cf899a GIT binary patch literal 469 zcmV;`0V@89P)Px$k4Z#9RA@u(nGFttFbsv+&G2O6$?#@1b!qsQcD_NaEHM~_x^HjYx;7CJH33?> zK%A*~DdJ3!<~v0mkIeIYPOoh{aNh6v`}kgkQLuw>=egt3d2Oc{gg*kNeNXwE9)tn9 zPHA@MF}4E++6O@b%=!8rHswBp)PxWykUHBSM?e5!)m3gpP7QBRQmVW_X+~?0p!dnH6MloRR$0*Y6z53l?>uZjY7xIAnf4Q*a_@RL9wP2)SSrF8g2VL&`P`+xdK*AXnK zfZkM1ig*SwBqwsLPx$wn;=mRA@u(nPHNHAPj}^WNlB@_GE2O=FZzrW*yg%7et7T{HjwFKHm#SGK}Lm zrUSI$1PP|%sYozEQhi0<@032DKTcdryIxbeT)tQMU9r^xc|N~WdOY~43CR6k1!^5g z3BVF6pjHBvg8;�HYOvUN5HSzdn8tc>Z=P8jQXPFwPkAfo!3IMhCTFH?r{{Eg@v` z4j2xkg`KoFPuh$F83t0|jk*!vwKfO>d%CG@G}r8735(@HdRl5uX29e@BB((Iz77&e z4FX07iKNEiKmeqyV9Sa`w3Vo$>?`{NQC6>IkRG2S?Ed5ei5Tccz%MHj8ALg=92_Ka zjJOnu4B`s*$RLN=M_eFS>Utlhw6u|uWzjzxBibvIF4`AJ=KP*NSVdCBNZ#!S#K@-D z$%hE45UErfB*F?-B^?Bio(HX}2|B>^uo#iglI@1Gmh^53r$!e*qMrklSX zMDE_=@a0sY4u~uQu-n?)uvESr^^p0eSh*t8Cjmt2i5{p50A<0>WI6-{CF*%;TJA@Q y+F4q&hOVQCHA;j3Pml&L*)_zei0gGV===kJD`|Qc7g!qr0000Px&Pf0{URA@u(S-XzaFc6*aT<8`Fi2{jj_y{VJFX2DTc-+;IUuf!$PE#>nZ%GWuncvXe(ao_ zY&Q10))7B)IK&l*;i3Y?xm#+H+WrINl7y0J#vqeO zGZalN3m~8vWW<^cLx!MbRGy?%)A}MHQ)>h!KZ=|RY0!AmcknF8n1@1;QE5_l&Om)8 zNo6~-S+dwacAb3bd-)|2f+mV73nt0a%$9^tFB!B5 z=Ksay0)sBGhz63YRIPeNK%msS3Fd2Q6@8Ez8jNBfpSvzxx>+loYdMp}j?OT>E|No4 zEl^WyrPv|>bKW$QN871$yxzt1@i(=|5Qx1aamiw5XX)XJ`@X*A&|B^9oE;mOx_Hol z2$V7J2oRfC1f5xU`P_9;WwDQ0r9`PY|C(6@onPho-4w`DV8GGH<-p;dSYMf1OfyX! zN!iJAHSt6ma$I6Rs&R=;FmJq<*Urh$NCL@t5p!3g40+xj>N3rOk>))y(%AVPI4Aex zE0+1x(hC(H|I@%NORmG5a)9@o+k1+u3WT7}y_av!g;7j>h<1ofYoI(Dz*pd?a2%)7 zUk=m4A?9wE*wt_s#+TgO|M04dF!Xk~8;B)=uv5P3Uc@JA$T1D^;q_L>Q!lxCAQqWg rxg%dvZv|2^dNuxCEmC7tOWOPc5A~e;qLr^-00000NkvXXu0mjfR&%bs literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Camera space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Camera space/metadata.json new file mode 100644 index 0000000000..2d4bfe30da --- /dev/null +++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Camera space/metadata.json @@ -0,0 +1,3 @@ +{ + "numScreenshots": 1 +} \ No newline at end of file diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/000.png new file mode 100644 index 0000000000000000000000000000000000000000..1b77843e48980b4dfe5b3f67ba5cc75cdee6dabe GIT binary patch literal 312 zcmV-80muG{P)Px#@<~KNRA@u(ncESAAP_~DN|H{%N>U1@lvJX2l2k&5-$Y>++%a(uzs}v+y$?Zj zDWxQh>+W15vK@8}L2lFZRlqTbh@eQjvjl6E$irG#OUOvk1Z0Gakdd+nj>t&vD6X7y z|L)MpAis7*K@k+`*z{^p-dbA>v5(ZeQ+bZHuvVvqw&16*7S}-~cRYqcp7U&Ep!KpQ ziZDorhG87V$GGop{1J+rW{~`EB^C&zUU(MQr)iS4R;&XSN6wvE^4^9Yyq<*&^PwXFqxXwgqwk0000< KMNUMnLSTZ&KZ&gX literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/001.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/001.png new file mode 100644 index 0000000000000000000000000000000000000000..1b77843e48980b4dfe5b3f67ba5cc75cdee6dabe GIT binary patch literal 312 zcmV-80muG{P)Px#@<~KNRA@u(ncESAAP_~DN|H{%N>U1@lvJX2l2k&5-$Y>++%a(uzs}v+y$?Zj zDWxQh>+W15vK@8}L2lFZRlqTbh@eQjvjl6E$irG#OUOvk1Z0Gakdd+nj>t&vD6X7y z|L)MpAis7*K@k+`*z{^p-dbA>v5(ZeQ+bZHuvVvqw&16*7S}-~cRYqcp7U&Ep!KpQ ziZDorhG87V$GGop{1J+rW{~`EB^C&zUU(MQr)iS4R;&XSN6wvE^4^9Yyq<*&^PwXFqxXwgqwk0000< KMNUMnLSTZ&KZ&gX literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/002.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/002.png new file mode 100644 index 0000000000000000000000000000000000000000..1b77843e48980b4dfe5b3f67ba5cc75cdee6dabe GIT binary patch literal 312 zcmV-80muG{P)Px#@<~KNRA@u(ncESAAP_~DN|H{%N>U1@lvJX2l2k&5-$Y>++%a(uzs}v+y$?Zj zDWxQh>+W15vK@8}L2lFZRlqTbh@eQjvjl6E$irG#OUOvk1Z0Gakdd+nj>t&vD6X7y z|L)MpAis7*K@k+`*z{^p-dbA>v5(ZeQ+bZHuvVvqw&16*7S}-~cRYqcp7U&Ep!KpQ ziZDorhG87V$GGop{1J+rW{~`EB^C&zUU(MQr)iS4R;&XSN6wvE^4^9Yyq<*&^PwXFqxXwgqwk0000< KMNUMnLSTZ&KZ&gX literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/metadata.json new file mode 100644 index 0000000000..0c316a63ab --- /dev/null +++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/metadata.json @@ -0,0 +1,3 @@ +{ + "numScreenshots": 3 +} \ No newline at end of file diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object space/000.png new file mode 100644 index 0000000000000000000000000000000000000000..f6fab1658c28c8ddfe423efaedcb7a3e6676bb3b GIT binary patch literal 1029 zcmV+g1p51lP)Px&zez+vRA@u(nM-ceKoEw@yn{fHgb)$}3QB;8Y!DI%@emz$oGRs;z)5U2u;C7{ zLIR014En9qsHRf3yW5^2LSxBlKgM!>{ny`J?kOgd$%OuctyqGbF%_4JoH0RYkRsp8 zlFkv)@49ZTErhwUCxd(`OZr*Y^sBDv0@2J42<*5n$I{*k zfmTDH-4n2}siHwXmnD5=ri&+mN-HoHK*K;80V;^-0W;kj8K@To05x+H2!i)OG=!%H z?rRuHyThuY>m#LHCx}2G4Fm*%YBg}210rxc%(OLvI;|iYLW8tHXeF#FS`Dp^T;FD< zI|E@{5DNhiY6?s9kq^((&M>?*DAHaY-YmDfRqIisC|?4vW8EYPhw!6WEA96kgk-{Xz0lpuXN2T zUW#eIK$Z2x6q|zdsi9%CS8TcofcA}Ne7SE&GyytDRHXrlRYPDz6$_zL%$r-KUS#m5jPscB`^^X8QyPyz;@EEEJ_F)*=kq9Q8e z?MR=DqKGbG^kiuZOm8B!aJoa1K$vLMbuAr;RVn7&KED@f_+o4jlrhrtUf?!R?_5_7 z`>`NnnBAJ+tI2e5UhtPx=_AKCLZG|S5rW8ipEqRJCf-%5)}kwg@~}Aw-;&jW=$cdj8BD--)k5PA}XK-2o~{D zR#vh;ta3s0N{j{(CC~x_FmEE~4~ZrDQ#Thvojj=Bgvhuij|&zN%fbD;Xi-6H9F;D?RF;eOoGaV+T zl$%VTcsCM2r`fxD8R-UPx(J4r-ARA@u(nQdwmK@f&({Wbgl(ttGZ_}8jVJF1dhQm$bzYOtjK~1V%Zh> zzQ1oj4i5fu^2{+Xv-P5|jh&tGGxs@n!1!^jgHUN;F zG_%uYcFN4oxGU|PSBt{7hC^GOLZ#jyK-4J^OT*}MoNzDHrYkCaF3VmX*BJz#|F*l^ z`JZ7ds&H~h9kMYh@t!Nko3gZ(j_Py*>8gTgJ%n6LPyqRRU^q8Ju=U}v^?JQ9mCAJRlg$JDq^g#+4H#AC;wDZsBIF zK=uX-$JR>!*HN>R48`!c%>&SnKANsSw5V$vK?rOmwSE}?Tt@LBL*-T&T&0GF?|uk& zuOVJ)L8f&nf#XKYlT#4H3+^T*6!0EO_gq&(u+>vjScN@GJy-oKPhRl1q&g2<>$sdap`=>+=xo$s&Px2;IkEaUZGk zH8F!#Dl!YV^2)?U)`7+EK9!~2tjH^K0r8`*dxAJtL!%zMm12bUlzUZzOjC}ea*eNa zl~2@HrHSBZSNX!d&-_~<*xiaasRYR#=zfHiFJ!c@wbVu*fdI+9+9)R14ihAaH6VYnHhvf`N>xDqik2(zI!`)g}ev${6^iqOjGrAh}|MxM1P5WM)^) z?9!x6k>6jKl=gtoPt~wrMJkSX|BF6FVVm;?krC8XKxieX0uhind#jX*Ck;S;o7qN} zV9%w9jFEAE=JIQfcuJ0^U!P0fmZe=^ggg>&LU_1%GeRYd&o>{tBt(8V?P4l+jaZEs zz}H>;R&nBC$ms7AyDZ6~F}HikARiOncyD-|;nfe9dUx0$GET9fQIEk=p!6p`))MRY z+J#jvRT$BDjqaDWei0?mcnyE8C~T)@^KLF6NW8(2diMS4!=CW#hON{_kQ_6Z4|HX9ALvzEL8^$ke#x;N#6O;Pq2)nT zlFM~)ErIBrYBR1VaWU5h9Wc|lm|R5_u(pI$;rilGo7UKK>+wSlw z!Q0bW5&vV8Lp~NyctKIS0RiOV`|f_ z>hGl5rcxvYMLVCUy;2))3gr{^LVlj^GIF!(n_ZDv8QS!Bk3pJ7Xx{ISj3R#kx*x-O T2L_#800000NkvXXu0mjf_-P~4 literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/World space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/World space/metadata.json new file mode 100644 index 0000000000..2d4bfe30da --- /dev/null +++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/World space/metadata.json @@ -0,0 +1,3 @@ +{ + "numScreenshots": 1 +} \ No newline at end of file diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Camera space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Camera space/000.png new file mode 100644 index 0000000000000000000000000000000000000000..1a5e70fea6a4d7bf6524c986523ccb25ca2d4113 GIT binary patch literal 2208 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 N002ovPDHLkV1jU&9T5Nk literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/World space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/World space/metadata.json new file mode 100644 index 0000000000..2d4bfe30da --- /dev/null +++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/World space/metadata.json @@ -0,0 +1,3 @@ +{ + "numScreenshots": 1 +} \ No newline at end of file From 34a116d598859cf759f8bf5d638b7d60a0847517 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Wed, 18 Dec 2024 11:53:31 -0500 Subject: [PATCH 4/5] Fix examples --- src/webgl/material.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webgl/material.js b/src/webgl/material.js index 630ccaa1e5..a6c197421c 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -1739,7 +1739,7 @@ function material(p5, fn){ * uniforms: { * 'float time': () => millis() * }, - * 'Vertex getWorldInputs': `(Inputs inputs) { + * 'Vertex getWorldInputs': `(Vertex inputs) { * inputs.position.y += * 20. * sin(time * 0.001 + inputs.position.x * 0.05); * return inputs; @@ -1937,6 +1937,7 @@ function material(p5, fn){ * inputs.position.y*0.01 * )); * inputs.weight *= scale; + * return inputs; * }` * }); * } From 5f81f8f28e85604070b9c40f5e35eab9f1c12a77 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Wed, 18 Dec 2024 12:01:29 -0500 Subject: [PATCH 5/5] Take out noStroke from stroke example --- src/webgl/material.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/webgl/material.js b/src/webgl/material.js index a6c197421c..3fdb3733cd 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -1945,7 +1945,6 @@ function material(p5, fn){ * function draw() { * background(255); * strokeShader(myShader); - * noStroke(); * myShader.setUniform('time', millis()); * strokeWeight(10); * beginShape();