X Tutup
Skip to content

Commit a948fd7

Browse files
committed
Add support for negative vertex indices in OBJ loader
1 parent a6831ac commit a948fd7

File tree

3 files changed

+59
-11
lines changed

3 files changed

+59
-11
lines changed

src/webgl/loading.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -620,12 +620,10 @@ function parseObj(model, lines, materials= {}) {
620620
const vertString = tokens[vertexTokens[tokenInd]];
621621
let vertParts=vertString.split('/');
622622

623-
// TODO: Faces can technically use negative numbers to refer to the
624-
// previous nth vertex. I haven't seen this used in practice, but
625-
// it might be good to implement this in the future.
626-
627623
for (let i = 0; i < vertParts.length; i++) {
628-
vertParts[i] = parseInt(vertParts[i]) - 1;
624+
let index=parseInt(vertParts[i]);
625+
if (index > 0) index -= 1; // OBJ uses 1-based indexing
626+
vertParts[i]=index;
629627
}
630628

631629
if (!usedVerts[vertString]) {
@@ -634,19 +632,19 @@ function parseObj(model, lines, materials= {}) {
634632

635633
if (usedVerts[vertString][currentMaterial] === undefined) {
636634
const vertIndex = model.vertices.length;
637-
model.vertices.push(loadedVerts.v[vertParts[0]].copy());
638-
model.uvs.push(loadedVerts.vt[vertParts[1]] ?
639-
loadedVerts.vt[vertParts[1]].slice() : [0, 0]);
640-
model.vertexNormals.push(loadedVerts.vn[vertParts[2]] ?
641-
loadedVerts.vn[vertParts[2]].copy() : new p5.Vector());
635+
model.vertices.push(loadedVerts.v.at(vertParts[0]).copy());
636+
model.uvs.push(loadedVerts.vt.at(vertParts[1]) ?
637+
loadedVerts.vt.at(vertParts[1]).slice() : [0, 0]);
638+
model.vertexNormals.push(loadedVerts.vn.at(vertParts[2]) ?
639+
loadedVerts.vn.at(vertParts[2]).copy() : new p5.Vector());
642640

643641
usedVerts[vertString][currentMaterial] = vertIndex;
644642
face.push(vertIndex);
645643
if (currentMaterial
646644
&& materials[currentMaterial]
647645
&& materials[currentMaterial].diffuseColor) {
648646
// Mark this vertex as colored
649-
coloredVerts.add(loadedVerts.v[vertParts[0]]); //since a set would only push unique values
647+
coloredVerts.add(loadedVerts.v.at(vertParts[0])); //since a set would only push unique values
650648
}
651649
} else {
652650
face.push(usedVerts[vertString][currentMaterial]);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Cube using negative vertex indices
2+
# Negative indices count backwards: -1 = last vertex, -2 = second-to-last, etc.
3+
4+
# Vertices
5+
v 0.0 0.0 0.0
6+
v 1.0 0.0 0.0
7+
v 1.0 1.0 0.0
8+
v 0.0 1.0 0.0
9+
v 0.0 0.0 1.0
10+
v 1.0 0.0 1.0
11+
v 1.0 1.0 1.0
12+
v 0.0 1.0 1.0
13+
14+
# Faces using negative indices
15+
f -8 -7 -6 -5
16+
f -4 -3 -2 -1
17+
f -8 -4 -1 -5
18+
f -7 -3 -2 -6
19+
f -5 -6 -2 -1
20+
f -8 -7 -3 -4

test/unit/io/loadModel.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,34 @@ suite('loadModel', function() {
212212
});
213213
assert.instanceOf(model, p5.Geometry);
214214
});
215+
216+
test('OBJ with negative vertex indices loads correctly', async function() {
217+
const model = await promisedSketch(function(sketch, resolve, reject) {
218+
sketch.preload = function() {
219+
sketch.loadModel('unit/assets/cube-negative-indices.obj', resolve, reject);
220+
};
221+
});
222+
assert.instanceOf(model, p5.Geometry);
223+
assert.isAbove(model.vertices.length, 0, 'Model should have vertices');
224+
assert.isAbove(model.faces.length, 0, 'Model should have faces');
225+
});
226+
227+
test('OBJ with negative indices produces same geometry as positive indices', async function() {
228+
const [positiveModel, negativeModel] = await promisedSketch(function(sketch, resolve, reject) {
229+
let positive, negative;
230+
let loaded = 0;
231+
function checkDone() {
232+
loaded++;
233+
if (loaded === 2) resolve([positive, negative]);
234+
}
235+
sketch.preload = function() {
236+
sketch.loadModel('unit/assets/cube.obj', function(m) { positive = m; checkDone(); }, reject);
237+
sketch.loadModel('unit/assets/cube-negative-indices.obj', function(m) { negative = m; checkDone(); }, reject);
238+
};
239+
});
240+
assert.equal(positiveModel.vertices.length, negativeModel.vertices.length,
241+
'Vertex count should match between positive and negative index OBJs');
242+
assert.equal(positiveModel.faces.length, negativeModel.faces.length,
243+
'Face count should match between positive and negative index OBJs');
244+
});
215245
});

0 commit comments

Comments
 (0)
X Tutup