You get a not very friendly GLSL error with dimensions not matching rather than a more directed strands error.
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();
}
Most appropriate sub-area of p5.js?
p5.js version
2.2.3
Web browser and version
All
Operating system
All
Steps to reproduce this
Steps:
sharedVec3()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