Reads the numbers of an FBX file, binary or text, into the node tree the importer uses.
How the precision is kept
Each value is read with the type the file gives it and is not scaled or rounded here. Single-precision properties and arrays stay 32-bit because the file stores them so; doubles are 64-bit. Whole numbers of 64 bits are kept exactly up to 2⁵³ and as decimal text beyond that.
Calculations under this policy
3 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.
Reads one property value with the width the file states.
A 32-bit float is read with getFloat32 and held as a 64-bit number with the same value; nothing is added to or taken from the file's digits. Doubles are read with getFloat64.
io/fbx-parse.js
lines 93 to 98
ModelCraft 0.8.1
case 'Y': need(2); props.push(dv.getInt16(q, true)); q += 2; break;
case 'C': need(1); props.push(b[q] !== 0); q += 1; break;
case 'I': need(4); props.push(dv.getInt32(q, true)); q += 4; break;
case 'F': need(4); props.push(dv.getFloat32(q, true)); q += 4; break;
case 'D': need(8); props.push(dv.getFloat64(q, true)); q += 8; break;
case 'L': need(8); props.push(i64(dv, q)); q += 8; break;
64-bit whole numbers
Exact
Reads a signed 64-bit whole number from two 32-bit halves.
v = hi × 2³² + lo when −2²¹ ≤ hi < 2²¹; otherwise decimal text
Inside that range the value is below 2⁵³ in magnitude and the sum is exact. Larger values are built with BigInt and returned as text, so no digit is lost.
io/fbx-parse.js
lines 154 to 160
ModelCraft 0.8.1
/** A signed 64-bit integer: a Number when it fits exactly, else its decimal text (object ids can be that large). */
function i64(dv, q) {
const lo = dv.getUint32(q, true);
const hi = dv.getInt32(q + 4, true);
if (hi >= -0x200000 && hi < 0x200000) return hi * 4294967296 + lo;
return ((BigInt(hi) << 32n) | BigInt(lo)).toString();
}
Arrays by type
64-bit
Reads an array of floats, doubles or whole numbers.
Float arrays go into a Float32Array and double arrays into a Float64Array, each as stored. An array of 64-bit whole numbers goes into a Float64Array; a value that i64 returned as text is converted with Number() and so rounded above 2⁵³.
io/fbx-parse.js
lines 162 to 171
ModelCraft 0.8.1
function typedArray(tc, raw, n) {
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
if (tc === 'f') { const a = new Float32Array(n); for (let i = 0; i < n; i++) a[i] = dv.getFloat32(i * 4, true); return a; }
if (tc === 'd') { const a = new Float64Array(n); for (let i = 0; i < n; i++) a[i] = dv.getFloat64(i * 8, true); return a; }
if (tc === 'i') { const a = new Int32Array(n); for (let i = 0; i < n; i++) a[i] = dv.getInt32(i * 4, true); return a; }
if (tc === 'l') { const a = new Float64Array(n); for (let i = 0; i < n; i++) { const v = i64(dv, i * 8); a[i] = typeof v === 'number' ? v : Number(v); } return a; }
const a = new Uint8Array(n);
for (let i = 0; i < n; i++) a[i] = tc === 'b' ? (raw[i] ? 1 : 0) : raw[i]; // b: booleans; c: bytes (seen in files, e.g. edge crease flags)
return a;
}
In detail
Method
DataView reads by type letter: Y 16-bit, I 32-bit, F 32-bit float, D 64-bit float, L 64-bit whole number; arrays f, d, l, i, b, c. Text files: Number() of each token.
Number types
Float32Array for f arrays, Float64Array for d and l arrays, Int32Array for i arrays, 64-bit numbers for single values.
Limits
In an array of 64-bit whole numbers a value of 2⁵³ or more is converted with Number() and rounded to the nearest 64-bit float. Accuracy of 32-bit values is the file's own.
Approach: 64-bit, stated limit
The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.