Avatar redesign: armoured robot instead of primitive boxes
New primitives (tapered capsule with rounded caps, superellipsoid rounded box) and a full body redesign: three-segment torso (chest plate, dark abdomen, pelvis plate) with glowing core and belt light, helmet with visor/jaw/ears/antenna, shoulder pads, tapered capsule limbs with elbow/knee joints, hand plates with wrist lights, boots with toe lights. Two-tone armour tinted by the palette, emissive details in colorB. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a0edb14d1e
commit
88838792e1
2 files changed
+86
-25
No files matched your search
+46
-23
@@ -1042,41 +1042,64 @@ class InteractiveSim {
|
||||
const hp2 = hipsVis ? W(24) : [neck[0]+shw*0.28, neck[1]-shw*1.25, neck[2]];
|
||||
const pelvis = mid(hp1, hp2);
|
||||
const t = shw;
|
||||
const metal = [0.60, 0.64, 0.72], dark = [0.28, 0.30, 0.36];
|
||||
// two-tone armour + palette-emissive details
|
||||
const ca = e.colorA || [0.05, 0, 0.2];
|
||||
const acc = e.colorB || [0.2, 1, 1];
|
||||
const metal = [0.60+ca[0]*0.18, 0.64+ca[1]*0.18, 0.72+ca[2]*0.18];
|
||||
const dark = [0.15, 0.16, 0.21]; // undersuit / joints
|
||||
const dark2 = [0.30, 0.32, 0.40]; // secondary plates
|
||||
const parts = [];
|
||||
const limb = (a, b, r, col) => parts.push({ a, b, rx: r, rz: r, kind: 'cube', col });
|
||||
const seg = (a, b, r, col, kind) => parts.push({ a, b, rx: r, rz: r, kind: kind || 'caps', col });
|
||||
const ball = (a, r, col) => parts.push({ a, b: null, rx: r, kind: 'sphere', col });
|
||||
// torso + chest light
|
||||
parts.push({ a: neck, b: pelvis, rx: shw*0.52, rz: shw*0.28, kind: 'cube', col: metal });
|
||||
ball(mid(neck, mid(neck, pelvis)), t*0.10, acc);
|
||||
// head with visor + antenna
|
||||
const along = (a, b, k) => [a[0]+(b[0]-a[0])*k, a[1]+(b[1]-a[1])*k, a[2]+(b[2]-a[2])*k];
|
||||
// --- torso in three segments: chest plate, abdomen, pelvis
|
||||
const chestC = along(neck, pelvis, 0.30);
|
||||
parts.push({ a: along(neck, pelvis, 0.02), b: along(neck, pelvis, 0.56),
|
||||
rx: shw*0.55, rz: t*0.32, kind: 'rbox', col: metal });
|
||||
parts.push({ a: along(neck, pelvis, 0.52), b: along(neck, pelvis, 0.80),
|
||||
rx: shw*0.36, rz: t*0.26, kind: 'rbox', col: dark });
|
||||
parts.push({ a: along(neck, pelvis, 0.78), b: along(neck, pelvis, 1.06),
|
||||
rx: shw*0.45, rz: t*0.28, kind: 'rbox', col: dark2 });
|
||||
// glowing chest core + belt light
|
||||
ball([chestC[0], chestC[1], chestC[2]+t*0.28], t*0.09, acc);
|
||||
ball([pelvis[0], pelvis[1]+t*0.02, pelvis[2]+t*0.24], t*0.05, acc);
|
||||
// --- head: neck, helmet, visor, jaw, ears, antenna
|
||||
const nose = L[0].vis > 0.4 ? W(0) : [neck[0], neck[1]+t*0.55, neck[2]];
|
||||
const headC = [nose[0], nose[1] + t*0.05, nose[2]];
|
||||
parts.push({ a: headC, b: null, rx: t*0.34, ry: t*0.38, rz: t*0.30, kind: 'cube', col: metal });
|
||||
parts.push({ a: [headC[0], headC[1]+t*0.02, headC[2]+t*0.30], b: null,
|
||||
rx: t*0.24, ry: t*0.08, rz: t*0.06, kind: 'cube', col: acc });
|
||||
ball([headC[0], headC[1]+t*0.52, headC[2]], t*0.07, acc);
|
||||
// arms (shoulder->elbow->wrist), glowing hands
|
||||
const headC = [nose[0], nose[1] + t*0.06, nose[2]];
|
||||
seg(neck, headC, t*0.10, dark);
|
||||
parts.push({ a: headC, b: null, rx: t*0.30, ry: t*0.30, rz: t*0.28, kind: 'rbox', col: metal });
|
||||
parts.push({ a: [headC[0], headC[1]+t*0.03, headC[2]+t*0.26], b: null,
|
||||
rx: t*0.215, ry: t*0.085, rz: t*0.06, kind: 'rbox', col: acc });
|
||||
parts.push({ a: [headC[0], headC[1]-t*0.20, headC[2]+t*0.18], b: null,
|
||||
rx: t*0.16, ry: t*0.075, rz: t*0.10, kind: 'rbox', col: dark2 });
|
||||
ball([headC[0]-t*0.30, headC[1], headC[2]], t*0.085, dark2);
|
||||
ball([headC[0]+t*0.30, headC[1], headC[2]], t*0.085, dark2);
|
||||
seg([headC[0]+t*0.16, headC[1]+t*0.26, headC[2]], [headC[0]+t*0.22, headC[1]+t*0.52, headC[2]], t*0.025, dark2);
|
||||
ball([headC[0]+t*0.22, headC[1]+t*0.55, headC[2]], t*0.05, acc);
|
||||
// --- arms: shoulder pads, tapered capsules, elbow, hand plate
|
||||
const arm = (s, elI, wrI) => {
|
||||
ball([s[0], s[1]+t*0.04, s[2]], t*0.19, metal); // shoulder pad
|
||||
if (L[elI].vis < 0.4 || L[wrI].vis < 0.4) return;
|
||||
const el = W(elI), wr = W(wrI);
|
||||
limb(s, el, t*0.14, metal);
|
||||
limb(el, wr, t*0.12, metal);
|
||||
ball(el, t*0.15, dark);
|
||||
ball(wr, t*0.17, acc);
|
||||
seg(s, el, t*0.115, dark); // upper arm
|
||||
ball(el, t*0.10, dark2); // elbow
|
||||
seg(el, wr, t*0.095, metal); // forearm
|
||||
const hand = along(el, wr, 1.18);
|
||||
parts.push({ a: wr, b: hand, rx: t*0.095, rz: t*0.05, kind: 'rbox', col: dark2 });
|
||||
ball(along(el, wr, 1.10), t*0.045, acc); // wrist light
|
||||
};
|
||||
arm(sh1, 13, 15); arm(sh2, 14, 16);
|
||||
ball(sh1, t*0.16, dark); ball(sh2, t*0.16, dark);
|
||||
// legs with feet (only when actually visible: seated = bust only)
|
||||
// --- legs: tapered capsules, knee, boot with toe
|
||||
const leg = (h, knI, anI) => {
|
||||
if (!hipsVis || L[knI].vis < 0.4 || L[anI].vis < 0.4) return;
|
||||
const kn = W(knI), an = W(anI);
|
||||
limb(h, kn, t*0.16, metal);
|
||||
limb(kn, an, t*0.13, metal);
|
||||
ball(kn, t*0.16, dark);
|
||||
parts.push({ a: [an[0], an[1]-t*0.06, an[2]+t*0.12], b: null,
|
||||
rx: t*0.14, ry: t*0.08, rz: t*0.22, kind: 'cube', col: dark });
|
||||
seg(h, kn, t*0.15, metal); // thigh
|
||||
ball(kn, t*0.115, dark2); // knee
|
||||
seg(kn, an, t*0.115, dark); // shin
|
||||
parts.push({ a: [an[0], an[1]-t*0.04, an[2]-t*0.02],
|
||||
b: [an[0], an[1]-t*0.09, an[2]+t*0.30], rx: t*0.115, rz: t*0.09,
|
||||
kind: 'rbox', col: metal }); // boot
|
||||
ball([an[0], an[1]-t*0.06, an[2]+t*0.30], t*0.04, acc); // toe light
|
||||
};
|
||||
leg(hp1, 25, 27); leg(hp2, 26, 28);
|
||||
this.modelSim.renderAvatar(timeSec, audio, e, canvas, parts);
|
||||
|
||||
+40
-2
@@ -404,7 +404,45 @@ class ModelSim {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.prims = { cube, sphere: this._primMesh(SP, SN, SI) };
|
||||
// tapered capsule (limb): rounded ends, slightly narrower at the top
|
||||
const CP = [], CN = [], CI = [], SEC = 14, CAP = 5;
|
||||
const prof = [];
|
||||
for (let i = 0; i <= CAP; i++) { const a = Math.PI/2*(1 - i/CAP);
|
||||
prof.push({ r: 0.8*Math.cos(a), y: 0.72 + 0.28*Math.sin(a) }); }
|
||||
prof.push({ r: 1.0, y: -0.72 });
|
||||
for (let i = 1; i <= CAP; i++) { const a = Math.PI/2*i/CAP;
|
||||
prof.push({ r: Math.cos(a), y: -0.72 - 0.28*Math.sin(a) }); }
|
||||
prof.forEach((p, pi) => {
|
||||
for (let j = 0; j <= SEC; j++) {
|
||||
const th = j/SEC*Math.PI*2, x = p.r*Math.cos(th), z = p.r*Math.sin(th);
|
||||
CP.push(x, p.y, z);
|
||||
// capsule-style normal: radiate from the nearest axis point
|
||||
const cy = Math.max(-0.72, Math.min(0.72, p.y));
|
||||
const nl = Math.hypot(x, p.y-cy, z) || 1;
|
||||
CN.push(x/nl, (p.y-cy)/nl, z/nl);
|
||||
if (pi < prof.length-1 && j < SEC) {
|
||||
const a0 = pi*(SEC+1)+j;
|
||||
CI.push(a0, a0+SEC+1, a0+1, a0+1, a0+SEC+1, a0+SEC+2);
|
||||
}
|
||||
}
|
||||
});
|
||||
// rounded box: superellipsoid built from the sphere directions
|
||||
const RP = [], RN = [], RI = [], RST = 10, RSE = 16, EE = 0.42;
|
||||
const se = (c) => Math.sign(c)*Math.pow(Math.abs(c), EE);
|
||||
for (let i = 0; i <= RST; i++) {
|
||||
const ph = i/RST*Math.PI, y = Math.cos(ph), r = Math.sin(ph);
|
||||
for (let j = 0; j <= RSE; j++) {
|
||||
const th = j/RSE*Math.PI*2, x = r*Math.cos(th), z = r*Math.sin(th);
|
||||
RP.push(se(x), se(y), se(z));
|
||||
RN.push(x, y, z); // smooth rounded-cube shading
|
||||
if (i < RST && j < RSE) {
|
||||
const a0 = i*(RSE+1)+j;
|
||||
RI.push(a0, a0+RSE+1, a0+1, a0+1, a0+RSE+1, a0+RSE+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.prims = { cube, sphere: this._primMesh(SP, SN, SI),
|
||||
caps: this._primMesh(CP, CN, CI), rbox: this._primMesh(RP, RN, RI) };
|
||||
}
|
||||
|
||||
// Matrix placing a unit primitive as a limb from a to b (thickness rx/rz)
|
||||
@@ -470,7 +508,7 @@ class ModelSim {
|
||||
gl.uniform1f(this.um.uRim, 0.15 + 0.3*beat);
|
||||
gl.uniform1i(this.um.uHasTex, 0);
|
||||
for (const spec of parts) {
|
||||
const m = this.prims[spec.kind === 'sphere' ? 'sphere' : 'cube'];
|
||||
const m = this.prims[spec.kind] || this.prims.cube;
|
||||
gl.uniformMatrix4fv(this.um.uModel, false, this._partMatrix(spec));
|
||||
gl.uniform3fv(this.um.uBase, spec.col);
|
||||
const bind = (buf, loc, n) => {
|
||||
|
||||
Reference in new issue
Block a user