Solved: WebGL P5 sketch: Diagonal Bottom Blades Seem Skewed

Hi All.

I am currently trying to make a P5 WebGL version of a Diagonal Blades P5 program I made previously. The standard version renders properly (with the biggest blades aligned to the left side) but in the WebGL version it seems to skew the blades at the bottom by an amount of the width of the canvas (leaving half of the rendered canvas black). This is not a homework exercise but I love making graphics and learning new things, but P5 WebGL has got me stumped.

I have the standard p5 version here: Diagonal-Blades by Boleeman -p5.js Web Editor

and the WebGL p5 version here:

The WebGL p5 version has 3 files:

sketch.js:

let bladeShader;
let shaderBuffer;
let bladeMultiplier = 3; 
let colorProgress = 0.0; 
let isInverted = false; 

function preload() {
  bladeShader = loadShader('vertex.vert', 'fragment.frag');
}

function setup() {
  createCanvas(1024, 1024);
  pixelDensity(1);
  
  shaderBuffer = createGraphics(1024, 1024, WEBGL);
  shaderBuffer.pixelDensity(1);
  shaderBuffer.noStroke();
}

function draw() {
  background(0);
  
  shaderBuffer.shader(bladeShader);
  
  bladeShader.setUniform('u_resolution', [1024.0, 1024.0]);
  bladeShader.setUniform('u_bladeMultiplier', float(bladeMultiplier));
  bladeShader.setUniform('u_colorProgress', colorProgress);
  bladeShader.setUniform('u_isInverted', isInverted);
  
  // Build a perfect 2-triangle quad spanning from -1 to 1.
  
  // Triangle One
  shaderBuffer.vertex(-1, -1, 0, 0, 0);
  shaderBuffer.vertex( 1, -1, 0, 1, 0);
  shaderBuffer.vertex(-1,  1, 0, 0, 1);
  
  // Triangle Two
  shaderBuffer.vertex( 1, -1, 0, 1, 0);
  shaderBuffer.vertex( 1,  1, 0, 1, 1);
  shaderBuffer.vertex(-1,  1, 0, 0, 1);
  
  shaderBuffer.endShape();
  
  // Render the WebGL layer on our 2D viewport
  image(shaderBuffer, 0, 0);
  
  drawUI();
}

function drawUI() {
  fill(0, 150); 
  noStroke();
  rect(10, 10, 310, 68, 5);
  
  fill(255);
  textSize(12);
  text("Blades Multiplier: " + bladeMultiplier + " (U = More / D = Less)", 20, 28);
  text("Spectrum Shift: " + Math.floor(colorProgress * 100) + "% (▲ / ▼ Keys)", 20, 46);
  text("Blueprint Mode: " + (isInverted ? "ON" : "OFF") + " (I = Toggle) | S = Save", 20, 64);
}

function keyPressed() {
  if (key === 'u' || key === 'U') {
    bladeMultiplier++;
  } else if (key === 'd' || key === 'D') {
    if (bladeMultiplier > 1) { 
      bladeMultiplier--;
    }
  }
  
  if (keyCode === UP_ARROW) {
    colorProgress = (colorProgress + 0.01) % 1.0; 
  } else if (keyCode === DOWN_ARROW) {
    colorProgress = (colorProgress - 0.01 + 1.0) % 1.0;
  }

  if (key === 'i' || key === 'I') {
    isInverted = !isInverted;
  }

  if (key === 's' || key === 'S') {
    image(shaderBuffer, 0, 0); 
    let filename = isInverted ? 'neon_blueprint_blades' : 'radial_diagonal_blades';
    saveCanvas(filename, 'png');
    drawUI(); 
  }
}

vertex.vert:

attribute vec3 aPosition;
attribute vec2 aTexCoord;

varying vec2 vTexCoord;

void main() {
  vTexCoord = aTexCoord;
  gl_Position = vec4(aPosition, 1.0);
}

and fragment.frag:

precision mediump float;

varying vec2 vTexCoord;

uniform vec2 u_resolution;
uniform float u_bladeMultiplier;
uniform float u_colorProgress;
uniform bool u_isInverted;

#define TWO_PI 6.28318530718

float lerp(float start, float stop, float amt) {
  return start + (stop - start) * amt;
}

