This commit is contained in:
Sean Lilley 2019-05-29 08:50:35 -04:00
parent 601fca2794
commit 0f0bb8296a
6 changed files with 103 additions and 20 deletions

View File

@ -1,6 +1,10 @@
Change Log
==========
### 3.0.3 2019-??-??
* Fixed parsing obj files that contain tabs.
### 3.0.2 2019-03-21
* Fixed a crash when saving separate resources that would exceed the Node buffer size limit. [#173](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/173)

View File

@ -96,7 +96,7 @@ function loadMtl(mtlPath, options) {
if (/^newmtl/i.test(line)) {
const name = line.substring(7).trim();
createMaterial(name);
} else if (/^Ka /i.test(line)) {
} else if (/^Ka\s+/i.test(line)) {
values = line.substring(3).trim().split(' ');
material.ambientColor = [
parseFloat(values[0]),
@ -104,7 +104,7 @@ function loadMtl(mtlPath, options) {
parseFloat(values[2]),
1.0
];
} else if (/^Ke /i.test(line)) {
} else if (/^Ke\s+/i.test(line)) {
values = line.substring(3).trim().split(' ');
material.emissiveColor = [
parseFloat(values[0]),
@ -112,7 +112,7 @@ function loadMtl(mtlPath, options) {
parseFloat(values[2]),
1.0
];
} else if (/^Kd /i.test(line)) {
} else if (/^Kd\s+/i.test(line)) {
values = line.substring(3).trim().split(' ');
material.diffuseColor = [
parseFloat(values[0]),
@ -120,7 +120,7 @@ function loadMtl(mtlPath, options) {
parseFloat(values[2]),
1.0
];
} else if (/^Ks /i.test(line)) {
} else if (/^Ks\s+/i.test(line)) {
values = line.substring(3).trim().split(' ');
material.specularColor = [
parseFloat(values[0]),
@ -128,40 +128,40 @@ function loadMtl(mtlPath, options) {
parseFloat(values[2]),
1.0
];
} else if (/^Ns /i.test(line)) {
} else if (/^Ns\s+/i.test(line)) {
value = line.substring(3).trim();
material.specularShininess = parseFloat(value);
} else if (/^d /i.test(line)) {
} else if (/^d\s+/i.test(line)) {
value = line.substring(2).trim();
material.alpha = correctAlpha(parseFloat(value));
} else if (/^Tr /i.test(line)) {
} else if (/^Tr\s+/i.test(line)) {
value = line.substring(3).trim();
material.alpha = correctAlpha(1.0 - parseFloat(value));
} else if (/^map_Ka /i.test(line)) {
} else if (/^map_Ka\s+/i.test(line)) {
if (!defined(overridingAmbientTexture)) {
material.ambientTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
}
} else if (/^map_Ke /i.test(line)) {
} else if (/^map_Ke\s+/i.test(line)) {
if (!defined(overridingEmissiveTexture)) {
material.emissiveTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
}
} else if (/^map_Kd /i.test(line)) {
} else if (/^map_Kd\s+/i.test(line)) {
if (!defined(overridingDiffuseTexture)) {
material.diffuseTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
}
} else if (/^map_Ks /i.test(line)) {
} else if (/^map_Ks\s+/i.test(line)) {
if (!defined(overridingSpecularTexture)) {
material.specularTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
}
} else if (/^map_Ns /i.test(line)) {
} else if (/^map_Ns\s+/i.test(line)) {
if (!defined(overridingSpecularShininessTexture)) {
material.specularShininessTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
}
} else if (/^map_Bump /i.test(line)) {
} else if (/^map_Bump\s+/i.test(line)) {
if (!defined(overridingNormalTexture)) {
material.normalTexture = normalizeTexturePath(line.substring(9).trim(), mtlDirectory);
}
} else if (/^map_d /i.test(line)) {
} else if (/^map_d\s+/i.test(line)) {
if (!defined(overridingAlphaTexture)) {
material.alphaTexture = normalizeTexturePath(line.substring(6).trim(), mtlDirectory);
}

View File

@ -42,10 +42,11 @@ function Primitive() {
}
// OBJ regex patterns are modified from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js)
const vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // v float float float
const normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vn float float float
const uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vt float float
const vertexPattern = /v(\s+[\d|\.|\+|\-|e|E]+)(\s+[\d|\.|\+|\-|e|E]+)(\s+[\d|\.|\+|\-|e|E]+)/; // v float float float
const normalPattern = /vn(\s+[\d|\.|\+|\-|e|E]+)(\s+[\d|\.|\+|\-|e|E]+)(\s+[\d|\.|\+|\-|e|E]+)/; // vn float float float
const uvPattern = /vt(\s+[\d|\.|\+|\-|e|E]+)(\s+[\d|\.|\+|\-|e|E]+)/; // vt float float
const facePattern = /(-?\d+)\/?(-?\d*)\/?(-?\d*)/g; // for any face format "f v", "f v/v", "f v//v", "f v/v/v"
const faceStartPattern = /f\s+/;
/**
* Parse an obj file.
@ -356,11 +357,11 @@ function loadObj(objPath, options) {
// 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
if (line.slice(-1) === '\\') {
lineBuffer += line.substring(0, line.length-1);
lineBuffer += line.slice(0, -1);
return;
}
lineBuffer += line;
if (lineBuffer.substring(0, 2) === 'f ') {
if (faceStartPattern.test(lineBuffer)) {
while ((result = facePattern.exec(lineBuffer)) !== null) {
faceVertices.push(result[0]);
facePositions.push(result[1]);
@ -402,7 +403,7 @@ function loadObj(objPath, options) {
function getMtlPaths(mtllibLine) {
// Handle paths with spaces. E.g. mtllib my material file.mtl
const mtlPaths = [];
const splits = mtllibLine.split(' ');
const splits = mtllibLine.split(/\s/);
const length = splits.length;
let startIndex = 0;
for (let i = 0; i < length; ++i) {

View File

@ -0,0 +1,12 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl Material
Ns 96.078431
Ka 0.100000 0.000000 0.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.100000
Ni 1.000000
d 1.000000
illum 2

View File

@ -0,0 +1,46 @@
#Blender v2.78 (sub 0) OBJ File: ''
# www.blender.org
mtllib box-tabs.mtl
o Cube
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
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
vt 0.0000 0.0000
vt 1.0000 0.0000
vt 1.0000 1.0000
vt 0.0000 1.0000
vt 0.0000 0.0000
vt 1.0000 0.0000
vt 1.0000 1.0000
vt 0.0000 1.0000
vt 0.0000 0.0000
vt 1.0000 0.0000
vt 1.0000 1.0000
vt 0.0000 1.0000
vt 0.0000 0.0000
vt 1.0000 0.0000
vt 1.0000 1.0000
vt 0.0000 1.0000
vt 1.0000 0.0000
vt 1.0000 1.0000
vt 0.0000 0.0000
vt 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
usemtl Material
s off
f 1/1/1 2/2/1 4/3/1 3/4/1
f 3/5/2 4/6/2 8/7/2 7/8/2
f 7/9/3 8/10/3 6/11/3 5/12/3
f 5/13/4 6/14/4 2/15/4 1/16/4
f 3/5/5 7/17/5 5/18/5 1/16/5
f 8/19/6 4/6/6 2/15/6 6/20/6

View File

@ -10,6 +10,7 @@ const clone = Cesium.clone;
const RuntimeError = Cesium.RuntimeError;
const objPath = 'specs/data/box/box.obj';
const objTabsPath = 'specs/data/box-tabs/box-tabs.obj';
const objNormalsPath = 'specs/data/box-normals/box-normals.obj';
const objUvsPath = 'specs/data/box-uvs/box-uvs.obj';
const objPositionsOnlyPath = 'specs/data/box-positions-only/box-positions-only.obj';
@ -102,6 +103,25 @@ describe('loadObj', () => {
expect(primitive.material).toBe('Material');
});
it('loads obj with tabs', async () => {
const data = await loadObj(objTabsPath, options);
const primitives = getPrimitives(data);
const primitive = primitives[0];
expect(primitive.positions.length / 3).toBe(24);
expect(primitive.normals.length / 3).toBe(24);
expect(primitive.uvs.length / 2).toBe(24);
expect(primitive.indices.length).toBe(36);
expect(primitive.material).toBe('Material');
const material = data.materials[0];
const pbr = material.pbrMetallicRoughness;
expect(pbr.baseColorFactor).toEqual([0.64, 0.64, 0.64, 1.0]);
expect(pbr.metallicFactor).toBe(0.0);
expect(CesiumMath.equalsEpsilon(pbr.roughnessFactor, 0.903921569, CesiumMath.EPSILON7)).toBe(true);
expect(material.emissiveFactor).toEqual([0.0, 0.0, 0.1]);
});
it('loads obj with normals', async () => {
const data = await loadObj(objNormalsPath, options);
const primitive = getPrimitives(data)[0];