obj2gltf/specs/lib/createGltfSpec.js
Matthew Amato f141c2d9c9 Update npm dependencies
A few npm dependencies were major versions behind, so this updates `yargs`,
`fs-extra`, and `jasmin-spec-reporter` to their latest versions.

The major change here is `fs-extra`, which now has promise implementations
of all functions by default, this means there's no reason to manually
`Promisify` a function any more, the result is less code overall.

There is one important edge case, `fs-extra` uses built-in native Node
promises, which do not have a `finally` function. If you start a promise
change with an `fs-extra` function, you need to wrap it in `Promise.resolve`
in order to make use of finally at the end (assuming you are using finally
at all, if not you don't need to worry about it. The upside is that your
code will always error if you forget to do this.
2017-05-19 11:37:33 -04:00

370 lines
14 KiB
JavaScript

'use strict';
var Cesium = require('cesium');
var fsExtra = require('fs-extra');
var path = require('path');
var Promise = require('bluebird');
var obj2gltf = require('../../lib/obj2gltf');
var createGltf = require('../../lib/createGltf');
var loadImage = require('../../lib/loadImage');
var loadObj = require('../../lib/loadObj');
var Material = require('../../lib/Material');
var writeUris = require('../../lib/writeUris');
var clone = Cesium.clone;
var WebGLConstants = Cesium.WebGLConstants;
var boxObjUrl = 'specs/data/box/box.obj';
var groupObjUrl = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj';
var boxGltfUrl = 'specs/data/box/box.gltf';
var groupGltfUrl = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.gltf';
var diffuseTextureUrl = 'specs/data/box-textured/cesium.png';
var transparentDiffuseTextureUrl = 'specs/data/box-complex-material/diffuse.png';
var defaultOptions = obj2gltf.defaults;
var checkTransparencyOptions = clone(defaultOptions);
checkTransparencyOptions.checkTransparency = true;
describe('createGltf', function() {
var boxObjData;
var duplicateBoxObjData;
var groupObjData;
var boxGltf;
var groupGltf;
var diffuseTexture;
var transparentDiffuseTexture;
beforeEach(function(done) {
return Promise.all([
loadObj(boxObjUrl, defaultOptions)
.then(function(data) {
boxObjData = data;
}),
loadObj(boxObjUrl, defaultOptions)
.then(function(data) {
duplicateBoxObjData = data;
}),
loadObj(groupObjUrl, defaultOptions)
.then(function(data) {
groupObjData = data;
}),
fsExtra.readJson(boxGltfUrl)
.then(function(gltf) {
boxGltf = gltf;
}),
fsExtra.readJson(groupGltfUrl)
.then(function(gltf) {
groupGltf = gltf;
}),
loadImage(diffuseTextureUrl, defaultOptions)
.then(function(image) {
diffuseTexture = image;
}),
loadImage(transparentDiffuseTextureUrl, checkTransparencyOptions)
.then(function(image) {
transparentDiffuseTexture = image;
})
]).then(done);
});
it('simple gltf', function(done) {
var gltf = createGltf(boxObjData);
expect(writeUris(gltf, boxGltfUrl, path.dirname(boxGltfUrl), defaultOptions)
.then(function() {
expect(gltf).toEqual(boxGltf);
}), done).toResolve();
});
it('multiple nodes, meshes, and primitives', function(done) {
var gltf = createGltf(groupObjData);
expect(writeUris(gltf, groupGltfUrl, path.dirname(groupGltfUrl), defaultOptions)
.then(function() {
expect(gltf).toEqual(groupGltf);
expect(Object.keys(gltf.materials).length).toBe(3);
expect(Object.keys(gltf.nodes).length).toBe(1);
expect(Object.keys(gltf.meshes).length).toBe(3);
// Check for two primitives in each mesh
for (var id in gltf.meshes) {
if (gltf.meshes.hasOwnProperty(id)) {
var mesh = gltf.meshes[id];
expect(mesh.primitives.length).toBe(2);
}
}
}), done).toResolve();
});
it('sets default material values', function() {
boxObjData.materials.Material = new Material();
var gltf = createGltf(boxObjData);
var material = gltf.materials.Material;
var kmc = material.extensions.KHR_materials_common;
var values = kmc.values;
expect(kmc.technique).toBe('LAMBERT');
expect(values.ambient).toEqual([0.0, 0.0, 0.0, 1]);
expect(values.diffuse).toEqual([0.5, 0.5, 0.5, 1]);
expect(values.emission).toEqual([0.0, 0.0, 0.0, 1]);
expect(values.specular).toEqual([0.0, 0.0, 0.0, 1]);
expect(values.shininess).toEqual(0.0);
});
it('sets material for diffuse texture', function() {
var material = new Material();
material.diffuseTexture = diffuseTextureUrl;
boxObjData.materials.Material = material;
boxObjData.images[diffuseTextureUrl] = diffuseTexture;
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
var texture = gltf.textures.texture_cesium;
var image = gltf.images.cesium;
expect(kmc.technique).toBe('LAMBERT');
expect(kmc.values.diffuse).toEqual('texture_cesium');
expect(kmc.values.transparency).toBe(1.0);
expect(kmc.values.transparent).toBe(false);
expect(kmc.values.doubleSided).toBe(false);
expect(texture).toEqual({
format : WebGLConstants.RGB,
internalFormat : WebGLConstants.RGB,
sampler : 'sampler',
source : 'cesium',
target : WebGLConstants.TEXTURE_2D,
type : WebGLConstants.UNSIGNED_BYTE
});
expect(image).toBeDefined();
expect(image.name).toBe('cesium');
expect(image.extras._obj2gltf.source).toBeDefined();
expect(image.extras._obj2gltf.extension).toBe('.png');
expect(gltf.samplers.sampler).toEqual({
magFilter : WebGLConstants.LINEAR,
minFilter : WebGLConstants.LINEAR,
wrapS : WebGLConstants.REPEAT,
wrapT : WebGLConstants.REPEAT
});
});
it('sets material for alpha less than 1', function() {
var material = new Material();
material.alpha = 0.4;
boxObjData.materials.Material = material;
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 0.4]);
expect(kmc.values.transparency).toBe(1.0);
expect(kmc.values.transparent).toBe(true);
expect(kmc.values.doubleSided).toBe(true);
});
it('sets material for diffuse texture and alpha less than 1', function() {
var material = new Material();
material.diffuseTexture = diffuseTextureUrl;
material.alpha = 0.4;
boxObjData.materials.Material = material;
boxObjData.images[diffuseTextureUrl] = diffuseTexture;
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
expect(kmc.values.diffuse).toEqual('texture_cesium');
expect(kmc.values.transparency).toBe(0.4);
expect(kmc.values.transparent).toBe(true);
expect(kmc.values.doubleSided).toBe(true);
});
it('sets material for transparent diffuse texture', function() {
var material = new Material();
material.diffuseTexture = transparentDiffuseTextureUrl;
boxObjData.materials.Material = material;
boxObjData.images[transparentDiffuseTextureUrl] = transparentDiffuseTexture;
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
expect(kmc.values.diffuse).toBe('texture_diffuse');
expect(kmc.values.transparency).toBe(1.0);
expect(kmc.values.transparent).toBe(true);
expect(kmc.values.doubleSided).toBe(true);
});
it('sets material for specular', function() {
var material = new Material();
material.specularColor = [0.1, 0.1, 0.2, 1];
material.specularShininess = 0.1;
boxObjData.materials.Material = material;
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
expect(kmc.technique).toBe('PHONG');
expect(kmc.values.specular).toEqual([0.1, 0.1, 0.2, 1]);
expect(kmc.values.shininess).toEqual(0.1);
});
it('sets constant material when there are no normals', function() {
boxObjData.nodes[0].meshes[0].normals.length = 0;
var material = new Material();
material.diffuseTexture = diffuseTextureUrl;
boxObjData.materials.Material = material;
boxObjData.images[diffuseTextureUrl] = diffuseTexture;
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
expect(kmc.technique).toBe('CONSTANT');
expect(kmc.values.emission).toEqual('texture_cesium');
});
it('sets default material when texture is missing', function() {
var material = new Material();
material.diffuseTexture = diffuseTextureUrl;
boxObjData.materials.Material = material;
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 1.0]);
});
it('uses default material (1)', function() {
boxObjData.nodes[0].meshes[0].primitives[0].material = undefined;
// Creates a material called "default"
var gltf = createGltf(boxObjData);
expect(gltf.materials.default).toBeDefined();
var kmc = gltf.materials.default.extensions.KHR_materials_common;
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 1.0]);
});
it('uses default material (2)', function() {
boxObjData.materials = {};
// Uses the original name of the material
var gltf = createGltf(boxObjData);
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 1.0]);
});
it('handles material used with and without normals (1)', function() {
// Two meshes - one with normals, and one without
boxObjData.nodes.push(duplicateBoxObjData.nodes[0]);
boxObjData.nodes[1].meshes[0].normals.length = 0;
var gltf = createGltf(boxObjData);
var kmc1 = gltf.materials.Material.extensions.KHR_materials_common;
var kmc2 = gltf.materials.Material_constant.extensions.KHR_materials_common;
expect(kmc1.technique).toBe('PHONG');
expect(kmc2.technique).toBe('CONSTANT');
});
it('handles material used with and without normals (2)', function() {
// Now test in a different order
boxObjData.nodes.push(duplicateBoxObjData.nodes[0]);
boxObjData.nodes[0].meshes[0].normals.length = 0;
var gltf = createGltf(boxObjData);
var kmc1 = gltf.materials.Material.extensions.KHR_materials_common;
var kmc2 = gltf.materials.Material_shaded.extensions.KHR_materials_common;
expect(kmc1.technique).toBe('CONSTANT');
expect(kmc2.technique).toBe('PHONG');
});
it('runs without normals', function() {
boxObjData.nodes[0].meshes[0].normals.length = 0;
var gltf = createGltf(boxObjData);
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
expect(attributes.POSITION).toBeDefined();
expect(attributes.NORMAL).toBeUndefined();
expect(attributes.TEXCOORD_0).toBeDefined();
});
it('runs without uvs', function() {
boxObjData.nodes[0].meshes[0].uvs.length = 0;
var gltf = createGltf(boxObjData);
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
expect(attributes.POSITION).toBeDefined();
expect(attributes.NORMAL).toBeDefined();
expect(attributes.TEXCOORD_0).toBeUndefined();
});
it('runs without uvs and normals', function() {
boxObjData.nodes[0].meshes[0].normals.length = 0;
boxObjData.nodes[0].meshes[0].uvs.length = 0;
var gltf = createGltf(boxObjData);
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
expect(attributes.POSITION).toBeDefined();
expect(attributes.NORMAL).toBeUndefined();
expect(attributes.TEXCOORD_0).toBeUndefined();
});
function expandObjData(objData, duplicatesLength) {
var mesh = objData.nodes[0].meshes[0];
var indices = mesh.primitives[0].indices;
var positions = mesh.positions;
var normals = mesh.normals;
var uvs = mesh.uvs;
var indicesLength = indices.length;
var vertexCount = positions.length / 3;
for (var i = 1; i < duplicatesLength; ++i) {
for (var j = 0; j < vertexCount; ++j) {
positions.push(0.0);
positions.push(0.0);
positions.push(0.0);
normals.push(0.0);
normals.push(0.0);
normals.push(0.0);
uvs.push(0.0);
uvs.push(0.0);
}
for (var k = 0; k < indicesLength; ++k) {
indices.push(indices.get(k) + vertexCount * i);
}
}
}
it('detects need to use uint32 indices', function() {
expandObjData(boxObjData, 2731); // Right above 65536 limit
var mesh = boxObjData.nodes[0].meshes[0];
var indicesLength = mesh.primitives[0].indices.length;
var vertexCount = mesh.positions.length / 3;
var gltf = createGltf(boxObjData);
var primitive = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0];
var indicesAccessor = gltf.accessors[primitive.indices];
expect(indicesAccessor.count).toBe(indicesLength);
expect(indicesAccessor.max[0]).toBe(vertexCount - 1);
expect(indicesAccessor.componentType).toBe(WebGLConstants.UNSIGNED_INT);
var positionAccessor = gltf.accessors[primitive.attributes.POSITION];
expect(positionAccessor.count).toBe(vertexCount);
});
it('ambient of [1, 1, 1] is treated as [0, 0, 0]', function() {
boxObjData.materials.Material.ambientColor = [1.0, 1.0, 1.0, 1.0];
var gltf = createGltf(boxObjData);
var ambient = gltf.materials.Material.extensions.KHR_materials_common.values.ambient;
expect(ambient).toEqual([0.0, 0.0, 0.0, 1.0]);
});
});