function parseObjLine(line, obj) { line = line.trim(); if (line[0] === '#' || line.length < 1) { return; } const elements = line.split(/\s+/); obj[elements[0]].push(elements.slice(1)); } function getFaces(obj) { return obj.f.map(f => { const face = { 'vertices': [], 'normals': [], 'textures': [], }; if (f.length === 4) { // add duplicate vertices to make triangles f.splice(3, 0, f[0]); f.splice(4, 0, f[2]); } f.forEach(v => { const [vidx, vtidx, vnidx] = v.split('/'); face.vertices.push((obj.v[vidx - 1] || []).map(Number)); face.normals.push((obj.vn[vnidx - 1] || []).map(Number)); //face.textures.push((obj.vt[vtidx] || []).map(Number)); face.textures.push([0, 0]); }); return face; }); } export async function loadObjModel(url) { const stlDataStream = (await fetch(url)).body; const faces = []; const obj = new Proxy({}, { get: (target, name) =>{ if (!(name in target)) { target[name] = []; } return target[name]; }, }); return new Promise((resolve, reject) => { let partialLine = ""; const reader = stlDataStream.getReader(); const decoder = new TextDecoder(); function pump() { reader.read().then(({ done, value }) => { if (done) { parseObjLine(partialLine, obj); return resolve(getFaces(obj)); } const textInput = decoder.decode(value); const lines = textInput.split('\n'); if (lines.length > 1) { parseObjLine(partialLine + lines[0], obj); partialLine = ""; lines.slice(0, -1).forEach(line => { parseObjLine(line, obj); }); } partialLine = partialLine + lines.at(-1); pump(); }); } pump(); }); }