Resources Numerical accuracy Calculation policy

Texture bake inputs

Gathers the triangles, normals and ray distance that the texture bake (ambient occlusion, curvature, normals, lighting) reads to make pictures.

How the precision is kept

Positions are carried to world coordinates with the placement matrix into Float64Array. The results are pictures: colors along the mesh's UVs. No length, area or other number a person reads comes out of this code.

Calculations under this policy

2 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

ws-shading.js ModelCraft 0.8.1 32-bit, display only 2 calculations Reviewed

Tests tools/shading-test/browser-ui.mjs

A placement's surface in world coordinates

32-bit, display only

Every triangle corner of the selected object with its normal and UV, in world coordinates, for the bake.

Positions are the placement matrix times each corner, written to Float64Array. Faces that are not a mesh get one normal per triangle from a cross product. The arrays feed the bake that writes pictures.

  • ws-shading.js
  • lines 859 to 879
  • ModelCraft 0.8.1
/** A placement's surface in world coordinates: {pos, nrm, uv (null without UVs), tris} — a mesh renders `def.rendered`. */
export function surfaceOf(mdl, path) {
  const ctx = mdl.context(path);
  if (!ctx) return null;
  const def = ctx.def, m = ctx.m, pos = [], nrm = [], uv = [];
  if (def.mesh) {
    const R = def.rendered, T = R.triangulate(), P = R.P, hV = R.hV, CN = R.cornerNormals(), U = R.attrArray('uv');
    for (let i = 0; i < T.n; i++) for (let q = 0; q < 3; q++) {
      const h = T.tri[i * 3 + q], v = hV[h] * 3, w = apply(m, [P[v], P[v + 1], P[v + 2]]), n = norm(applyDir(m, [CN[h * 3], CN[h * 3 + 1], CN[h * 3 + 2]]));
      pos.push(...w); nrm.push(...n);
      if (U) uv.push(U[h * 2], U[h * 2 + 1]);
    }
    return { pos: new Float64Array(pos), nrm: new Float64Array(nrm), uv: U ? new Float64Array(uv) : null, mesh: true };
  }
  const t = defTriangles(def);
  for (let i = 0; i < t.length; i += 9) {
    const a = apply(m, [t[i], t[i + 1], t[i + 2]]), b = apply(m, [t[i + 3], t[i + 4], t[i + 5]]), c = apply(m, [t[i + 6], t[i + 7], t[i + 8]]), n = norm(cross(sub(b, a), sub(c, a)));
    pos.push(...a, ...b, ...c); nrm.push(...n, ...n, ...n);
  }
  return { pos: new Float64Array(pos), nrm: new Float64Array(nrm), uv: null, mesh: false };
}

Bake ray distance and widths

32-bit, display only

The ray distance, curvature width and cage distance handed to the bake.

dist = given, or 0.25 × bounding box diagonal; width = percent ÷ 100; cage = percent ÷ 100

The diagonal is one Math.hypot of the three box sides. When the typed distance is 0 the bake uses a quarter of that diagonal. These values steer how the pictures are shaded.

  • ws-shading.js
  • lines 913 to 924
  • ModelCraft 0.8.1
const bb = host.model.bbox(), diag = bb ? Math.hypot(bb.max[0] - bb.min[0], bb.max[1] - bb.min[1], bb.max[2] - bb.min[2]) : 1;
const ctrl = new AbortController();
st.bake.busy = { ctrl, done: 0 };
host.renderPanel();
let pool = null;
try { pool = await (await import('./compute/runtime.js')).pagePool(); } catch (e) { pool = null; }   // no workers: in the page
const t0 = performance.now();
try {
  const r = await bakeTextures({
    low: tg.low.s, maps, size: o.size, occluders: maps.some((k) => k === 'ao' || k === 'light') ? sceneTriangles(host.model) : null,
    high: tg.high ? tg.high.s : null,
    opts: { rays: o.rays, dist: o.dist > 0 ? o.dist : diag * 0.25, width: o.width / 100, cage: o.cage / 100, sun: bakeSun(host.view.style), sunPower: 1, seed: 1 },

In detail

Method
Placement matrix times each corner; corner normals turned by the matrix and made unit; default ray distance a quarter of the model's bounding box diagonal.
Number types
Float64Array for positions, normals and UVs handed to the bake; the mesh's corner normals and UV layer are the mesh's own arrays.
Limits
The output is PNG pictures added to the model.

Approach: Display only

Computed to draw the screen, often in 32-bit on the graphics processor. No number a person reads, saves or exports comes from it.

Every policy that takes this approach