71 lines
2.3 KiB
JavaScript
71 lines
2.3 KiB
JavaScript
import { Mesh, Vertex } from '../core.js';
|
|
|
|
export class OBJLoader {
|
|
|
|
async loadMesh(url) {
|
|
const response = await fetch(url);
|
|
const text = await response.text();
|
|
|
|
const lines = text.split('\n');
|
|
|
|
const vRegex = /v\s+(\S+)\s+(\S+)\s+(\S+)\s*/;
|
|
const vData = lines
|
|
.filter(line => vRegex.test(line))
|
|
.map(line => [...line.match(vRegex)].slice(1))
|
|
.map(entry => entry.map(entry => Number(entry)));
|
|
|
|
const vnRegex = /vn\s+(\S+)\s+(\S+)\s+(\S+)\s*/;
|
|
const vnData = lines
|
|
.filter(line => vnRegex.test(line))
|
|
.map(line => [...line.match(vnRegex)].slice(1))
|
|
.map(entry => entry.map(entry => Number(entry)));
|
|
|
|
const vtRegex = /vt\s+(\S+)\s+(\S+)\s*/;
|
|
const vtData = lines
|
|
.filter(line => vtRegex.test(line))
|
|
.map(line => [...line.match(vtRegex)].slice(1))
|
|
.map(entry => entry.map(entry => Number(entry)));
|
|
|
|
function triangulate(list) {
|
|
const triangles = [];
|
|
for (let i = 2; i < list.length; i++) {
|
|
triangles.push(list[0], list[i - 1], list[i]);
|
|
}
|
|
return triangles;
|
|
}
|
|
|
|
const fRegex = /f\s+(.*)/;
|
|
const fData = lines
|
|
.filter(line => fRegex.test(line))
|
|
.map(line => line.match(fRegex)[1])
|
|
.map(line => line.trim().split(/\s+/))
|
|
.flatMap(face => triangulate(face));
|
|
|
|
const vertices = [];
|
|
const indices = [];
|
|
const cache = {};
|
|
let cacheLength = 0;
|
|
const indicesRegex = /(\d+)(\/(\d+))?(\/(\d+))?/;
|
|
|
|
for (const id of fData) {
|
|
if (id in cache) {
|
|
indices.push(cache[id]);
|
|
} else {
|
|
cache[id] = cacheLength;
|
|
indices.push(cacheLength);
|
|
const [,vIndex,,vtIndex,,vnIndex] = [...id.match(indicesRegex)]
|
|
.map(entry => Number(entry) - 1);
|
|
vertices.push(new Vertex({
|
|
position: vData[vIndex],
|
|
normal: vnData[vnIndex],
|
|
texcoords: vtData[vtIndex],
|
|
}));
|
|
cacheLength++;
|
|
}
|
|
}
|
|
|
|
return new Mesh({ vertices, indices });
|
|
}
|
|
|
|
}
|