mirror of
https://github.com/CesiumGS/obj2gltf.git
synced 2025-02-18 16:43:52 -05:00
Merge pull request #153 from AnalyticalGraphicsInc/fix-uv-error
Remove faces that don't match the same attribute layout
This commit is contained in:
commit
6554214010
@ -1,13 +1,14 @@
|
|||||||
Change Log
|
Change Log
|
||||||
==========
|
==========
|
||||||
|
|
||||||
### 2.3.0 ???
|
### 2.3.0 2018-??-??
|
||||||
|
|
||||||
* Fixed normalization on Windows paths running the converter on Linux. [#150](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/150)
|
* Fixed handling of objs with mismatching attribute layouts. [#153](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/153)
|
||||||
|
* Fixed normalization oo Windows paths when running the converter on Linux. [#150](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/150)
|
||||||
* Added ability to use the first material in the mtl file when the obj is missing `usemtl`. [#133](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/133)
|
* Added ability to use the first material in the mtl file when the obj is missing `usemtl`. [#133](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/133)
|
||||||
* Fixed handling of unnormalized input normals. [#136](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/136)
|
* Fixed handling of unnormalized input normals. [#136](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/136)
|
||||||
|
|
||||||
### 2.2.0 2017-01-29
|
### 2.2.0 2018-01-29
|
||||||
|
|
||||||
* Fixed handling of materials where the diffuse and ambient texture are the same. [#127](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/127)
|
* Fixed handling of materials where the diffuse and ambient texture are the same. [#127](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/127)
|
||||||
* Added ability to load alpha textures. [#124](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/124)
|
* Added ability to load alpha textures. [#124](https://github.com/AnalyticalGraphicsInc/obj2gltf/pull/124)
|
||||||
|
@ -131,10 +131,8 @@ function addBufferView(gltf, buffers, accessors, byteStride, target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addBuffers(gltf, bufferState, name) {
|
function addBuffers(gltf, bufferState, name) {
|
||||||
// Positions and normals share the same byte stride so they can share the same bufferView
|
addBufferView(gltf, bufferState.positionBuffers, bufferState.positionAccessors, 12, WebGLConstants.ARRAY_BUFFER);
|
||||||
var positionsAndNormalsAccessors = bufferState.positionAccessors.concat(bufferState.normalAccessors);
|
addBufferView(gltf, bufferState.normalBuffers, bufferState.normalAccessors, 12, WebGLConstants.ARRAY_BUFFER);
|
||||||
var positionsAndNormalsBuffers = bufferState.positionBuffers.concat(bufferState.normalBuffers);
|
|
||||||
addBufferView(gltf, positionsAndNormalsBuffers, positionsAndNormalsAccessors, 12, WebGLConstants.ARRAY_BUFFER);
|
|
||||||
addBufferView(gltf, bufferState.uvBuffers, bufferState.uvAccessors, 8, WebGLConstants.ARRAY_BUFFER);
|
addBufferView(gltf, bufferState.uvBuffers, bufferState.uvAccessors, 8, WebGLConstants.ARRAY_BUFFER);
|
||||||
addBufferView(gltf, bufferState.indexBuffers, bufferState.indexAccessors, undefined, WebGLConstants.ELEMENT_ARRAY_BUFFER);
|
addBufferView(gltf, bufferState.indexBuffers, bufferState.indexAccessors, undefined, WebGLConstants.ELEMENT_ARRAY_BUFFER);
|
||||||
|
|
||||||
@ -297,68 +295,73 @@ function requiresUint32Indices(nodes) {
|
|||||||
var meshes = nodes[i].meshes;
|
var meshes = nodes[i].meshes;
|
||||||
var meshesLength = meshes.length;
|
var meshesLength = meshes.length;
|
||||||
for (var j = 0; j < meshesLength; ++j) {
|
for (var j = 0; j < meshesLength; ++j) {
|
||||||
// Reserve the 65535 index for primitive restart
|
var primitives = meshes[j].primitives;
|
||||||
var vertexCount = meshes[j].positions.length / 3;
|
var primitivesLength = primitives.length;
|
||||||
if (vertexCount > 65534) {
|
for (var k = 0; k < primitivesLength; ++k) {
|
||||||
return true;
|
// Reserve the 65535 index for primitive restart
|
||||||
|
var vertexCount = primitives[k].positions.length / 3;
|
||||||
|
if (vertexCount > 65534) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMesh(gltf, materials, bufferState, uint32Indices, mesh, options) {
|
function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitive, index, options) {
|
||||||
var hasPositions = mesh.positions.length > 0;
|
var hasPositions = primitive.positions.length > 0;
|
||||||
var hasNormals = mesh.normals.length > 0;
|
var hasNormals = primitive.normals.length > 0;
|
||||||
var hasUVs = mesh.uvs.length > 0;
|
var hasUVs = primitive.uvs.length > 0;
|
||||||
|
|
||||||
// Vertex attributes are shared by all primitives in the mesh
|
|
||||||
var accessorIndex;
|
var accessorIndex;
|
||||||
var attributes = {};
|
var attributes = {};
|
||||||
if (hasPositions) {
|
if (hasPositions) {
|
||||||
accessorIndex = addVertexAttribute(gltf, mesh.positions, 3, mesh.name + '_positions');
|
accessorIndex = addVertexAttribute(gltf, primitive.positions, 3, mesh.name + '_' + index + '_positions');
|
||||||
attributes.POSITION = accessorIndex;
|
attributes.POSITION = accessorIndex;
|
||||||
bufferState.positionBuffers.push(mesh.positions.toFloatBuffer());
|
bufferState.positionBuffers.push(primitive.positions.toFloatBuffer());
|
||||||
bufferState.positionAccessors.push(accessorIndex);
|
bufferState.positionAccessors.push(accessorIndex);
|
||||||
}
|
}
|
||||||
if (hasNormals) {
|
if (hasNormals) {
|
||||||
accessorIndex = addVertexAttribute(gltf, mesh.normals, 3, mesh.name + '_normals');
|
accessorIndex = addVertexAttribute(gltf, primitive.normals, 3, mesh.name + '_' + index + '_normals');
|
||||||
attributes.NORMAL = accessorIndex;
|
attributes.NORMAL = accessorIndex;
|
||||||
bufferState.normalBuffers.push(mesh.normals.toFloatBuffer());
|
bufferState.normalBuffers.push(primitive.normals.toFloatBuffer());
|
||||||
bufferState.normalAccessors.push(accessorIndex);
|
bufferState.normalAccessors.push(accessorIndex);
|
||||||
}
|
}
|
||||||
if (hasUVs) {
|
if (hasUVs) {
|
||||||
accessorIndex = addVertexAttribute(gltf, mesh.uvs, 2, mesh.name + '_texcoords');
|
accessorIndex = addVertexAttribute(gltf, primitive.uvs, 2, mesh.name + '_' + index + '_texcoords');
|
||||||
attributes.TEXCOORD_0 = accessorIndex;
|
attributes.TEXCOORD_0 = accessorIndex;
|
||||||
bufferState.uvBuffers.push(mesh.uvs.toFloatBuffer());
|
bufferState.uvBuffers.push(primitive.uvs.toFloatBuffer());
|
||||||
bufferState.uvAccessors.push(accessorIndex);
|
bufferState.uvAccessors.push(accessorIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload resources
|
var indexAccessorIndex = addIndexArray(gltf, primitive.indices, uint32Indices, mesh.name + '_' + index + '_indices');
|
||||||
mesh.positions = undefined;
|
var indexBuffer = uint32Indices ? primitive.indices.toUint32Buffer() : primitive.indices.toUint16Buffer();
|
||||||
mesh.normals = undefined;
|
bufferState.indexBuffers.push(indexBuffer);
|
||||||
mesh.uvs = undefined;
|
bufferState.indexAccessors.push(indexAccessorIndex);
|
||||||
|
|
||||||
|
// Unload resources
|
||||||
|
primitive.positions = undefined;
|
||||||
|
primitive.normals = undefined;
|
||||||
|
primitive.uvs = undefined;
|
||||||
|
primitive.indices = undefined;
|
||||||
|
|
||||||
|
var materialIndex = getMaterial(gltf, materials, primitive.material, options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
attributes : attributes,
|
||||||
|
indices : indexAccessorIndex,
|
||||||
|
material : materialIndex,
|
||||||
|
mode : WebGLConstants.TRIANGLES
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMesh(gltf, materials, bufferState, uint32Indices, mesh, options) {
|
||||||
var gltfPrimitives = [];
|
var gltfPrimitives = [];
|
||||||
var primitives = mesh.primitives;
|
var primitives = mesh.primitives;
|
||||||
var primitivesLength = primitives.length;
|
var primitivesLength = primitives.length;
|
||||||
for (var i = 0; i < primitivesLength; ++i) {
|
for (var i = 0; i < primitivesLength; ++i) {
|
||||||
var primitive = primitives[i];
|
gltfPrimitives.push(addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitives[i], i, options));
|
||||||
var indexAccessorIndex = addIndexArray(gltf, primitive.indices, uint32Indices, mesh.name + '_' + i + '_indices');
|
|
||||||
var indexBuffer = uint32Indices ? primitive.indices.toUint32Buffer() : primitive.indices.toUint16Buffer();
|
|
||||||
bufferState.indexBuffers.push(indexBuffer);
|
|
||||||
bufferState.indexAccessors.push(indexAccessorIndex);
|
|
||||||
|
|
||||||
primitive.indices = undefined; // Unload resources
|
|
||||||
|
|
||||||
var materialIndex = getMaterial(gltf, materials, primitive.material, options);
|
|
||||||
|
|
||||||
gltfPrimitives.push({
|
|
||||||
attributes : attributes,
|
|
||||||
indices : indexAccessorIndex,
|
|
||||||
material : materialIndex,
|
|
||||||
mode : WebGLConstants.TRIANGLES
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var gltfMesh = {
|
var gltfMesh = {
|
||||||
|
@ -36,14 +36,14 @@ function Node() {
|
|||||||
function Mesh() {
|
function Mesh() {
|
||||||
this.name = undefined;
|
this.name = undefined;
|
||||||
this.primitives = [];
|
this.primitives = [];
|
||||||
this.positions = new ArrayStorage(ComponentDatatype.FLOAT);
|
|
||||||
this.normals = new ArrayStorage(ComponentDatatype.FLOAT);
|
|
||||||
this.uvs = new ArrayStorage(ComponentDatatype.FLOAT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Primitive() {
|
function Primitive() {
|
||||||
this.material = undefined;
|
this.material = undefined;
|
||||||
this.indices = new ArrayStorage(ComponentDatatype.UNSIGNED_INT);
|
this.indices = new ArrayStorage(ComponentDatatype.UNSIGNED_INT);
|
||||||
|
this.positions = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
this.normals = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
this.uvs = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// OBJ regex patterns are modified from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js)
|
// OBJ regex patterns are modified from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js)
|
||||||
@ -76,7 +76,7 @@ function loadObj(objPath, options) {
|
|||||||
// All nodes seen in the obj
|
// All nodes seen in the obj
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
|
|
||||||
// Used to build the indices. The vertex cache is unique to each mesh.
|
// Used to build the indices. The vertex cache is unique to each primitive.
|
||||||
var vertexCache = {};
|
var vertexCache = {};
|
||||||
var vertexCacheLimit = 1000000;
|
var vertexCacheLimit = 1000000;
|
||||||
var vertexCacheCount = 0;
|
var vertexCacheCount = 0;
|
||||||
@ -112,17 +112,17 @@ function loadObj(objPath, options) {
|
|||||||
mesh.name = getName(name);
|
mesh.name = getName(name);
|
||||||
node.meshes.push(mesh);
|
node.meshes.push(mesh);
|
||||||
addPrimitive();
|
addPrimitive();
|
||||||
|
|
||||||
// Clear the vertex cache for each new mesh
|
|
||||||
vertexCache = {};
|
|
||||||
vertexCacheCount = 0;
|
|
||||||
vertexCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPrimitive() {
|
function addPrimitive() {
|
||||||
primitive = new Primitive();
|
primitive = new Primitive();
|
||||||
primitive.material = activeMaterial;
|
primitive.material = activeMaterial;
|
||||||
mesh.primitives.push(primitive);
|
mesh.primitives.push(primitive);
|
||||||
|
|
||||||
|
// Clear the vertex cache for each new primitive
|
||||||
|
vertexCache = {};
|
||||||
|
vertexCacheCount = 0;
|
||||||
|
vertexCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useMaterial(name) {
|
function useMaterial(name) {
|
||||||
@ -158,9 +158,9 @@ function loadObj(objPath, options) {
|
|||||||
var px = positions.get(pi + 0);
|
var px = positions.get(pi + 0);
|
||||||
var py = positions.get(pi + 1);
|
var py = positions.get(pi + 1);
|
||||||
var pz = positions.get(pi + 2);
|
var pz = positions.get(pi + 2);
|
||||||
mesh.positions.push(px);
|
primitive.positions.push(px);
|
||||||
mesh.positions.push(py);
|
primitive.positions.push(py);
|
||||||
mesh.positions.push(pz);
|
primitive.positions.push(pz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normals
|
// Normals
|
||||||
@ -169,9 +169,9 @@ function loadObj(objPath, options) {
|
|||||||
var nx = normals.get(ni + 0);
|
var nx = normals.get(ni + 0);
|
||||||
var ny = normals.get(ni + 1);
|
var ny = normals.get(ni + 1);
|
||||||
var nz = normals.get(ni + 2);
|
var nz = normals.get(ni + 2);
|
||||||
mesh.normals.push(nx);
|
primitive.normals.push(nx);
|
||||||
mesh.normals.push(ny);
|
primitive.normals.push(ny);
|
||||||
mesh.normals.push(nz);
|
primitive.normals.push(nz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UVs
|
// UVs
|
||||||
@ -179,8 +179,8 @@ function loadObj(objPath, options) {
|
|||||||
var ui = getOffset(u, uvs, 2);
|
var ui = getOffset(u, uvs, 2);
|
||||||
var ux = uvs.get(ui + 0);
|
var ux = uvs.get(ui + 0);
|
||||||
var uy = uvs.get(ui + 1);
|
var uy = uvs.get(ui + 1);
|
||||||
mesh.uvs.push(ux);
|
primitive.uvs.push(ux);
|
||||||
mesh.uvs.push(uy);
|
primitive.uvs.push(uy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,6 +373,17 @@ function loadObj(objPath, options) {
|
|||||||
var isWindingCorrect = true;
|
var isWindingCorrect = true;
|
||||||
var faceNormal;
|
var faceNormal;
|
||||||
|
|
||||||
|
var firstFace = primitive.indices.length === 0;
|
||||||
|
var faceHasUvs = uvs[0].length > 0;
|
||||||
|
var faceHasNormals = normals[0].length > 0;
|
||||||
|
var primitiveHasUvs = primitive.uvs.length > 0;
|
||||||
|
var primitiveHasNormals = primitive.normals.length > 0;
|
||||||
|
|
||||||
|
if (!firstFace && (faceHasUvs !== primitiveHasUvs || faceHasNormals !== primitiveHasNormals)) {
|
||||||
|
// Discard faces that don't use the same attributes
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If normals are defined, find a face normal to use in winding order sanitization.
|
// If normals are defined, find a face normal to use in winding order sanitization.
|
||||||
// If no face normal, we have to assume the winding is correct.
|
// If no face normal, we have to assume the winding is correct.
|
||||||
if (normals[0].length > 0) {
|
if (normals[0].length > 0) {
|
||||||
@ -502,7 +513,7 @@ function loadObj(objPath, options) {
|
|||||||
uvs = undefined;
|
uvs = undefined;
|
||||||
|
|
||||||
// Load materials and textures
|
// Load materials and textures
|
||||||
return finishLoading(nodes, mtlPaths, objPath, options);
|
return finishLoading(nodes, mtlPaths, objPath, defined(activeMaterial), options);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +534,7 @@ function getMtlPaths(mtllibLine) {
|
|||||||
return mtlPaths;
|
return mtlPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishLoading(nodes, mtlPaths, objPath, options) {
|
function finishLoading(nodes, mtlPaths, objPath, usesMaterials, options) {
|
||||||
nodes = cleanNodes(nodes);
|
nodes = cleanNodes(nodes);
|
||||||
if (nodes.length === 0) {
|
if (nodes.length === 0) {
|
||||||
throw new RuntimeError(objPath + ' does not have any geometry data');
|
throw new RuntimeError(objPath + ' does not have any geometry data');
|
||||||
@ -531,7 +542,9 @@ function finishLoading(nodes, mtlPaths, objPath, options) {
|
|||||||
var name = path.basename(objPath, path.extname(objPath));
|
var name = path.basename(objPath, path.extname(objPath));
|
||||||
return loadMtls(mtlPaths, objPath, options)
|
return loadMtls(mtlPaths, objPath, options)
|
||||||
.then(function(materials) {
|
.then(function(materials) {
|
||||||
assignDefaultMaterial(nodes, materials);
|
if (materials.length > 0 && !usesMaterials) {
|
||||||
|
assignDefaultMaterial(nodes, materials, usesMaterials);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
nodes : nodes,
|
nodes : nodes,
|
||||||
materials : materials,
|
materials : materials,
|
||||||
@ -591,9 +604,6 @@ function loadMtls(mtlPaths, objPath, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function assignDefaultMaterial(nodes, materials) {
|
function assignDefaultMaterial(nodes, materials) {
|
||||||
if (materials.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var defaultMaterial = materials[0].name;
|
var defaultMaterial = materials[0].name;
|
||||||
var nodesLength = nodes.length;
|
var nodesLength = nodes.length;
|
||||||
for (var i = 0; i < nodesLength; ++i) {
|
for (var i = 0; i < nodesLength; ++i) {
|
||||||
@ -614,10 +624,10 @@ function removeEmptyMeshes(meshes) {
|
|||||||
return meshes.filter(function(mesh) {
|
return meshes.filter(function(mesh) {
|
||||||
// Remove empty primitives
|
// Remove empty primitives
|
||||||
mesh.primitives = mesh.primitives.filter(function(primitive) {
|
mesh.primitives = mesh.primitives.filter(function(primitive) {
|
||||||
return primitive.indices.length > 0;
|
return primitive.indices.length > 0 && primitive.positions.length > 0;
|
||||||
});
|
});
|
||||||
// Valid meshes must have at least one primitive and contain positions
|
// Valid meshes must have at least one primitive
|
||||||
return (mesh.primitives.length > 0) && (mesh.positions.length > 0);
|
return (mesh.primitives.length > 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
specs/data/box-mixed-attributes/box-mixed-attributes.mtl
Normal file
12
specs/data/box-mixed-attributes/box-mixed-attributes.mtl
Normal 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
|
46
specs/data/box-mixed-attributes/box-mixed-attributes.obj
Normal file
46
specs/data/box-mixed-attributes/box-mixed-attributes.obj
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Blender v2.78 (sub 0) OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-mixed-attributes.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 4 8 7
|
||||||
|
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 7//5 5//5 1//5
|
||||||
|
f 8/19 4/6 2/15 6/20
|
@ -133,42 +133,42 @@ describe('createGltf', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('runs without normals', function() {
|
it('runs without normals', function() {
|
||||||
boxObjData.nodes[0].meshes[0].normals.length = 0;
|
boxObjData.nodes[0].meshes[0].primitives[0].normals.length = 0;
|
||||||
|
|
||||||
var gltf = createGltf(boxObjData, options);
|
var gltf = createGltf(boxObjData, options);
|
||||||
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
|
var attributes = gltf.meshes[0].primitives[0].attributes;
|
||||||
expect(attributes.POSITION).toBeDefined();
|
expect(attributes.POSITION).toBeDefined();
|
||||||
expect(attributes.NORMAL).toBeUndefined();
|
expect(attributes.NORMAL).toBeUndefined();
|
||||||
expect(attributes.TEXCOORD_0).toBeDefined();
|
expect(attributes.TEXCOORD_0).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs without uvs', function() {
|
it('runs without uvs', function() {
|
||||||
boxObjData.nodes[0].meshes[0].uvs.length = 0;
|
boxObjData.nodes[0].meshes[0].primitives[0].uvs.length = 0;
|
||||||
|
|
||||||
var gltf = createGltf(boxObjData, options);
|
var gltf = createGltf(boxObjData, options);
|
||||||
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
|
var attributes = gltf.meshes[0].primitives[0].attributes;
|
||||||
expect(attributes.POSITION).toBeDefined();
|
expect(attributes.POSITION).toBeDefined();
|
||||||
expect(attributes.NORMAL).toBeDefined();
|
expect(attributes.NORMAL).toBeDefined();
|
||||||
expect(attributes.TEXCOORD_0).toBeUndefined();
|
expect(attributes.TEXCOORD_0).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs without uvs and normals', function() {
|
it('runs without uvs and normals', function() {
|
||||||
boxObjData.nodes[0].meshes[0].normals.length = 0;
|
boxObjData.nodes[0].meshes[0].primitives[0].normals.length = 0;
|
||||||
boxObjData.nodes[0].meshes[0].uvs.length = 0;
|
boxObjData.nodes[0].meshes[0].primitives[0].uvs.length = 0;
|
||||||
|
|
||||||
var gltf = createGltf(boxObjData, options);
|
var gltf = createGltf(boxObjData, options);
|
||||||
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
|
var attributes = gltf.meshes[0].primitives[0].attributes;
|
||||||
expect(attributes.POSITION).toBeDefined();
|
expect(attributes.POSITION).toBeDefined();
|
||||||
expect(attributes.NORMAL).toBeUndefined();
|
expect(attributes.NORMAL).toBeUndefined();
|
||||||
expect(attributes.TEXCOORD_0).toBeUndefined();
|
expect(attributes.TEXCOORD_0).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
function expandObjData(objData, duplicatesLength) {
|
function expandObjData(objData, duplicatesLength) {
|
||||||
var mesh = objData.nodes[0].meshes[0];
|
var primitive = objData.nodes[0].meshes[0].primitives[0];
|
||||||
var indices = mesh.primitives[0].indices;
|
var indices = primitive.indices;
|
||||||
var positions = mesh.positions;
|
var positions = primitive.positions;
|
||||||
var normals = mesh.normals;
|
var normals = primitive.normals;
|
||||||
var uvs = mesh.uvs;
|
var uvs = primitive.uvs;
|
||||||
|
|
||||||
var indicesLength = indices.length;
|
var indicesLength = indices.length;
|
||||||
var vertexCount = positions.length / 3;
|
var vertexCount = positions.length / 3;
|
||||||
@ -192,12 +192,12 @@ describe('createGltf', function() {
|
|||||||
|
|
||||||
it('detects need to use uint32 indices', function() {
|
it('detects need to use uint32 indices', function() {
|
||||||
expandObjData(boxObjData, 2731); // Right above 65536 limit
|
expandObjData(boxObjData, 2731); // Right above 65536 limit
|
||||||
var mesh = boxObjData.nodes[0].meshes[0];
|
var primitive = boxObjData.nodes[0].meshes[0].primitives[0];
|
||||||
var indicesLength = mesh.primitives[0].indices.length;
|
var indicesLength = primitive.indices.length;
|
||||||
var vertexCount = mesh.positions.length / 3;
|
var vertexCount = primitive.positions.length / 3;
|
||||||
|
|
||||||
var gltf = createGltf(boxObjData, options);
|
var gltf = createGltf(boxObjData, options);
|
||||||
var primitive = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0];
|
primitive = gltf.meshes[0].primitives[0];
|
||||||
var indicesAccessor = gltf.accessors[primitive.indices];
|
var indicesAccessor = gltf.accessors[primitive.indices];
|
||||||
expect(indicesAccessor.count).toBe(indicesLength);
|
expect(indicesAccessor.count).toBe(indicesLength);
|
||||||
expect(indicesAccessor.max[0]).toBe(vertexCount - 1);
|
expect(indicesAccessor.max[0]).toBe(vertexCount - 1);
|
||||||
|
@ -38,6 +38,7 @@ var objWindowsPaths = 'specs/data/box-windows-paths/box-windows-paths.obj';
|
|||||||
var objInvalidContentsPath = 'specs/data/box/box.mtl';
|
var objInvalidContentsPath = 'specs/data/box/box.mtl';
|
||||||
var objConcavePath = 'specs/data/concave/concave.obj';
|
var objConcavePath = 'specs/data/concave/concave.obj';
|
||||||
var objUnnormalizedPath = 'specs/data/box-unnormalized/box-unnormalized.obj';
|
var objUnnormalizedPath = 'specs/data/box-unnormalized/box-unnormalized.obj';
|
||||||
|
var objMixedAttributesPath = 'specs/data/box-mixed-attributes/box-mixed-attributes.obj';
|
||||||
var objInvalidPath = 'invalid.obj';
|
var objInvalidPath = 'invalid.obj';
|
||||||
|
|
||||||
function getMeshes(data) {
|
function getMeshes(data) {
|
||||||
@ -94,9 +95,9 @@ describe('loadObj', function() {
|
|||||||
|
|
||||||
expect(node.name).toBe('Cube');
|
expect(node.name).toBe('Cube');
|
||||||
expect(mesh.name).toBe('Cube-Mesh');
|
expect(mesh.name).toBe('Cube-Mesh');
|
||||||
expect(mesh.positions.length / 3).toBe(24);
|
expect(primitive.positions.length / 3).toBe(24);
|
||||||
expect(mesh.normals.length / 3).toBe(24);
|
expect(primitive.normals.length / 3).toBe(24);
|
||||||
expect(mesh.uvs.length / 2).toBe(24);
|
expect(primitive.uvs.length / 2).toBe(24);
|
||||||
expect(primitive.indices.length).toBe(36);
|
expect(primitive.indices.length).toBe(36);
|
||||||
expect(primitive.material).toBe('Material');
|
expect(primitive.material).toBe('Material');
|
||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
@ -105,10 +106,10 @@ describe('loadObj', function() {
|
|||||||
it('loads obj with normals', function(done) {
|
it('loads obj with normals', function(done) {
|
||||||
expect(loadObj(objNormalsPath, options)
|
expect(loadObj(objNormalsPath, options)
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
var mesh = getMeshes(data)[0];
|
var primitive = getPrimitives(data)[0];
|
||||||
expect(mesh.positions.length / 3).toBe(24);
|
expect(primitive.positions.length / 3).toBe(24);
|
||||||
expect(mesh.normals.length / 3).toBe(24);
|
expect(primitive.normals.length / 3).toBe(24);
|
||||||
expect(mesh.uvs.length / 2).toBe(0);
|
expect(primitive.uvs.length / 2).toBe(0);
|
||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -116,8 +117,8 @@ describe('loadObj', function() {
|
|||||||
expect(loadObj(objUnnormalizedPath, options)
|
expect(loadObj(objUnnormalizedPath, options)
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
var scratchNormal = new Cesium.Cartesian3();
|
var scratchNormal = new Cesium.Cartesian3();
|
||||||
var mesh = getMeshes(data)[0];
|
var primitive = getPrimitives(data)[0];
|
||||||
var normals = mesh.normals;
|
var normals = primitive.normals;
|
||||||
var normalsLength = normals.length / 3;
|
var normalsLength = normals.length / 3;
|
||||||
for (var i = 0; i < normalsLength; ++i) {
|
for (var i = 0; i < normalsLength; ++i) {
|
||||||
var normalX = normals.get(i * 3);
|
var normalX = normals.get(i * 3);
|
||||||
@ -132,10 +133,10 @@ describe('loadObj', function() {
|
|||||||
it('loads obj with uvs', function(done) {
|
it('loads obj with uvs', function(done) {
|
||||||
expect(loadObj(objUvsPath, options)
|
expect(loadObj(objUvsPath, options)
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
var mesh = getMeshes(data)[0];
|
var primitive = getPrimitives(data)[0];
|
||||||
expect(mesh.positions.length / 3).toBe(20);
|
expect(primitive.positions.length / 3).toBe(20);
|
||||||
expect(mesh.normals.length / 3).toBe(0);
|
expect(primitive.normals.length / 3).toBe(0);
|
||||||
expect(mesh.uvs.length / 2).toBe(20);
|
expect(primitive.uvs.length / 2).toBe(20);
|
||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -145,8 +146,8 @@ describe('loadObj', function() {
|
|||||||
loadObj(objNegativeIndicesPath, options)
|
loadObj(objNegativeIndicesPath, options)
|
||||||
])
|
])
|
||||||
.then(function(results) {
|
.then(function(results) {
|
||||||
var positionsReference = getMeshes(results[0])[0].positions.toFloatBuffer();
|
var positionsReference = getPrimitives(results[0])[0].positions.toFloatBuffer();
|
||||||
var positions = getMeshes(results[1])[0].positions.toFloatBuffer();
|
var positions = getPrimitives(results[1])[0].positions.toFloatBuffer();
|
||||||
expect(positions).toEqual(positionsReference);
|
expect(positions).toEqual(positionsReference);
|
||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
});
|
});
|
||||||
@ -154,9 +155,8 @@ describe('loadObj', function() {
|
|||||||
it('loads obj with triangle faces', function(done) {
|
it('loads obj with triangle faces', function(done) {
|
||||||
expect(loadObj(objTrianglesPath, options)
|
expect(loadObj(objTrianglesPath, options)
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
var mesh = getMeshes(data)[0];
|
|
||||||
var primitive = getPrimitives(data)[0];
|
var primitive = getPrimitives(data)[0];
|
||||||
expect(mesh.positions.length / 3).toBe(24);
|
expect(primitive.positions.length / 3).toBe(24);
|
||||||
expect(primitive.indices.length).toBe(36);
|
expect(primitive.indices.length).toBe(36);
|
||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
});
|
});
|
||||||
@ -256,9 +256,8 @@ describe('loadObj', function() {
|
|||||||
it('loads obj with concave face containing 5 vertices', function(done) {
|
it('loads obj with concave face containing 5 vertices', function(done) {
|
||||||
expect(loadObj(objConcavePath, options)
|
expect(loadObj(objConcavePath, options)
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
var mesh = getMeshes(data)[0];
|
|
||||||
var primitive = getPrimitives(data)[0];
|
var primitive = getPrimitives(data)[0];
|
||||||
expect(mesh.positions.length / 3).toBe(30);
|
expect(primitive.positions.length / 3).toBe(30);
|
||||||
expect(primitive.indices.length).toBe(48);
|
expect(primitive.indices.length).toBe(48);
|
||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
});
|
});
|
||||||
@ -488,6 +487,14 @@ describe('loadObj', function() {
|
|||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('discards faces that don\'t use the same attributes as other faces in the primitive', function(done) {
|
||||||
|
expect(loadObj(objMixedAttributesPath, options)
|
||||||
|
.then(function(data) {
|
||||||
|
var primitive = getPrimitives(data)[0];
|
||||||
|
expect(primitive.indices.length).toBe(18); // 3 faces removed
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
it('throws when file has invalid contents', function(done) {
|
it('throws when file has invalid contents', function(done) {
|
||||||
expect(loadObj(objInvalidContentsPath, options), done).toRejectWith(RuntimeError);
|
expect(loadObj(objInvalidContentsPath, options), done).toRejectWith(RuntimeError);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user