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 d63b9a6b69..3fdb3733cd 100644
--- a/src/webgl/material.js
+++ b/src/webgl/material.js
@@ -1195,56 +1195,34 @@ function material(p5, fn){
*
*
@@ -1831,20 +1928,16 @@ 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;
+ * return inputs;
* }`
* });
* }
@@ -1852,7 +1945,6 @@ function material(p5, fn){
* function draw() {
* background(255);
* strokeShader(myShader);
- * noStroke();
* myShader.setUniform('time', millis());
* strokeWeight(10);
* beginShape();
diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js
index c2d97f1a01..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;
}
@@ -1809,12 +1808,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: {
@@ -1863,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: {
@@ -1898,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: {
@@ -1989,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: {
@@ -2191,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",
@@ -2205,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 01256011df..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,6 +374,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}`
);
@@ -382,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}`
);
@@ -629,8 +640,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/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.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/src/webgl/shaders/phong.vert b/src/webgl/shaders/phong.vert
index 0576ccd304..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,9 +9,16 @@ IN vec4 aVertexColor;
uniform vec3 uAmbientColor[5];
+#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 int uAmbientLightCount;
uniform bool uUseVertexColor;
@@ -21,18 +30,49 @@ 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_getObjectInputs
+ inputs = HOOK_getObjectInputs(inputs);
+#endif
- vNormal = HOOK_getWorldNormal(uNormalMatrix * HOOK_getLocalNormal(aNormal));
- vTexCoord = HOOK_getUV(aTexCoord);
+#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
+ vViewPosition = inputs.position;
+ vTexCoord = inputs.uv;
+ vNormal = inputs.normal;
+ vColor = inputs.color;
// TODO: this should be a uniform
vAmbientColor = vec3(0.0);
@@ -41,7 +81,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();
}
diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js
index fe676a0e8c..f32f9c2f31 100644
--- a/test/unit/visual/cases/webgl.js
+++ b/test/unit/visual/cases/webgl.js
@@ -345,4 +345,151 @@ 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();
+ });
+ });
+
+ 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 0000000000..5878075344
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Camera space/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Camera space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Camera space/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/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/baseColorShader/Combined vs split matrices/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/000.png
new file mode 100644
index 0000000000..ee9d8c2748
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/000.png differ
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 0000000000..ee9d8c2748
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/001.png differ
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 0000000000..ee9d8c2748
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Combined vs split matrices/002.png differ
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 0000000000..9692230099
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object space/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object space/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/Object 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/baseColorShader/World space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/World space/000.png
new file mode 100644
index 0000000000..075543a498
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/World space/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/World space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/World space/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseColorShader/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/baseMaterialShader/Camera space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Camera space/000.png
new file mode 100644
index 0000000000..41f35381dd
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Camera space/000.png differ
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 0000000000..1b77843e48
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/000.png differ
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 0000000000..1b77843e48
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/001.png differ
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 0000000000..1b77843e48
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Combined vs split matrices/002.png differ
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 0000000000..f6fab1658c
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object space/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object space/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/Object 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/World space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/World space/000.png
new file mode 100644
index 0000000000..f545c7da45
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseMaterialShader/World space/000.png differ
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 0000000000..1a5e70fea6
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Camera space/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Camera space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Camera space/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/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/baseNormalShader/Combined vs split matrices/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/000.png
new file mode 100644
index 0000000000..62eb6320b8
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/001.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/001.png
new file mode 100644
index 0000000000..62eb6320b8
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/001.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/002.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/002.png
new file mode 100644
index 0000000000..62eb6320b8
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/002.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Combined vs split matrices/metadata.json
new file mode 100644
index 0000000000..0c316a63ab
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/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/baseNormalShader/Object space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Object space/000.png
new file mode 100644
index 0000000000..2f428f5f74
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Object space/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Object space/metadata.json b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Object space/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/Object 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/World space/000.png b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/World space/000.png
new file mode 100644
index 0000000000..3e03667ebb
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Hooks coordinate spaces/baseNormalShader/World space/000.png differ
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
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 0000000000..b885704e16
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/metadata.json b/test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Opacity/Basic colors have opacity applied correctly/metadata.json
@@ -0,0 +1,3 @@
+{
+ "numScreenshots": 1
+}
\ No newline at end of file
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/000.png b/test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/000.png
new file mode 100644
index 0000000000..b885704e16
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/metadata.json b/test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Opacity/Colors have opacity applied correctly when lights are used/metadata.json
@@ -0,0 +1,3 @@
+{
+ "numScreenshots": 1
+}
\ No newline at end of file
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/000.png b/test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/000.png
new file mode 100644
index 0000000000..b885704e16
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/metadata.json b/test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Opacity/Colors in shader hooks have opacity applied correctly/metadata.json
@@ -0,0 +1,3 @@
+{
+ "numScreenshots": 1
+}
\ No newline at end of file
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/000.png b/test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/000.png
new file mode 100644
index 0000000000..b885704e16
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/metadata.json b/test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Opacity/Colors in textures have opacity applied correctly/metadata.json
@@ -0,0 +1,3 @@
+{
+ "numScreenshots": 1
+}
\ No newline at end of file
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/000.png b/test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/000.png
new file mode 100644
index 0000000000..b885704e16
Binary files /dev/null and b/test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/000.png differ
diff --git a/test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/metadata.json b/test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/metadata.json
new file mode 100644
index 0000000000..2d4bfe30da
--- /dev/null
+++ b/test/unit/visual/screenshots/WebGL/Opacity/Colors in tinted textures have opacity applied correctly/metadata.json
@@ -0,0 +1,3 @@
+{
+ "numScreenshots": 1
+}
\ No newline at end of file
|