Track B: Opus 5.5 with a GPT-6.1-Terra reviewer
agent (cont.)
+0:37Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && grep -n 'PAINT_VS\|PAINT_COMP\|PAINT_FS\|uKind\|const PAL\|hexp(' review/vroid-02/index.html | head -50; sed -n 180,275p tools/export_glb.py
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && grep -n 'PAINT_VS\|PAINT_COMP\|PAINT_FS\|uKind\|const PAL\|hexp(' review/vroid-02/index.html | head -50; sed -n 180,275p tools/export_glb.pyresult, 124 lines
316:const PAINT_VS = `${SKIN_HEAD} 341:const PAINT_FS = ` 342: uniform int uKind; uniform vec3 uBase; uniform vec3 uKey; uniform sampler2D uMap; uniform int uAlpha; 426: else if (uCastOn == 1 && uKind == 1 && int(uInfo.x * 255.0 + 0.5) == 2 && castShadow() > 0.5) 430: if (uKind == 0 || uKind == 5 || uKind == 6) { // cloth, leather, ground 433: float sh = uKind == 5 ? 0.93 : (cool ? 0.70 : 0.96); 437: float l = lit + (g1 - 0.5) * uGrain - (uKind == 6 ? 0.22 : 0.0); // ground: a flat top sits at the base colour 439: if (uKind == 5) col *= 0.965 + 0.07 * vnoise(vObj * 22.0); // mottled leather 440: } else if (uKind == 1) { // skin: pale, nearly unshaded from the front 446: } else if (uKind == 2) { // hair: four even bands, hard strand highlights 454: } else if (uKind == 3 || uKind == 4) { // steel, gold 457: bool gilt = uKind == 4 || (plate && w > 0.0 && e < w); // an outline plate's gold border 458: col = metal(gilt, gilt && uKind == 3 ? uGold : uBase, n, v, lit, plate ? vPlate.w : -1.0); 465: } else if (uKind == 7) { // iris 468: } else if (uKind == 8) { col = tex.rgb; } 470: if (vPlate.x > 0.5 && vPlate.z > 0.0 && uKind != 3 && uKind != 4) { // a cloth outline piece's gold border, 490: if (uKind <= 6) { 492: col *= uKind == 1 && uSkinRamp == 1 ? mix(vec3(1.0), grade, 0.3) : grade; // a designed skin ramp takes less of it 496: if (uKind != 1) col *= 1.0 + (g2 - 0.5) * 0.06; 500:const PAINT_COMP = ` 568:const paint = compPass(PAINT_COMP, { tColor: { value: null }, tInfo: { value: null }, tDepth: { value: null }, uRes: { value: new THREE.Vector2() }, 804: const u = { uKind: { value: 9 }, uBase: { value: new THREE.Color(0.8, 0.8, 0.8) }, uKey: { value: KEY.clone() }, 816: if (P) { u.uKind.value = KIND[P.kind] ?? 0; if (P.base) u.uBase.value = hex(P.base); if (P.grain != null) u.uGrain.value = P.grain; } 817: else if (Rl.bands) { u.uKind.value = Rl.world ? 6 : 0; u.uBase.value = hex(Rl.bands[Math.min(1, Rl.bands.length - 1)][1]); } 828: if (role === "iris") { u.uKind.value = 7; u.uAlpha.value = 1; } 829: else if (role === "white" || role === "highlight") { u.uKind.value = map ? 8 : 9; if (map) u.uAlpha.value = 1; u.uFlat.value = hex(Rl.color || "#ffffff"); } 830: else if (!P && Rl.mode === "flat") { u.uKind.value = 9; u.uFlat.value = hex(Rl.color); if (map) u.uAlpha.value = role === "line" ? 2 : 1; } 832: const m = new THREE.ShaderMaterial({ uniforms: u, vertexShader: PAINT_VS, fragmentShader: PAINT_FS, side: THREE.DoubleSide, 1323: if (!u || !u.uSkinRamp || u.uKind.value !== 1) continue; CLOTH_HEM_ONLY = {"OUTFIT_skirt"} # border band on the hem row only (its waist has a gold trim) def scene_info(portrait, palette): """Everything the browser's pixel renderer and cloth solver need besides the meshes: palette bands per role, the lights, body colliders, cloth grids and the mouth curve (model space, turned to face +z like the GLB).""" import vroid_portrait as vp from vrm import bone_weight hexp = lambda c: palette[c] bands = lambda tbl: [[thr if thr > -5 else -9, hexp(c)] for thr, c in tbl] roles = {"face": dict(mode="bands", bands=bands(vp.SKIN_BANDS)), "body": dict(mode="bands", bands=bands(vp.SKIN_BANDS), cap=hexp("4")), "shadow": dict(mode="flat", color=hexp("3")), "hair": dict(mode="bands", bands=bands(vp.HAIR_BANDS)), "cloth": dict(mode="bands", bands=bands(vp.CLOTH_BANDS)), "line": dict(mode="flat", color=hexp("o")), "brow": dict(mode="flat", color=hexp("A")), "mouth": dict(mode="flat", color=hexp("1")), "white": dict(mode="flat", color=hexp("w")), "highlight": dict(mode="flat", color=hexp("w")), "iris": dict(mode="iris", colors=[hexp("r"), hexp("s"), hexp("t")], cuts=[0.25, 0.5])} for r, tbl in vp.MATERIALS.items(): roles[r] = dict(mode="bands", bands=bands(tbl), world=r in vp.WORLD_ROLES) names = portrait.v.nodes_by_name() W = portrait.v.node_world(portrait.pose_now) body = [p for p, r in zip(portrait.prims, portrait.roles) if r == "body"][0] caps = [] for a, b in CAPSULES: if a not in names or b not in names: continue A, B = W[names[a]][:3, 3], W[names[b]][:3, 3] wv = bone_weight(body, (a,)) pts = body["pos"][wv > 0.5] if len(pts) < 8: continue ab = B - A t = np.clip(((pts - A) @ ab) / (ab @ ab), 0, 1) d = np.linalg.norm(pts - (A + t[:, None] * ab), axis=1) caps.append(dict(a=(A * FLIP).tolist(), b=(B * FLIP).tolist(), r=float(np.percentile(d, 70) + 0.012), bones=[a, b])) cloth = {} for p in portrait.prims: if p["material"] in CLOTH and "grid" in p: trims, band, collide = CLOTH[p["material"]] cloth[p["material"]] = dict(u=int(p["grid"][0]), v=int(p["grid"][1]), trims=list(trims), band=band, collide=list(collide) if collide else None, closed=bool(p.get("closed")), edges="hem" if p["material"] in CLOTH_HEM_ONLY else "all") curve = None if getattr(portrait, "mouth_curve", None) is not None: face = [p for p, r in zip(portrait.prims, portrait.roles) if r == "face"] allp = np.concatenate([p["pos"] for p in face]) alln = np.concatenate([p["nrm"] for p in face]) from scipy.spatial import cKDTree _, i = cKDTree(allp).query(portrait.mouth_curve) curve = ((portrait.mouth_curve + alln[i] * 0.0015) * FLIP).tolist() marks = None if getattr(portrait, "marks", None): m = next(iter(portrait.marks.values())) img = Image.fromarray(np.where(m == 1, 128, 0).astype(np.uint8), "L") # nose mark only; the mouth is a line b = io.BytesIO() img.save(b, "PNG", optimize=True) import base64 marks = base64.b64encode(b.getvalue()).decode() # painted renderer: a material kind and one base colour per role; the shader builds the ramp pc = dict(signature="#7d1e2c", doublet="#2a2d3d", heraldry="#dfe2e8", leather="#5f3e2b", boot="#4a3326", glove="#5f3e2b", steel="#a6adbb", gold="#b08b3f", hair=hexp("C"), trim="#b08b3f") pc.update(getattr(portrait, "paint", None) or {}) skin = dict(kind="skin", base=pc.get("skin") or "#f8e1d5") # light skin unless a tone is set skin["ramp"] = skin_ramp(skin["base"]) # its lit, shade and deep shade paint = {"face": dict(skin), "body": dict(skin), "shadow": dict(skin, shade=True), # shadow cards: skin in shade "hair": dict(kind="hair", base=pc["hair"]), "coat": dict(kind="cloth", base=pc["signature"]), "cape": dict(kind="cloth", base=pc["signature"]), "signature": dict(kind="cloth", base=pc["signature"]), "doublet": dict(kind="cloth", base=pc["doublet"]), "cloth": dict(kind="cloth", base=pc["doublet"]), "heraldry": dict(kind="cloth", base=pc["heraldry"]), "leather": dict(kind="leather", base=pc["leather"]), "boot": dict(kind="leather", base=pc["boot"]), "glove": dict(kind="leather", base=pc["glove"]), "metal": dict(kind="steel", base=pc["steel"]), "steel": dict(kind="steel", base=pc["steel"]), "gold": dict(kind="gold", base=pc["gold"]), "grass": dict(kind="world", base="#5a7a3a"), "dirt": dict(kind="world", base="#6a4a32"), "stone": dict(kind="world", base="#7c7a86"), "motif": dict(kind="cloth", base=pc.get("motif", "#3a44a0"))} # decal paint on steel (tools/plates.py) for role, val in pc.items(): # extra roles a cast entry names (cloth unless it says) if role not in paint and isinstance(val, str) and val.startswith("#"): paint[role] = dict(kind="cloth", base=val) elif role not in paint and isinstance(val, dict) and "base" in val: paint[role] = dict(kind=val.get("kind", "cloth"), base=val["base"]) for role, g in (pc.get("grain") or {}).items(): # optional per-role brush grain (big flat cloth mottles) if role in paint: paint[role]["grain"] = g return dict(roles=roles, light=vp.LIGHT.tolist(), sun=vp.SUN.tolist(), capsules=caps, cloth=cloth, face_marks=marks, paint=paint, mouth_curve=curve, mouth_bone="J_Bip_C_Head", ink=dict(o=hexp("o"), skin=hexp("1"), hair=hexp("A")), skin=[hexp(c) for c in "12345"], depth_gap=0.012) # ---- skinned export: one rigged character + animation clips -------------------------------------------------------- F4 = np.diag([-1.0, 1.0, -1.0, 1.0])Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && sed -n 316,600p review/vroid-02/index.html
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && sed -n 316,600p review/vroid-02/index.html
result, 285 lines
const PAINT_VS = `${SKIN_HEAD} attribute float edge; attribute vec4 _plate; varying vec3 vN; varying vec2 vUv; varying vec3 vView; varying vec3 vObj; varying float vEdge; varying vec4 vPlate; void main() { ${SKIN_BODY} vN = normalize(normalMatrix * objectNormal); vUv = uv; vObj = position; vEdge = edge; vPlate = _plate; vec4 mv = modelViewMatrix * vec4(transformed, 1.0); vView = -mv.xyz; gl_Position = projectionMatrix * mv; }`; const HSV = ` vec3 rgb2hsv(vec3 c) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); float d = q.x - min(q.w, q.y); return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + 1e-10)), d / (q.x + 1e-10), q.x); } vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); }`; // painted renderer, after the Unicorn Overlord study: tight terminators, hue-shifted ramps built from // one base colour per material, hard reflection bands on steel, strand highlights on hair, a stage // grade and a back rim const PAINT_FS = ` uniform int uKind; uniform vec3 uBase; uniform vec3 uKey; uniform sampler2D uMap; uniform int uAlpha; uniform int uPass; uniform vec4 uInfo; uniform vec3 uEye[3]; uniform vec3 uFlat; uniform vec3 uSkinRef; uniform vec3 uGold; uniform vec3 uAmbient; uniform vec3 uKeyCol; uniform vec3 uRimCol; uniform float uGrain; uniform int uFaceTex; uniform int uDecal; uniform vec3 uMotif; uniform vec3 uBand; uniform vec3 uSkinTone; uniform int uShadeOnly; uniform int uSkinRamp; uniform vec3 uSkinL; uniform vec3 uSkinS; uniform vec3 uSkinC; uniform sampler2D tCastInfo; uniform sampler2D tCastDepth; uniform vec2 uCastRes; uniform int uCastOn; uniform float uCastNear; uniform float uCastFar; uniform float uCastPpm; // Cast shadows on skin, in screen space (the "depth offset" shadows of anime toon shaders): walk from this pixel // toward the key light across the info pass already drawn; if the face (the jaw) or hair stands in front of that // ray, this pixel is in its shadow. The shape is the caster's own outline as the camera sees it, at any angle. float castShadow() { vec2 uv = gl_FragCoord.xy / uCastRes, px = 1.0 / uCastRes; float z0 = uCastNear + texture2D(tCastDepth, uv).x * (uCastFar - uCastNear); float sxy = length(uKey.xy); if (sxy < 0.05) return 0.0; vec2 dir = uKey.xy / sxy; float lz = uKey.z / sxy; // the ray's rise toward the camera per metre across for (int s = 1; s <= 14; s++) { float dm = float(s) * 0.003; // 3 mm steps across the screen, up to 4.2 cm vec2 q = uv + dir * dm * uCastPpm * px; vec4 ni = texture2D(tCastInfo, q); if (ni.a < 0.5) continue; int r = int(ni.r * 255.0 + 0.5); if (r != 1 && r != 3 && r != 11) continue; // casters: the face (jaw, chin) and hair float zq = uCastNear + texture2D(tCastDepth, q).x * (uCastFar - uCastNear); float zr = z0 - lz * dm; if (zq < zr - 0.004 && zq > zr - 0.20) return 1.0; } return 0.0; } varying vec3 vN; varying vec2 vUv; varying vec3 vView; varying vec3 vObj; varying float vEdge; varying vec4 vPlate; ${HSV} float hash(vec3 p) { p = fract(p * 0.3183099 + 0.1); p *= 17.0; return fract(p.x * p.y * p.z * (p.x + p.y + p.z)); } float vnoise(vec3 x) { vec3 i = floor(x), f = fract(x); f = f * f * (3.0 - 2.0 * f); return mix(mix(mix(hash(i), hash(i + vec3(1,0,0)), f.x), mix(hash(i + vec3(0,1,0)), hash(i + vec3(1,1,0)), f.x), f.y), mix(mix(hash(i + vec3(0,0,1)), hash(i + vec3(1,0,1)), f.x), mix(hash(i + vec3(0,1,1)), hash(i + vec3(1,1,1)), f.x), f.y), f.z); } float toward(float h, float target, float amt) { float d = target - h; d -= floor(d + 0.5); return fract(h + clamp(d, -amt, amt)); } vec3 tone(vec3 base, float hue, float amt, float sMul, float vMul) { vec3 h = rgb2hsv(base); return hsv2rgb(vec3(toward(h.x, hue, amt), clamp(h.y * sMul, 0.0, 1.0), clamp(h.z * vMul, 0.0, 1.0))); } float st(float x, float t) { return smoothstep(t - 0.03, t + 0.03, x); } // Steel and gold. Hard reflection bands (dark below the horizon, a dark core under a white streak) // read well where the surface turns fast: rims, tubes, lames. On a broad plate the reflection // barely changes, so a band there fills the whole plate (the blotches): bands fade by how sharply // the surface curves (normal change per metre on screen), and broad plates get a soft tone that // lightens up each outline plate (hgt: height in the plate 0..1, or -1 without plate data). vec3 metal(bool gold, vec3 base, vec3 n, vec3 v, float lit, float hgt) { vec3 r = reflect(-v, n); float ry = r.y + (vnoise(vObj * vec3(3.0, 14.0, 3.0)) - 0.5) * 0.14; // jitter the bands along their length, not into blobs float curv = length(fwidth(n)) / max(length(fwidth(vView)), 1e-5); float sharp = smoothstep(5.0, 14.0, curv); // a shaped plate's domes (over the bust, a crowned panel) turn the bands into closed rings: plates // keep only a little of them and take a crisp highlight toward the light instead if (hgt >= 0.0) sharp *= 0.25; else sharp = max(sharp, 0.3); vec3 s0, s1, s2, s3; if (!gold) { s0 = tone(base, 0.68, 0.10, 2.4, 0.32); s1 = tone(base, 0.68, 0.06, 1.7, 0.76); s2 = tone(base, 0.12, 0.0, 0.8, 0.88); s3 = vec3(0.97, 0.96, 0.92); } else { s0 = vec3(0.30, 0.20, 0.30); s1 = tone(base, 0.20, 0.03, 1.0, 0.72); s2 = base; s3 = tone(base, 0.16, 0.03, 0.5, 1.5); } vec3 hard = mix(s0, s1, st(ry, -0.42)); // facing down: dark hard = mix(hard, s2, st(ry, -0.08)); // facing us: the plate's own grey hard = mix(hard, s0, st(ry, 0.36)); // dark core under the streak hard = mix(hard, s3, st(ry, 0.47)); // the white streak hard = mix(hard, s2 * 1.06, st(ry, 0.70)); float k = smoothstep(-0.55, 0.30, r.y); // broad: darker toward the ground (no jitter: if (hgt >= 0.0) k = clamp(k * 0.45 + hgt * 0.80 - 0.18, 0.0, 1.0); // on a flat plate it streaks) else k = clamp(k * 0.6 + n.y * 0.35 + 0.05, 0.0, 1.0); // without plate data: lighter facing up vec3 soft = mix(s1 * 0.9, s2, k); float hl = dot(n, normalize(uKey + v)); // the key's highlight, a hard-edged shape if (hgt >= 0.0) soft = mix(soft, mix(s2, s3, 0.6), st(hl, 0.955) * smoothstep(0.45, 0.8, hgt)); // the upper part only vec3 col = mix(soft, hard, sharp); return mix(col * 0.72 + s0 * 0.28, col, st(lit, 0.30)); } void main() { vec4 tex = texture2D(uMap, vUv); if (uAlpha == 1 && tex.a < 0.5) discard; if (uAlpha == 2 && (tex.a < 0.5 || dot(tex.rgb, vec3(1.0 / 3.0)) >= 0.42)) discard; if (uPass == 1) { gl_FragColor = uInfo; return; } vec3 n = normalize(vN); if (!gl_FrontFacing) n = -n; vec3 v = normalize(vView); float lit = dot(n, uKey) * 0.5 + 0.5; if (uShadeOnly == 1) lit = min(lit, 0.37); // shadow cards only ever darken skin, to a soft shade else if (uCastOn == 1 && uKind == 1 && int(uInfo.x * 255.0 + 0.5) == 2 && castShadow() > 0.5) lit = min(lit, 0.37); // body skin under the jaw's or the hair's shadow float g1 = vnoise(vObj * 40.0), g2 = vnoise(vObj * 150.0); vec3 col; if (uKind == 0 || uKind == 5 || uKind == 6) { // cloth, leather, ground vec3 hb = rgb2hsv(uBase); bool cool = hb.x > 0.42 && hb.x < 0.86; float sh = uKind == 5 ? 0.93 : (cool ? 0.70 : 0.96); float li = cool ? 0.52 : 0.13; vec3 c0 = tone(uBase, sh, 0.09, 1.12, 0.40), c1 = tone(uBase, sh, 0.05, 1.08, 0.64); vec3 c3 = tone(uBase, li, 0.03, 0.80, 1.20); float l = lit + (g1 - 0.5) * uGrain - (uKind == 6 ? 0.22 : 0.0); // ground: a flat top sits at the base colour col = mix(c0, c1, st(l, 0.30)); col = mix(col, uBase, st(l, 0.50)); col = mix(col, c3, st(l, 0.91)); if (uKind == 5) col *= 0.965 + 0.07 * vnoise(vObj * 22.0); // mottled leather } else if (uKind == 1) { // skin: pale, nearly unshaded from the front vec3 sL = vec3(0.973, 0.882, 0.835), sS = vec3(0.776, 0.659, 0.608), sC = vec3(0.451, 0.322, 0.310); if (uSkinRamp == 1) { sL = uSkinL; sS = uSkinS; sC = uSkinC; } // the character's tone, designed per tone col = mix(sC, sS, st(lit, 0.20)); col = mix(col, sL, st(lit, 0.38)); if (uFaceTex == 1) col *= clamp(tex.rgb / uSkinRef, 0.55, 1.05); if (uSkinRamp == 0) col *= uSkinTone; // older builds: one tint over the light skin } else if (uKind == 2) { // hair: four even bands, hard strand highlights float strand = dot(tex.rgb, vec3(1.0 / 3.0)); vec3 c0 = tone(uBase, 0.72, 0.07, 1.10, 0.45), c1 = tone(uBase, 0.72, 0.035, 1.05, 0.68); vec3 c2 = tone(uBase, 0.56, 0.02, 0.92, 1.10), c3 = tone(uBase, 0.56, 0.03, 0.55, 1.42); float l = lit + (strand - 0.6) * 0.12; col = mix(c0, c1, st(l, 0.40)); col = mix(col, uBase, st(l, 0.56)); col = mix(col, c2, st(l, 0.84)); float sp = dot(n, normalize(uKey + v)) + (strand - 0.6) * 0.18; col = mix(col, c3, st(sp, 0.90) * (1.0 - st(sp, 0.985))); } else if (uKind == 3 || uKind == 4) { // steel, gold bool plate = vPlate.x > 0.5; float e = vPlate.y, w = vPlate.z; bool gilt = uKind == 4 || (plate && w > 0.0 && e < w); // an outline plate's gold border col = metal(gilt, gilt && uKind == 3 ? uGold : uBase, n, v, lit, plate ? vPlate.w : -1.0); if (plate && w > 0.0) { // engraved lines: one inside the border, one on its seam float aa = fwidth(e) * 1.2 + 1e-5; float l1 = 1.0 - smoothstep(0.0010, 0.0010 + aa, abs(e - (w + 0.0050))); float l2 = 1.0 - smoothstep(0.0006, 0.0006 + aa, abs(e - w)); col = mix(col, col * 0.42, max(l1, l2 * 0.8)); } } else if (uKind == 7) { // iris float l = dot(tex.rgb, vec3(1.0 / 3.0)); col = l < 0.3 ? mix(uEye[0], uEye[1], l / 0.3) : mix(uEye[1], uEye[2], clamp((l - 0.3) / 0.6, 0.0, 1.0)); } else if (uKind == 8) { col = tex.rgb; } else { col = uFlat; } if (vPlate.x > 0.5 && vPlate.z > 0.0 && uKind != 3 && uKind != 4) { // a cloth outline piece's gold border, float e = vPlate.y, w = vPlate.z, aa = fwidth(e) * 1.2 + 1e-5; // and a fine gold line inside it float band = 1.0 - smoothstep(w - aa, w, e); float l1 = 1.0 - smoothstep(0.0006, 0.0006 + aa, abs(e - (w + 0.0040))); col = mix(col, metal(true, uGold, n, v, lit, -1.0), max(band, l1 * 0.9)); } if (uDecal == 1) { // a design in the piece's own coordinates: vec3 dm = tex.rgb; // R paint, G groove, B gold inlay float pm = smoothstep(0.3, 0.7, dm.r), gm = smoothstep(0.3, 0.7, dm.g), au = smoothstep(0.3, 0.7, dm.b); if (au > 0.0) col = mix(col, metal(true, uGold, n, v, lit, -1.0), au); if (pm > 0.0) { vec3 pc = mix(tone(uMotif, 0.70, 0.05, 1.10, 0.62), uMotif, st(lit, 0.42)); col = mix(col, mix(pc, tone(uMotif, 0.56, 0.03, 0.8, 1.25), st(lit, 0.92)), pm); } if (gm > 0.0) col = mix(col, col * 0.30, gm); } if (vEdge > 0.5) { // the cloth's border band vec3 gd = tone(uBand, 0.20, 0.03, 1.0, 0.72); col = mix(gd, uBand, st(lit, 0.45)); col = mix(col, tone(uBand, 0.16, 0.03, 0.5, 1.45), st(lit, 0.85)); } if (uKind <= 6) { vec3 grade = mix(uAmbient, uKeyCol, st(lit, 0.55)); col *= uKind == 1 && uSkinRamp == 1 ? mix(vec3(1.0), grade, 0.3) : grade; // a designed skin ramp takes less of it float fr = pow(1.0 - max(dot(n, v), 0.0), 4.0); float back = clamp(dot(n, normalize(vec3(0.55, 0.45, -0.35))), 0.0, 1.0); col += uRimCol * fr * smoothstep(0.1, 0.5, back); if (uKind != 1) col *= 1.0 + (g2 - 0.5) * 0.06; } gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0); }`; const PAINT_COMP = ` uniform sampler2D tColor; uniform sampler2D tInfo; uniform sampler2D tDepth; uniform vec2 uRes; uniform float uNear; uniform float uFar; uniform float uGap; uniform float uSil; uniform float uInner; ${HSV} float z(vec2 p) { return uNear + texture2D(tDepth, p).x * (uFar - uNear); } int rid(vec4 i) { return int(i.r * 255.0 + 0.5); } float pid(vec4 i) { return floor(i.g * 255.0 + 0.5) + floor(i.b * 255.0 + 0.5) * 256.0; } vec3 ink(vec3 c) { vec3 h = rgb2hsv(c); return hsv2rgb(vec3(h.x, clamp(h.y, 0.20, 0.45), 0.19)); } void main() { vec2 uv = gl_FragCoord.xy / uRes, px = 1.0 / uRes; vec4 inf = texture2D(tInfo, uv); if (inf.a < 0.5) { // outer line: grow the silhouette outward vec4 best = vec4(0.0); vec2 bq = uv; for (int k = 0; k < 12; k++) { float a = float(k) * 0.5236; for (int s = 1; s <= 2; s++) { vec2 q = uv + vec2(cos(a), sin(a)) * uSil * float(s) * 0.5 * px; vec4 ni = texture2D(tInfo, q); if (ni.a > 0.5) { best = ni; bq = q; } } } if (best.a > 0.5) { int r = rid(best); if (r >= 4 && r <= 7) { gl_FragColor = vec4(0.0); return; } gl_FragColor = vec4(ink(texture2D(tColor, bq).rgb), 1.0); return; } gl_FragColor = vec4(0.0); return; } vec3 col = texture2D(tColor, uv).rgb; int r0 = rid(inf); float p0 = pid(inf); float z0 = z(uv); bool feature = r0 >= 4 && r0 <= 9; if (!feature) { for (int k = 0; k < 4; k++) { vec2 d = k == 0 ? vec2(1.0, 0.0) : (k == 1 ? vec2(-1.0, 0.0) : (k == 2 ? vec2(0.0, -1.0) : vec2(0.0, 1.0))); vec2 q = uv + d * px * uInner; vec4 ni = texture2D(tInfo, q); if (z(q) > z0 + uGap && pid(ni) != p0) { col = ink(col); break; } } float acc = 0.0, rad = uSil * 3.0; for (int k = 0; k < 8; k++) { float a = float(k) * 0.785398 + 0.39; vec2 q = uv + vec2(cos(a), sin(a)) * rad * px; vec4 ni = texture2D(tInfo, q); if (ni.a > 0.5) acc += clamp((z0 - z(q)) / 0.05, 0.0, 1.0); } col *= 1.0 - 0.22 * acc / 8.0; if (r0 == 1) { // the bangs shade the forehead float hair = 0.0; for (int s = 1; s <= 4; s++) { vec4 a = texture2D(tInfo, uv + vec2(0.0, float(s)) * uSil * px); int ra = rid(a); if (a.a > 0.5 && (ra == 3 || ra == 11)) hair = 1.0; } col = mix(col, col * vec3(0.84, 0.74, 0.76), 0.75 * hair); } } gl_FragColor = vec4(col, 1.0); }`; const compCam = new THREE.Camera(); function compPass(fs, uniforms) { const mat = new THREE.ShaderMaterial({ uniforms, vertexShader: `void main() { gl_Position = vec4(position.xy, 0.0, 1.0); }`, fragmentShader: fs, transparent: true }); const s = new THREE.Scene(); s.add(new THREE.Mesh(new THREE.PlaneGeometry(2, 2), mat)); return { mat, scene: s }; } // ---- the renderer --------------------------------------------------------------------------------------------------- const stageEl = $("stage"); const R = new THREE.WebGLRenderer({ antialias: false, alpha: true, preserveDrawingBuffer: !!SHEET }); R.setClearColor(0x000000, 0); R.outputColorSpace = THREE.LinearSRGBColorSpace; stageEl.appendChild(R.domElement); const paint = compPass(PAINT_COMP, { tColor: { value: null }, tInfo: { value: null }, tDepth: { value: null }, uRes: { value: new THREE.Vector2() }, uNear: { value: 0.1 }, uFar: { value: 40 }, uGap: { value: 0.012 }, uSil: { value: 2 }, uInner: { value: 1 } }); const ctl = new OrbitControls(camera, R.domElement); ctl.enableDamping = true; ctl.zoomToCursor = true; ctl.screenSpacePanning = true; ctl.minZoom = 0.3; ctl.maxZoom = 12; let freeLook = false; ctl.addEventListener("start", () => { freeLook = true; }); R.domElement.addEventListener("dblclick", focusAt); const targets = { rt: null, rtInfo: null, key: "" }; function targetsFor(w, h) { const key = `${w}x${h}`; if (targets.key === key) return; [targets.rt, targets.rtInfo].forEach(t => t && t.dispose()); const o = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter }; targets.rt = new THREE.WebGLRenderTarget(w, h, o); targets.rtInfo = new THREE.WebGLRenderTarget(w, h, { ...o, depthTexture: new THREE.DepthTexture(w, h) }); targets.key = key; } // ---- cloth ------------------------------------------------------------------------------------------------------- // The skinned cape/tails stay hidden and provide the pinned row (they follow the animated body); // a plain display mesh in world space shows the simulated cloth. Colliders ride the bones. const _v = new THREE.Vector3(), _a = new THREE.Vector3(), _ab = new THREE.Vector3(), _cp = new THREE.Vector3(); const _A = new THREE.Vector3(), _B = new THREE.Vector3(); class Cloth { constructor(skinned, U, V, trims, capsules, bone, closed = false, hemOnly = false) { this.skinned = skinned; this.U = U; this.V = V; this.trims = trims; this.closed = closed; this.hemOnly = hemOnly; this.n = skinned.geometry.attributes.position.count; this.caps = capsules.map(c => ({ a: bone(c.bones[0]), b: bone(c.bones[1]), r: c.r + 0.006 })).filter(c => c.a && c.b); this.x = new Float32Array(this.n * 3); this.prev = new Float32Array(this.n * 3); const idx = (i, j) => i * V + j, links = [], bends = [], edge = new Float32Array(this.n); for (let i = 0; i < U; i++) for (let j = 0; j < V; j++) { // a closed cloth (a skirt) wraps around: the last column links back to the firstBashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cat ~/Projects/lowmarch-bench/brief/materials/vroid-shapes.txt | head -80; cd $LOWMARCH_REPO && sed -n 980,1000p tools/vroid_portrait.py; grep -n '"1"\|"A"\|"B"' tools/vroid_portrait.py | head
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cat ~/Projects/lowmarch-bench/brief/materials/vroid-shapes.txt | head -80; cd $LOWMARCH_REPO && sed -n 980,1000p tools/vroid_portrait.py; grep -n '"1"\|"A"\|"B"' tools/vroid_portrait.py | head
result, 42 lines
The 57 VRoid expression shapes on our faces (morph targets, applied by tools/vrm.py VRM.primitives; a recipe key matches a target whose name ends with it): Fcl_ALL_Angry Fcl_ALL_Fun Fcl_ALL_Joy Fcl_ALL_Neutral Fcl_ALL_Sorrow Fcl_ALL_Surprised Fcl_BRW_Angry Fcl_BRW_Fun Fcl_BRW_Joy Fcl_BRW_Sorrow Fcl_BRW_Surprised Fcl_EYE_Angry Fcl_EYE_Close Fcl_EYE_Close_L Fcl_EYE_Close_R Fcl_EYE_Fun Fcl_EYE_Highlight_Hide Fcl_EYE_Iris_Hide Fcl_EYE_Joy Fcl_EYE_Joy_L Fcl_EYE_Joy_R Fcl_EYE_Natural Fcl_EYE_Sorrow Fcl_EYE_Spread Fcl_EYE_Surprised Fcl_HA_Fung1 Fcl_HA_Fung1_Low Fcl_HA_Fung1_Up Fcl_HA_Fung2 Fcl_HA_Fung2_Low Fcl_HA_Fung2_Up Fcl_HA_Fung3 Fcl_HA_Fung3_Low Fcl_HA_Fung3_Up Fcl_HA_Hide Fcl_HA_Short Fcl_HA_Short_Low Fcl_HA_Short_Up Fcl_MTH_A Fcl_MTH_Angry Fcl_MTH_Close Fcl_MTH_Down Fcl_MTH_E Fcl_MTH_Fun Fcl_MTH_I Fcl_MTH_Joy Fcl_MTH_Large Fcl_MTH_Neutral Fcl_MTH_O Fcl_MTH_SkinFung Fcl_MTH_SkinFung_L Fcl_MTH_SkinFung_R Fcl_MTH_Small Fcl_MTH_Sorrow Fcl_MTH_Surprised Fcl_MTH_U Fcl_MTH_Up elif r == "hair": char[mk] = bands(lit[mk], HAIR_BANDS) elif r == "cloth": char[mk] = bands(lit[mk], CLOTH_BANDS) elif r in MATERIALS: nn = n[mk] back = nn[:, 2] < 0 # we see the inside of the piece lv = np.where(back, (-nn) @ LIGHT, lit[mk]) c = bands(lv, MATERIALS[r]) c[back] = [DARKER.get(x_, x_) for x_ in c[back]] char[mk] = c elif r in ("line",): char[mk] = "o" elif r == "brow": char[mk] = "A" elif r == "mouth": char[mk] = "1" elif r == "white": char[mk] = "w" elif r == "highlight": char[mk] = "w" 42:PRIORITY = {"o": 8, "r": 5, "s": 5, "t": 4, "w": 3, "A": 3, "1": 8} # features win the 4x4 vote 56:HAIR_BANDS = [(0.86, "E"), (0.66, "D"), (0.42, "C"), (-9, "B")] 975: c[on] = "1" 994: char[mk] = "A" 996: char[mk] = "1" 1019: down = {"E": "D", "D": "C", "C": "B", "B": "A"} 1060: rule[skin & skin1] = "1" 1062: rule[hair0 & hair1 & (p1 != prim)] = "A" 1118: c[y, x] = "3" if end else "1" 1143: c[y, x] = "1" if dark[0] <= u <= dark[1] else "2"Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $WORK/site && python3 -c "
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $WORK/site && python3 -c " import json;d=json.load(open('arm_f_slender.glb.json'));print(type(d), list(d.keys())[:20] if isinstance(d,dict) else len(d)) " ; ls -la; head -c 600 camera.jsonresult, 55 lines
<class 'dict'> ['glb'] total 7476 drwx------ 2 severian severian 4096 Oct 30 12:42 . drwx------ 4 severian severian 4096 Oct 30 12:43 .. -rw------- 1 severian severian 4268051 Oct 30 12:42 arm_f_slender.glb.json -rw------- 1 severian severian 2785655 Oct 30 12:42 arm_m_youth.glb.json -rw------- 1 severian severian 256105 Oct 30 12:42 camera.json -rw------- 1 severian severian 5960 Oct 30 12:42 checks.json -rw------- 1 severian severian 106760 Oct 30 12:42 index.html -rw------- 1 severian severian 206775 Oct 30 12:42 plains.glb.json { "characters": [ { "name": "arm_m_youth", "label": "Man, youth", "info": { "roles": { "face": { "mode": "bands", "bands": [ [ 0.8, "#fff6d8" ], [ 0.62, "#fbd99c" ], [ 0.38, "#eca067" ], [ -9, "#b06e4b" ] ] }, "body": { "mode": "bands", "bands": [ [ 0.8, "#fff6d8" ], [ 0.62, "#fbd99c" ], [ 0.38, "#eca067" ], [ -9Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && mkdir -p $WORK/tex && cd $WORK && python3 -I - <<'EOF'
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && mkdir -p $WORK/tex && cd $WORK && python3 -I - <<'EOF' import json,base64,struct,io d=json.load(open('site/arm_f_slender.glb.json'))['glb'] b=base64.b64decode(d) L=struct.unpack('<I',b[12:16])[0]; js=json.loads(b[20:20+L]); bin0=20+L+8 print([m.get('name') for m in js['materials']]) for i,m in enumerate(js['materials']): pbr=m.get('pbrMetallicRoughness',{}); t=pbr.get('baseColorTexture') if t is None: continue img=js['images'][js['textures'][t['index']]['source']]; bv=js['bufferViews'][img['bufferView']] open(f'tex/{i}_{m.get("name")}.png','wb').write(b[bin0+bv.get('byteOffset',0):bin0+bv.get('byteOffset',0)+bv['byteLength']]) print([ (me.get('name'), me.get('extras')) for me in js['meshes']][:40]) EOF ls $WORK/texresult, 12 lines
['body:mouth', 'body:iris', 'body:highlight', 'body:face', 'body:white', 'body:brow', 'body:line', 'body:line', 'body:body', 'hair:hair', 'hair:hair', 'underwear:cloth', 'underwear:cloth', 'body:shadow'] [('body', None), ('body', None), ('body', None), ('body', None), ('body', None), ('body', None), ('body', None), ('body', None), ('body', None), ('hair', None), ('hair', None), ('underwear', None), ('underwear', None), ('body', None)] 0_body:mouth.png 10_hair:hair.png 1_body:iris.png 2_body:highlight.png 3_body:face.png 4_body:white.png 5_body:brow.png 6_body:line.png 7_body:line.png 9_hair:hair.pngRead~/Projects/lowmarch-bench/work/b/tex/0_body:mouth.png
input
{ "file_path": "~/Projects/lowmarch-bench/work/b/tex/0_body:mouth.png" }result
no output
Read~/Projects/lowmarch-bench/brief/materials/yin-expressions/shout_y00.png
input
{ "file_path": "~/Projects/lowmarch-bench/brief/materials/yin-expressions/shout_y00.png" }result, 1 line
[redacted: reference rig image (Yin/Yang by DillonGoo, personal-use licence)]Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && grep -n -i 'weight\|morph\|target' tools/vrm.py | head -30; grep -n 'rest' tools/vroid_portrait.py | head -20; grep -n -i 'brow\|bang' docs/portrait-guide.md | head -30
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && grep -n -i 'weight\|morph\|target' tools/vrm.py | head -30; grep -n 'rest' tools/vroid_portrait.py | head -20; grep -n -i 'brow\|bang' docs/portrait-guide.md | head -30
result, 45 lines
133: def primitives(self, morphs=None, pose=None): 135: morphs: {target name substring: weight} applied to meshes that have targets. 141: names = mesh.get("extras", {}).get("targetNames") or \ 142: mesh["primitives"][0].get("extras", {}).get("targetNames") or [] 148: if morphs and pr.get("targets"): 149: for key, wgt in morphs.items(): 151: if tn.endswith(key) and "POSITION" in pr["targets"][ti]: 152: pos += wgt * self.accessor(pr["targets"][ti]["POSITION"]) 157: Wt = self.accessor(at["WEIGHTS_0"]).astype(np.float64) 171: def target_names(self): 173: names = mesh.get("extras", {}).get("targetNames") or \ 174: mesh["primitives"][0].get("extras", {}).get("targetNames") 251:def bone_weight(prim, match): 252: """Per-vertex total skin weight on bones whose name contains any of `match` (substrings).""" 121: the winning char per pixel plus the depth / primitive / role of its nearest sample.""" 161:# 3. resting expression: VRoid's own shapes (hooded eyes, stern brows) held at a low weight 167: face_normals=1.0, hair_normals=0.0, shadow_cards=1.0, rest={}) 476: weights at the nearest vertex, so it rides and bends with the skin beneath.""" 601: """A point on the face seen straight on: the nearest surface hit from the front.""" 739: mo = dict(sh["rest"]) 1093: # no triangle contains it (a gap between UV islands): take the nearest vertex in UV space 16:material's own darkest tone: rosy brown in skin, darkest hair tone between locks. 19:steps (yellow-cream → orange → brown → line). Shadows go: under the bangs (cast), the far side 28:**Brows.** Men: heavy, sitting right on the lash line. Women: thin, high. 34:upper left) and a shadow side; the separating line sits on the shadow side. Bangs sweep 41:Heavy builds: round masses. Women: rounder cheeks, more eye white, thin high brows. 52: separating lines. Then `pix.py shadow` casts the bangs onto the face. 63:- Bangs hanging straight down read as a curtain. Sweep them toward the face's turn. 68:- Bare forehead between bangs looked like light columns. Always run the cast-shadow pass. 96:- **Flat eye plane.** A cylinder-like face squeezes the far eye even at 20° ("cursed"). Keep brow and 121:- **Features from geometry and masks.** Eyes, brows and lashes come from VRoid's alpha-tested face 126:- **Archetypes are shape controls on the mesh** (face length, jaw, chin, cheeks, eyes, brows, nose, 157: inside the nose-and-mouth window of the shared VRoid face layout, or the ear shading turns brown. 202:- **Cloth in the viewer:** the cape and tails export as grids (`grid`); the browser runs Verlet with 321: leaves the bangs and side locks. 540: - Bangs read as separate pointed locks when they are narrow (2.2-2.8 cm) with long tapers. 542:- **Bangs from a study, not a formula.** The user found seven evenly spaced matching points jarring. 550: `lock(profile=...)` takes a width profile (`hair.clump`). Elaine's bangs: a side part over her 616:- The eyes, brows and mouth are anime drawings in textures, so moving the skull under them changes 633: smoothed brow strips, and a lip line. 834:brows, mouth and expression shapes) by landmarks onto MakeHuman's skull, keeping MakeHuman's structure and 1164: length, cheeks, eye size), and leave the jaw, brow and nose to the design. 1231:face, brows, lines, mouth and skull are shaded from normals that point away from a short vertical line inside the 1329: and the stage's blue shade turned brown skin grey. A ramp per tone, with shade hue nudged warm on people (cool on 1332: and stopped at a mid brown.Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && sed -n 800,840p review/vroid-02/index.html; grep -n 'SKIN_BODY =\|SKIN_HEAD =' review/vroid-02/index.html
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && sed -n 800,840p review/vroid-02/index.html; grep -n 'SKIN_BODY =\|SKIN_HEAD =' review/vroid-02/index.html
result, 43 lines
bust: { ambient: [0.90, 0.90, 0.98], key: [1.03, 1.0, 0.96], rim: [0.24, 0.24, 0.34] } }; const KIND = { cloth: 0, skin: 1, hair: 2, steel: 3, gold: 4, leather: 5, world: 6 }; function paintMaterial(V, role, map, index, infoRole = role, decal = false) { const Rl = V.roles[role] || { mode: "flat", color: "#ff00ff" }, P = (V.paint || {})[role]; const u = { uKind: { value: 9 }, uBase: { value: new THREE.Color(0.8, 0.8, 0.8) }, uKey: { value: KEY.clone() }, uMap: { value: map || white }, uAlpha: { value: 0 }, uPass: { value: 0 }, uInfo: { value: new THREE.Vector4(roleId(infoRole) / 255, (index % 256) / 255, Math.floor(index / 256) / 255, 1) }, uEye: { value: V.roles.iris.colors.map(hex) }, uFlat: { value: new THREE.Color() }, uSkinRef: { value: new THREE.Vector3(0.965, 0.878, 0.80) }, uGold: { value: hex((V.paint && V.paint.gold && V.paint.gold.base) || "#b08b3f") }, uAmbient: { value: new THREE.Vector3(1, 1, 1) }, uKeyCol: { value: new THREE.Vector3(1, 1, 1) }, uRimCol: { value: new THREE.Vector3() }, uGrain: { value: 0.05 }, uFaceTex: { value: 0 }, uDecal: { value: decal ? 1 : 0 }, uBand: { value: null }, uSkinTone: { value: new THREE.Vector3(1, 1, 1) }, uShadeOnly: { value: 0 }, uSkinRamp: { value: 0 }, uSkinL: { value: new THREE.Color() }, uSkinS: { value: new THREE.Color() }, uSkinC: { value: new THREE.Color() }, tCastInfo: { value: null }, tCastDepth: { value: null }, uCastRes: { value: new THREE.Vector2(1, 1) }, uCastOn: { value: 0 }, uCastNear: { value: 0.1 }, uCastFar: { value: 40 }, uCastPpm: { value: 1 }, uMotif: { value: hex((V.paint && V.paint.motif && V.paint.motif.base) || "#3a44a0") } }; if (P) { u.uKind.value = KIND[P.kind] ?? 0; if (P.base) u.uBase.value = hex(P.base); if (P.grain != null) u.uGrain.value = P.grain; } else if (Rl.bands) { u.uKind.value = Rl.world ? 6 : 0; u.uBase.value = hex(Rl.bands[Math.min(1, Rl.bands.length - 1)][1]); } if (P && P.kind === "world") { u.uKey.value = new THREE.Vector3(...V.sun); u.uGrain.value = 0.12; } if (P && P.shade) u.uShadeOnly.value = 1; // shadow cards: skin, always in its shade tone if (P && P.kind === "skin" && P.ramp) { // a designed ramp: lit, shade, deep shade u.uSkinRamp.value = 1; u.uSkinL.value = hex(P.ramp[0]); u.uSkinS.value = hex(P.ramp[1]); u.uSkinC.value = hex(P.ramp[2]); } if (P && P.kind === "skin" && P.base) { // skin tone: the base colour against the default light skin const c = hex(P.base); u.uSkinTone.value.set(c.r / 0.973, c.g / 0.882, c.b / 0.835); } if (role === "face" && map) u.uFaceTex.value = 1; if (role === "hair" && map) u.uAlpha.value = 1; if (role === "iris") { u.uKind.value = 7; u.uAlpha.value = 1; } else if (role === "white" || role === "highlight") { u.uKind.value = map ? 8 : 9; if (map) u.uAlpha.value = 1; u.uFlat.value = hex(Rl.color || "#ffffff"); } else if (!P && Rl.mode === "flat") { u.uKind.value = 9; u.uFlat.value = hex(Rl.color); if (map) u.uAlpha.value = role === "line" ? 2 : 1; } u.uBand.value = u.uGold.value.clone(); const m = new THREE.ShaderMaterial({ uniforms: u, vertexShader: PAINT_VS, fragmentShader: PAINT_FS, side: THREE.DoubleSide, extensions: { derivatives: true } }); // meshes without plate data or a cloth edge read zeros, not whatever another program left in that slot m.defaultAttributeValues = { ...m.defaultAttributeValues, _plate: [0, 0, 0, 0], edge: [0] }; return m; } // ---- models ------------------------------------------------------------------------------------------------------ const loader = new GLTFLoader(); 309:const SKIN_HEAD = `#include <common> 311:const SKIN_BODY = `#include <beginnormal_vertex>Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && python3 -I - <<'EOF'
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && python3 -I - <<'EOF' p='review/vroid-02/index.html'; s=open(p).read() def rep(a,b): global s assert s.count(a)==1,a; s=s.replace(a,b) rep(""" attribute float edge; attribute vec4 _plate; varying vec3 vN;""",""" attribute float edge; attribute vec4 _plate; uniform float uLift; varying vec3 vN;""") rep(""" vec4 mv = modelViewMatrix * vec4(transformed, 1.0); vView = -mv.xyz; gl_Position""",""" vec4 mv = modelViewMatrix * vec4(transformed, 1.0); vView = -mv.xyz; mv.z += uLift; // brows: drawn over the bangs (depth lift toward the camera) gl_Position""") rep(""" } else if (uKind == 8) { col = tex.rgb; }""",""" } else if (uKind == 8) { col = tex.rgb; } else if (uKind == 10) { // open mouth: deep maroon, pink tongue, white teeth float l = dot(tex.rgb, vec3(1.0 / 3.0)); vec3 deep = vec3(0.34, 0.12, 0.15), tongue = vec3(0.88, 0.47, 0.49); col = mix(deep, tongue, smoothstep(0.65, 0.70, l)); col = mix(col, vec3(0.99, 0.97, 0.96), smoothstep(0.84, 0.90, l)); }""") rep(""" uMotif: { value: hex((V.paint && V.paint.motif && V.paint.motif.base) || "#3a44a0") } };""", """ uMotif: { value: hex((V.paint && V.paint.motif && V.paint.motif.base) || "#3a44a0") }, uLift: { value: 0 } };""") rep(""" u.uBand.value = u.uGold.value.clone();""",""" if (role === "brow") u.uLift.value = BROW_LIFT; if (role === "mouth" && map) { u.uKind.value = 10; u.uAlpha.value = 1; } u.uBand.value = u.uGold.value.clone();""") rep("""const KIND = { cloth: 0,""","""// Brows draw over the bangs: they are lifted this far (m) toward the camera, more than the bangs stand off the // forehead and much less than the head is deep, so a brow still hides behind the skull when the head turns away. const BROW_LIFT = 0.04; const KIND = { cloth: 0,""") open(p,'w').write(s) EOF grep -n 'uniform vec3 uGold' review/vroid-02/index.htmlresult, 1 line
345: uniform vec3 uGold; uniform vec3 uAmbient; uniform vec3 uKeyCol; uniform vec3 uRimCol; uniform float uGrain;
Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cp $WORK/expr_list.txt $WORK/expr_list.orig.txt && cat > $WORK/expr_list.txt <<'EOF'
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cp $WORK/expr_list.txt $WORK/expr_list.orig.txt && cat > $WORK/expr_list.txt <<'EOF' # expression recipes: name|VRoid shapes baked at build (Fcl_* names, weight; ';' between; 'none' = neutral) # the 14 the sheets show; keep these names (front_sheet.py reads them). Edit the recipes freely. neutral|none joy|Fcl_BRW_Joy:1;Fcl_EYE_Joy:1;Fcl_MTH_Joy:0.6 smile|Fcl_BRW_Fun:1;Fcl_EYE_Fun:0.5;Fcl_MTH_Fun:1 angry|Fcl_BRW_Angry:1.4;Fcl_EYE_Angry:1;Fcl_MTH_Angry:1 sad|Fcl_BRW_Sorrow:1.3;Fcl_EYE_Sorrow:1;Fcl_MTH_Sorrow:1 surprised|Fcl_BRW_Surprised:1.2;Fcl_EYE_Surprised:1;Fcl_MTH_Surprised:0.6 shout|Fcl_BRW_Angry:1.3;Fcl_EYE_Angry:0.8;Fcl_MTH_A:0.8 wink|Fcl_EYE_Close_R:1;Fcl_BRW_Fun:0.6;Fcl_MTH_Fun:1 smug|Fcl_EYE_Close:0.35;Fcl_BRW_Angry:0.5;Fcl_MTH_Fun:0.6 lip_A|Fcl_MTH_A:0.75 lip_I|Fcl_MTH_I:1 lip_U|Fcl_MTH_U:1 lip_E|Fcl_MTH_E:0.9 lip_O|Fcl_MTH_O:0.75 EOF cd $LOWMARCH_REPO && time $KIT/build_expr.sh $WORK/expr_list.txt neutral joy smile angry sad surprised shout
result, 11 lines
built neutral built joy built smile built angry built sad built surprised built shout real 1m44.552s user 1m28.765s sys 1m7.160s
Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && time $KIT/build_expr.sh $WORK/expr_list.txt wink smug lip_A lip_I lip_U lip_E lip_O && time $KIT/shoot_expr.sh $LOWMARCH_REPO/review/vroid-02/index.html r1 && $KIT/sheets.sh r1 "Round 1: brows over bangs, textured mouth, tuned recipes"
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $LOWMARCH_REPO && time $KIT/build_expr.sh $WORK/expr_list.txt wink smug lip_A lip_I lip_U lip_E lip_O && time $KIT/shoot_expr.sh $LOWMARCH_REPO/review/vroid-02/index.html r1 && $KIT/sheets.sh r1 "Round 1: brows over bangs, textured mouth, tuned recipes"
result, 18 lines
built wink built smug built lip_A built lip_I built lip_U built lip_E built lip_O real 1m42.031s user 1m32.035s sys 1m10.588s shot r1 real 7m59.116s user 0m32.270s sys 0m27.314s ~/Projects/lowmarch-bench/work/b/sheet_r1_woman.png (1968, 1144) ~/Projects/lowmarch-bench/work/b/sheet_r1_youth.png (1968, 1144)
Read~/Projects/lowmarch-bench/work/b/sheet_r1_woman.png
input
{ "file_path": "~/Projects/lowmarch-bench/work/b/sheet_r1_woman.png" }result
no output
Read~/Projects/lowmarch-bench/work/b/sheet_r1_youth.png
input
{ "file_path": "~/Projects/lowmarch-bench/work/b/sheet_r1_youth.png" }result
no output
Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && cd $WORK && python3 -I -c "
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && cd $WORK && python3 -I -c " from PIL import Image im=Image.open('shot_r1/shout/painted_arm_f_slender.png'); print(im.size) w,h=im.size; im.crop((300,560,700,860)).resize((800,600)).save('$WORK/crop_shout.png') im.crop((w//2+250,560,w//2+650,860)).resize((800,600)).save('$WORK/crop_shout30.png') "result, 1 line
(1938, 1024)
Read~/Projects/lowmarch-bench/work/b/crop_shout.png
input
{ "file_path": "~/Projects/lowmarch-bench/work/b/crop_shout.png" }result
no output
Read~/Projects/lowmarch-bench/work/b/crop_shout30.png
input
{ "file_path": "~/Projects/lowmarch-bench/work/b/crop_shout30.png" }result
no output
Bashsource ~/Projects/lowmarch-bench/kit/env-b.sh && time $KIT/terra_review.sh r1 $WORK/sheet_r1_woman.png $WORK/sheet_r1_youth.png
command
source ~/Projects/lowmarch-bench/kit/env-b.sh && time $KIT/terra_review.sh r1 $WORK/sheet_r1_woman.png $WORK/sheet_r1_youth.png
result, 18 lines
exit=0 The current round makes the brows easier to read, especially for Angry and Surprised, but drawing them over the bangs creates a floating, pasted-on look. The new pink mouths also lose some of the depth and clarity of the darker Before mouths. **Woman:** Joy and Wink read clearly through the closed eyes; Angry reads through the sharply slanted brows. Neutral and Smile are pleasant but very similar. Sad reads mostly from the brows and small mouth; the eyes still look fairly neutral. Surprised and Shout are harder to tell apart: both mouths are small, horizontal pink shapes, and Surprised lacks a convincing open “O.” Smug reads close to Neutral because the eyes and mouth barely change. **Youth:** Joy, Angry and Surprised read through their eye and brow shapes. Wink reads, though the closed eye still shows enough iris to look half-lidded. Smile, Sad and Smug are subtle; Smug especially needs a more asymmetric or self-satisfied mouth. Shout looks more like a small smile than a forceful call. For both bodies, the lip-sync shapes have regressed: A and O are flattened and similarly pink, I is nearly invisible, U is a tiny mark, and E is a thin smile. White rims and dark corner fragments make several mouths look outlined or detached. The three highest-impact changes for the next round: 1. **Integrate the brows with the hair:** keep their expressive angles, but break or soften strokes where bangs cross them so they don’t appear painted on top. 2. **Restore mouth depth:** use a dark interior with restrained tongue or lip colour; remove the white rims and corner fragments. Give Shout a substantially taller opening. 3. **Separate the phonemes:** make A tall and open, I wide and narrow, U small and rounded, E wide with visible teeth, and O distinctly round. real 0m14.235s user 0m0.797s sys 0m0.729s