void main() {
  float x = floor(vTexCoord.x * u_resolution.x);
  float y = floor((1.0 - vTexCoord.y) * u_resolution.y); 

  float angle = u_colorProgress * TWO_PI;
  float cosA = cos(angle);
  float sinA = sin(angle);

  float safeY = (y == 0.0) ? 0.001 : y;

  float r1 = floor(x / safeY);
  float g1 = floor(0.1 * x - y);
  float b1 = floor(mod(u_bladeMultiplier * x, safeY));

  r1 = clamp(r1, 0.0, 255.0);
  g1 = clamp(g1, 0.0, 255.0);
  b1 = clamp(b1, 0.0, 255.0);

  float gBoost = g1 * 6.0;
  if (gBoost > 255.0) gBoost = 255.0;

  // Matrix maps
  float r = sign(r1) * floor(abs(r1 * (0.299 + 0.701 * cosA + 0.168 * sinA) + gBoost * (0.587 - 0.587 * cosA + 0.330 * sinA) + b1 * (0.114 - 0.114 * cosA - 0.497 * sinA)) + 0.5);
  float g = sign(r1) * floor(abs(r1 * (0.299 - 0.299 * cosA - 0.328 * sinA) + gBoost * (0.587 + 0.413 * cosA + 0.035 * sinA) + b1 * (0.114 - 0.114 * cosA + 0.292 * sinA)) + 0.5);
  float b = sign(r1) * floor(abs(r1 * (0.299 - 0.300 * cosA + 1.250 * sinA) + gBoost * (0.587 - 0.588 * cosA - 1.050 * sinA) + b1 * (0.114 + 0.886 * cosA - 0.203 * sinA)) + 0.5);

  // Horizon Masking
  if (x > 400.0 && y < 450.0) {
    float xFactor = (x - 400.0) / 624.0;
    float yFactor = (450.0 - y) / 450.0;
    float horizonMask = pow(xFactor * yFactor, 0.7);
    r = lerp(r, 0.0, horizonMask);
    g = lerp(g, 0.0, horizonMask);
    b = lerp(b, 0.0, horizonMask);
  }

  r = clamp(r, 0.0, 255.0);
  g = clamp(g, 0.0, 255.0);
  b = clamp(b, 0.0, 255.0);

  if (u_isInverted) {
    r = 255.0 - r;
    g = 255.0 - g;
    b = 255.0 - b;
  }

  gl_FragColor = vec4(r / 255.0, g / 255.0, b / 255.0, 1.0);
}

Not sure if anyone can work out why/where the skewing is happening in the WebGL shader version? I have tried many approaches to try to fix the problem but nothing seems to work.

The attached png pictures hopefully explain the problem.
P5 WebGL output render:

Standard P5 render:

Hello @Boleeman!

I had some fun with this and my lobes (frontal, parietal, and occipital) got a workout!

They are not skewed but are coloured black. :upside_down_face:

 float originalR1 = r1;

  // Exact color processing matrix maps
  r1 = 1.0; // I started with this to remove condition r1 = 0.0
  //sign(value) * floor(abs(value) + 0.5)
  float r = sign(r1) * floor(abs(r1 * (0.299 + 0.701 * cosA + 0.168 * sinA) + gBoost * (0.587 - 0.587 * cosA + 0.330 * sinA) + b1 * (0.114 - 0.114 * cosA - 0.497 * sinA)) + 0.5);
  float g = sign(r1) * floor(abs(r1 * (0.299 - 0.299 * cosA - 0.328 * sinA) + gBoost * (0.587 + 0.413 * cosA + 0.035 * sinA) + b1 * (0.114 - 0.114 * cosA + 0.292 * sinA)) + 0.5);
  float b = sign(r1) * floor(abs(r1 * (0.299 - 0.300 * cosA + 1.250 * sinA) + gBoost * (0.587 - 0.588 * cosA - 1.050 * sinA) + b1 * (0.114 + 0.886 * cosA - 0.203 * sinA)) + 0.5);

//This restores the missing blades! I made it yellow to stand out. You can mae it blue.
// r1 == 0.0 → sign(r1) == 0.0

if (originalR1 == 0.0) {
  r = b;
  g = b;
  b = 0.0;
}

The above is just an examination of the code to isolate the issue.

I will leave the rework and solution to you to complete.

:)

Wow. Thanks glv. That fixed it.

My knowledge of WegGL is still on a learning curve.I was convinced that the blades were skewed so I assumed that that was the problem. I also thought that being WebGL, camera/view-ports may be the problem, but in the end I was just going round in circles.
If I may ask, how did you roughly go about finding the problem?

Thank you glv for your help in fixing up the missing blades. Much appreciated. :grinning_face_with_smiling_eyes: