Skip to content

[p5.js 2.0+ Bug Report]: No FES error reported when assigning to strands shared variables with wrong dimensions #8812

@davepagurek

Description

@davepagurek

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • WebGPU
  • p5.strands
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

p5.js version

2.2.3

Web browser and version

All

Operating system

All

Steps to reproduce this

Steps:

  1. Create a sharedVec3()
  2. Assign to it with a single value

You get a not very friendly GLSL error with dimensions not matching rather than a more directed strands error.

Snippet:

Live: https://editor.p5js.org/davepagurek/sketches/1msmY-46C

let textInput, fontFile, fontSize, extrudeDepth;
let colorA, colorB, trailLength, trailCount;
let tiltAmount, driftAmount, enableAnim, animSpeed;
let iridShader;
let textGeom = null;

async function setup() {
  textInput = createInput('TEST')
  fontFile = (await loadFont('https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuDyYMZhrib2Bg-4.ttf'))
  fontSize = createSlider(20, 200, 72, 1)
  extrudeDepth = createSlider(0, 120, 28, 1)
  colorA = createColorPicker('#ff6ec4')
  colorB = createColorPicker('#7873f5')
  trailLength = createSlider(0.1, 4, 1.8, 0.1)
  trailCount = createSlider(0, 20, 10, 1)
  tiltAmount = createSlider(0, 1, 0.38, 0.01)
  driftAmount = createSlider(0, 120, 28, 1)
  enableAnim = createCheckbox('Animate', true)
  animSpeed = createSlider(25, 400, 100, 1)

  textFont(fontFile);
  textSize(fontSize.value());
  textAlign(CENTER);
  const tw = textWidth(textInput.value()) || 200;
  const th = fontSize.value();
  createCanvas(tw + 80, th * 2.2 + 60, WEBGL);

  const txt = textInput.value() || ' ';
  const ed = extrudeDepth.value();
  try {
    textGeom = fontFile.textToModel(txt, 0, 0, { sampleFactor: 0.3, extrude: ed });
  } catch(e) {
    textGeom = null;
  }

  iridShader = buildMaterialShader(() => {
    let t = uniformFloat(() => millis() * 0.001);
    let trailAlpha = uniformFloat(() => 1.0);
    let caR = uniformFloat(() => red(color(colorA.value())) / 255);
    let caG = uniformFloat(() => green(color(colorA.value())) / 255);
    let caB = uniformFloat(() => blue(color(colorA.value())) / 255);
    let cbR = uniformFloat(() => red(color(colorB.value())) / 255);
    let cbG = uniformFloat(() => green(color(colorB.value())) / 255);
    let cbB = uniformFloat(() => blue(color(colorB.value())) / 255);

    let worldPosX = sharedVec3();
    let worldPosY = sharedVec3();
    let worldPosZ = sharedVec3();
    let myNormalX = sharedVec3();
    let myNormalY = sharedVec3();
    let myNormalZ = sharedVec3();

    worldInputs.begin();
    worldPosX = worldInputs.position.x;
    worldPosY = worldInputs.position.y;
    worldPosZ = worldInputs.position.z;
    myNormalX = worldInputs.normal.x;
    myNormalY = worldInputs.normal.y;
    myNormalZ = worldInputs.normal.z;
    worldInputs.end();

    finalColor.begin();
    let nLen = sqrt(myNormalX * myNormalX + myNormalY * myNormalY + myNormalZ * myNormalZ) + 0.0001;
    let nz = myNormalZ / nLen;
    let fresnel = pow(1.0 - abs(nz), 2.5);
    let phase = worldPosX * 0.012 + worldPosY * 0.008 + worldPosZ * 0.005 + t * 0.6 + fresnel * 0.9;
    let r = 0.5 + 0.5 * cos(6.2831 * (phase + 0.0));
    let g = 0.5 + 0.5 * cos(6.2831 * (phase + 0.333));
    let b = 0.5 + 0.5 * cos(6.2831 * (phase + 0.667));
    let baseR = mix(caR, cbR, fresnel);
    let baseG = mix(caG, cbG, fresnel);
    let baseB = mix(caB, cbB, fresnel);
    let finalR = mix(baseR, r, 0.72 + 0.28 * fresnel);
    let finalG = mix(baseG, g, 0.72 + 0.28 * fresnel);
    let finalB = mix(baseB, b, 0.72 + 0.28 * fresnel);
    let brightness = 0.85 + 0.15 * fresnel;
    finalColor.color = [finalR * brightness, finalG * brightness, finalB * brightness, trailAlpha];
    finalColor.end();
  });
}

