processing/p5.js

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

Open

Aperta il 20 mag 2026

Vedi su GitHub
 (6 commenti) (0 reazioni) (1 assegnatario)JavaScript (20.784 star) (3178 fork)batch import
Area:WebGLArea:WebGPUHelp Wantedp5.js 2.0+p5.strands

Descrizione

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();
}

Guida contributor