mirror of
https://github.com/CesiumGS/obj2gltf.git
synced 2024-11-23 08:34:14 -05:00
Merge pull request #191 from AnalyticalGraphicsInc/fix-negative-indices
Fix negative indices
This commit is contained in:
commit
a81d88bdcb
109
lib/loadObj.js
109
lib/loadObj.js
@ -58,9 +58,9 @@ const facePattern = /(-?\d+)\/?(-?\d*)\/?(-?\d*)/g;
|
||||
*/
|
||||
function loadObj(objPath, options) {
|
||||
// Global store of vertex attributes listed in the obj file
|
||||
let positions = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
let normals = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
let uvs = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
let globalPositions = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
let globalNormals = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
let globalUvs = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
|
||||
// The current node, mesh, and primitive
|
||||
let node;
|
||||
@ -144,8 +144,8 @@ function loadObj(objPath, options) {
|
||||
}
|
||||
|
||||
function faceAndPrimitiveMatch(uvs, normals, primitive) {
|
||||
const faceHasUvs = uvs[0].length > 0;
|
||||
const faceHasNormals = normals[0].length > 0;
|
||||
const faceHasUvs = defined(uvs[0]);
|
||||
const faceHasNormals = defined(normals[0]);
|
||||
const primitiveHasUvs = primitive.uvs.length > 0;
|
||||
const primitiveHasNormals = primitive.normals.length > 0;
|
||||
return primitiveHasUvs === faceHasUvs && primitiveHasNormals === faceHasNormals;
|
||||
@ -160,43 +160,58 @@ function loadObj(objPath, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function getOffset(a, attributeData, components) {
|
||||
const i = parseInt(a);
|
||||
function getIndexFromStart(index, attributeData, components) {
|
||||
const i = parseInt(index);
|
||||
if (i < 0) {
|
||||
// Negative vertex indexes reference the vertices immediately above it
|
||||
return (attributeData.length / components + i) * components;
|
||||
return (attributeData.length / components + i);
|
||||
}
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
function correctAttributeIndices(attributeIndices, attributeData, components) {
|
||||
const length = attributeIndices.length;
|
||||
for (let i = 0; i < length; ++i) {
|
||||
if (attributeIndices[i].length === 0) {
|
||||
attributeIndices[i] = undefined;
|
||||
} else {
|
||||
attributeIndices[i] = getIndexFromStart(attributeIndices[i], attributeData, components);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function correctVertices(vertices, positions, uvs, normals) {
|
||||
const length = vertices.length;
|
||||
for (let i = 0; i < length; ++i) {
|
||||
vertices[i] = defaultValue(positions[i], '') + '/' + defaultValue(uvs[i], '') + '/' + defaultValue(normals[i], '');
|
||||
}
|
||||
return (i - 1) * components;
|
||||
}
|
||||
|
||||
function createVertex(p, u, n) {
|
||||
// Positions
|
||||
if (p.length > 0) {
|
||||
const pi = getOffset(p, positions, 3);
|
||||
const px = positions.get(pi + 0);
|
||||
const py = positions.get(pi + 1);
|
||||
const pz = positions.get(pi + 2);
|
||||
if (defined(p)) {
|
||||
const px = globalPositions.get(p * 3);
|
||||
const py = globalPositions.get(p * 3 + 1);
|
||||
const pz = globalPositions.get(p * 3 + 2);
|
||||
primitive.positions.push(px);
|
||||
primitive.positions.push(py);
|
||||
primitive.positions.push(pz);
|
||||
}
|
||||
|
||||
// Normals
|
||||
if (n.length > 0) {
|
||||
const ni = getOffset(n, normals, 3);
|
||||
const nx = normals.get(ni + 0);
|
||||
const ny = normals.get(ni + 1);
|
||||
const nz = normals.get(ni + 2);
|
||||
if (defined(n)) {
|
||||
const nx = globalNormals.get(n * 3);
|
||||
const ny = globalNormals.get(n * 3 + 1);
|
||||
const nz = globalNormals.get(n * 3 + 2);
|
||||
primitive.normals.push(nx);
|
||||
primitive.normals.push(ny);
|
||||
primitive.normals.push(nz);
|
||||
}
|
||||
|
||||
// UVs
|
||||
if (u.length > 0) {
|
||||
const ui = getOffset(u, uvs, 2);
|
||||
const ux = uvs.get(ui + 0);
|
||||
const uy = uvs.get(ui + 1);
|
||||
if (defined(u)) {
|
||||
const ux = globalUvs.get(u * 2);
|
||||
const uy = globalUvs.get(u * 2 + 1);
|
||||
primitive.uvs.push(ux);
|
||||
primitive.uvs.push(uy);
|
||||
}
|
||||
@ -220,18 +235,16 @@ function loadObj(objPath, options) {
|
||||
}
|
||||
|
||||
function getPosition(index, result) {
|
||||
const pi = getOffset(index, positions, 3);
|
||||
const px = positions.get(pi + 0);
|
||||
const py = positions.get(pi + 1);
|
||||
const pz = positions.get(pi + 2);
|
||||
const px = globalPositions.get(index * 3);
|
||||
const py = globalPositions.get(index * 3 + 1);
|
||||
const pz = globalPositions.get(index * 3 + 2);
|
||||
return Cartesian3.fromElements(px, py, pz, result);
|
||||
}
|
||||
|
||||
function getNormal(index, result) {
|
||||
const ni = getOffset(index, normals, 3);
|
||||
const nx = normals.get(ni + 0);
|
||||
const ny = normals.get(ni + 1);
|
||||
const nz = normals.get(ni + 2);
|
||||
const nx = globalNormals.get(index * 3);
|
||||
const ny = globalNormals.get(index * 3 + 1);
|
||||
const nz = globalNormals.get(index * 3 + 2);
|
||||
return Cartesian3.fromElements(nx, ny, nz, result);
|
||||
}
|
||||
|
||||
@ -249,7 +262,7 @@ function loadObj(objPath, options) {
|
||||
const scratchPoints = [];
|
||||
|
||||
function checkWindingCorrect(positionIndex1, positionIndex2, positionIndex3, normalIndex) {
|
||||
if (normalIndex.length === 0) {
|
||||
if (!defined(normalIndex)) {
|
||||
// If no face normal, we have to assume the winding is correct.
|
||||
return true;
|
||||
}
|
||||
@ -278,7 +291,12 @@ function loadObj(objPath, options) {
|
||||
}
|
||||
|
||||
function addFace(vertices, positions, uvs, normals) {
|
||||
checkPrimitive(uvs, normals);
|
||||
correctAttributeIndices(positions, globalPositions, 3);
|
||||
correctAttributeIndices(normals, globalNormals, 3);
|
||||
correctAttributeIndices(uvs, globalUvs, 2);
|
||||
correctVertices(vertices, positions, uvs, normals);
|
||||
|
||||
checkPrimitive(uvs, faceNormals);
|
||||
|
||||
if (vertices.length === 3) {
|
||||
const isWindingCorrect = checkWindingCorrect(positions[0], positions[1], positions[2], normals[0]);
|
||||
@ -336,9 +354,9 @@ function loadObj(objPath, options) {
|
||||
const mtllibLine = line.substring(7).trim();
|
||||
mtlPaths = mtlPaths.concat(getMtlPaths(mtllibLine));
|
||||
} else if ((result = vertexPattern.exec(line)) !== null) {
|
||||
positions.push(parseFloat(result[1]));
|
||||
positions.push(parseFloat(result[2]));
|
||||
positions.push(parseFloat(result[3]));
|
||||
globalPositions.push(parseFloat(result[1]));
|
||||
globalPositions.push(parseFloat(result[2]));
|
||||
globalPositions.push(parseFloat(result[3]));
|
||||
} else if ((result = normalPattern.exec(line) ) !== null) {
|
||||
const normal = Cartesian3.fromElements(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]), scratchNormal);
|
||||
if (Cartesian3.equals(normal, Cartesian3.ZERO)) {
|
||||
@ -346,12 +364,12 @@ function loadObj(objPath, options) {
|
||||
} else {
|
||||
Cartesian3.normalize(normal, normal);
|
||||
}
|
||||
normals.push(normal.x);
|
||||
normals.push(normal.y);
|
||||
normals.push(normal.z);
|
||||
globalNormals.push(normal.x);
|
||||
globalNormals.push(normal.y);
|
||||
globalNormals.push(normal.z);
|
||||
} else if ((result = uvPattern.exec(line)) !== null) {
|
||||
uvs.push(parseFloat(result[1]));
|
||||
uvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image
|
||||
globalUvs.push(parseFloat(result[1]));
|
||||
globalUvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image
|
||||
} else { // face line or invalid line
|
||||
// Because face lines can contain n vertices, we use a line buffer in case the face data spans multiple lines.
|
||||
// If there's a line continuation don't create face yet
|
||||
@ -386,13 +404,10 @@ function loadObj(objPath, options) {
|
||||
// Parse the obj file
|
||||
return readLines(objPath, parseLine)
|
||||
.then(function() {
|
||||
// Add hasNormals to options object for loadMtl
|
||||
options.hasNormals = normals.length > 0;
|
||||
|
||||
// Unload resources
|
||||
positions = undefined;
|
||||
normals = undefined;
|
||||
uvs = undefined;
|
||||
globalPositions = undefined;
|
||||
globalNormals = undefined;
|
||||
globalUvs = undefined;
|
||||
|
||||
// Load materials and textures
|
||||
return finishLoading(nodes, mtlPaths, objPath, defined(activeMaterial), options);
|
||||
|
@ -9,12 +9,12 @@ v -1.000000 1.000000 -1.000000
|
||||
v 1.000000 -1.000000 1.000000
|
||||
v 1.000000 1.000000 1.000000
|
||||
v 1.000000 -1.000000 -1.000000
|
||||
v 1.000000 1.000000 -1.000000
|
||||
usemtl Material
|
||||
s off
|
||||
f -8 -7 -5 -6
|
||||
f -7 -6 -4 -5
|
||||
f -3 -2 -6 -7
|
||||
f -5 -1 -3 -7
|
||||
v 1.000000 1.000000 -1.000000
|
||||
f -1 -5 -7 -3
|
||||
f -6 -5 -1 -2
|
||||
f -2 -1 -3 -4
|
||||
f -4 -3 -7 -8
|
||||
f -6 -2 -4 -8
|
||||
f -1 -5 -7 -3
|
||||
|
@ -13,8 +13,8 @@ v 1.000000 1.000000 -1.000000
|
||||
usemtl Material
|
||||
s off
|
||||
f 1 2 4 3
|
||||
f 3 4 8 7
|
||||
f 7 8 6 5
|
||||
f 5 6 2 1
|
||||
f 3 7 5 1
|
||||
f 8 4 2 6
|
||||
f 3 4 8 7
|
||||
f 7 8 6 5
|
||||
|
@ -60,7 +60,6 @@ describe('loadMtl', () => {
|
||||
options = clone(obj2gltf.defaults);
|
||||
options.overridingTextures = {};
|
||||
options.logger = () => {};
|
||||
options.hasNormals = true;
|
||||
});
|
||||
|
||||
it('loads mtl', async () => {
|
||||
|
Loading…
Reference in New Issue
Block a user