function getPose(t) {
  const tilt = tiltAmount.value();
  const drift = driftAmount.value();
  return {
    rx: sin(t * 0.71) * tilt * 0.55,
    ry: sin(t * 0.5) * tilt,
    rz: sin(t * 0.38) * tilt * 0.2,
    px: sin(t * 0.31) * drift,
    py: cos(t * 0.43) * drift * 0.45,
  };
}

function applyPose(pose) {
  translate(pose.px, pose.py, 0);
  rotateX(pose.rx);
  rotateY(pose.ry);
  rotateZ(pose.rz);
}

function draw() {
  clear();
  orbitControl();
  noStroke();
  ambientLight(80, 80, 90);
  directionalLight(255, 240, 255, -0.5, 0.6, -0.8);
  directionalLight(180, 160, 255, 0.7, -0.4, 0.5);

  const spd = animSpeed.value() / 100;
  const T = enableAnim.checked() ? millis() * 0.001 * spd : 0;

  if (!textGeom) return;

  shader(iridShader);
  specularMaterial(255);
  shininess(60);

  const steps = floor(trailCount.value());
  const tLen = trailLength.value();
  const txt = textInput.value() || ' ';
  const ed = extrudeDepth.value();

  if (steps > 1) {
    const N = 80;
    textFont(fontFile);
    textSize(fontSize.value());
    textAlign(CENTER);
    const tw2 = textWidth(txt) * 0.5;
    const th2 = fontSize.value() * 0.25;
    const offsets = [
      [-tw2, -th2],
      [ tw2, -th2],
      [ tw2,  th2],
      [-tw2,  th2],
    ];

    for (let oi = 0; oi < offsets.length; oi++) {
      const ox = offsets[oi][0];
      const oy = offsets[oi][1];
      const pts = [];
      for (let i = 0; i <= N; i++) {
        const frac = i / N;
        const tPast = T - frac * tLen;
        const p = getPose(tPast);
        const cosRY = cos(p.ry), sinRY = sin(p.ry);
        const cosRX = cos(p.rx), sinRX = sin(p.rx);
        const cosRZ = cos(p.rz), sinRZ = sin(p.rz);
        let x = ox * cosRY + sinRY * (oy * sinRX + ed * 0.5 * cosRX);
        let y = oy * cosRX - ed * 0.5 * sinRX;
        let z = -ox * sinRY + cosRY * (oy * sinRX + ed * 0.5 * cosRX);
        const x2 = x * cosRZ - y * sinRZ;
        const y2 = x * sinRZ + y * cosRZ;
        x = x2 + p.px;
        y = y2 + p.py;
        pts.push([x, y, z]);
      }

      beginShape(TRIANGLE_STRIP);
      const halfW = max(2, fontSize.value() * 0.04);
      for (let i = 0; i < pts.length - 1; i++) {
        const frac = i / (pts.length - 2);
        const alpha = (1.0 - frac) * 0.55;
        iridShader.setUniform('trailAlpha', alpha);
        const p0 = pts[i], p1 = pts[i + 1];
        const dx = p1[0] - p0[0], dy = p1[1] - p0[1];
        const len = sqrt(dx*dx + dy*dy) + 0.0001;
        const tx2 = dx/len, ty2 = dy/len;
        const nx2 = -ty2 * halfW, ny2 = tx2 * halfW;
        vertex(p0[0] + nx2, p0[1] + ny2, p0[2]);
        vertex(p0[0] - nx2, p0[1] - ny2, p0[2]);
      }
      endShape();
    }
  }

  for (let i = steps; i >= 1; i--) {
    const frac = i / steps;
    const tPast = T - frac * tLen;
    const alpha = (1.0 - frac) * 0.48 + 0.04;
    const sc = 1.0 - frac * 0.08;
    iridShader.setUniform('trailAlpha', alpha);
    const pose = getPose(tPast);
    const depthZ = -frac * extrudeDepth.value() * 0.6;
    drawTransparent(() => {
      push();
      translate(pose.px, pose.py, depthZ);
      rotateX(pose.rx);
      rotateY(pose.ry);
      rotateZ(pose.rz);
      scale(sc);
      textFont(fontFile);
      textSize(fontSize.value());
      textAlign(CENTER);
      const tw3 = textWidth(txt);
      translate(-tw3 * 0.5, fontSize.value() * 0.3, 0);
      model(textGeom);
      pop();
    });
  }

  iridShader.setUniform('trailAlpha', 1.0);
  const mainPose = getPose(T);
  push();
  applyPose(mainPose);
  textFont(fontFile);
  textSize(fontSize.value());
  textAlign(CENTER);
  const twMain = textWidth(txt);
  translate(-twMain * 0.5, fontSize.value() * 0.3, 0);
  model(textGeom);
  pop();
}

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions