Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.0 pbr #274

Merged
merged 6 commits into from
Jun 9, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,11 @@ gulp.task('build-cesium', function () {
'findAccessorMinMax.js',
'ForEach.js',
'getAccessorByteStride.js',
'getJointCountForMaterials.js',
'getStatistics.js',
'numberOfComponentsForType.js',
'parseBinaryGltf.js',
'pbrToMaterialsCommon.js',
'processModelMaterialsCommon.js',
'removePipelineExtras.js',
'removeExtensionsRequired.js',
Expand Down
184 changes: 67 additions & 117 deletions lib/generateModelMaterialsCommon.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';
var Cesium = require('cesium');
var addExtensionsRequired = require('./addExtensionsRequired');
var ForEach = require('./ForEach');
var getJointCountForMaterials = require('./getJointCountForMaterials');

var defaultValue = Cesium.defaultValue;
var defined = Cesium.defined;
Expand All @@ -26,7 +28,6 @@ function generateModelMaterialsCommon(gltf, kmcOptions) {
kmcOptions.technique = defaultValue(kmcOptions.technique, 'PHONG');
addExtensionsRequired(gltf, 'KHR_materials_common');
var materialsCommon;
var materials = gltf.materials;
var nodes = gltf.nodes;
var techniques = gltf.techniques;
var jointCountForMaterialId = getJointCountForMaterials(gltf);
Expand All @@ -41,133 +42,82 @@ function generateModelMaterialsCommon(gltf, kmcOptions) {
var lights = {};
materialsCommon.lights = lights;

for (var materialId in materials) {
if (materials.hasOwnProperty(materialId)) {
var material = materials[materialId];
var technique = techniques[material.technique];
var techniqueParameters = technique.parameters;
if (defined(techniqueParameters.ambient) && !defined(lights.defaultAmbient)) {
lights.defaultAmbient = {
ambient: {
color: [1, 1, 1]
},
name: 'defaultAmbient',
type: 'ambient'
};
}
for (var parameterId in techniqueParameters) {
if (techniqueParameters.hasOwnProperty(parameterId)) {
if (parameterId.indexOf('light') === 0 && parameterId.indexOf('Transform') >= 0) {
var lightId = parameterId.substring(0, parameterId.indexOf('Transform'));
var lightTransform = techniqueParameters[parameterId];
var lightNodeId = lightTransform.node;
var lightNode = nodes[lightNodeId];
var nodeExtensions = lightNode.extensions;
if (!defined(nodeExtensions)) {
nodeExtensions = {};
lightNode.extensions = nodeExtensions;
}
materialsCommon = {};
nodeExtensions.KHR_materials_common = materialsCommon;
materialsCommon.light = lightId;
var lightColor = techniqueParameters[lightId + 'Color'];
var light = {
name: lightId,
type: 'directional',
directional: {
color: defaultValue(lightColor.value, [1, 1, 1])
}
};
lights[lightId] = light;
ForEach.material(gltf, function(material, materialId) {
var technique = techniques[material.technique];
var techniqueParameters = technique.parameters;
if (defined(techniqueParameters.ambient) && !defined(lights.defaultAmbient)) {
lights.defaultAmbient = {
ambient: {
color: [1, 1, 1]
},
name: 'defaultAmbient',
type: 'ambient'
};
}
for (var parameterId in techniqueParameters) {
if (techniqueParameters.hasOwnProperty(parameterId)) {
if (parameterId.indexOf('light') === 0 && parameterId.indexOf('Transform') >= 0) {
var lightId = parameterId.substring(0, parameterId.indexOf('Transform'));
var lightTransform = techniqueParameters[parameterId];
var lightNodeId = lightTransform.node;
var lightNode = nodes[lightNodeId];
var nodeExtensions = lightNode.extensions;
if (!defined(nodeExtensions)) {
nodeExtensions = {};
lightNode.extensions = nodeExtensions;
}
materialsCommon = {};
nodeExtensions.KHR_materials_common = materialsCommon;
materialsCommon.light = lightId;
var lightColor = techniqueParameters[lightId + 'Color'];
var light = {
name: lightId,
type: 'directional',
directional: {
color: defaultValue(lightColor.value, [1, 1, 1])
}
};
lights[lightId] = light;
}
}
}

delete material.technique;
var extensions = material.extensions;
if (!defined(extensions)) {
extensions = {};
material.extensions = extensions;
}
materialsCommon = {};
extensions.KHR_materials_common = materialsCommon;
for (var kmcOption in kmcOptions) {
if (kmcOptions.hasOwnProperty(kmcOption) && kmcOption !== 'enable') {
materialsCommon[kmcOption] = kmcOptions[kmcOption];
}
}
var jointCount = jointCountForMaterialId[materialId];
if (defined(jointCount)) {
materialsCommon.jointCount = jointCount;
delete material.technique;
var extensions = material.extensions;
if (!defined(extensions)) {
extensions = {};
material.extensions = extensions;
}
materialsCommon = {};
extensions.KHR_materials_common = materialsCommon;
for (var kmcOption in kmcOptions) {
if (kmcOptions.hasOwnProperty(kmcOption) && kmcOption !== 'enable') {
materialsCommon[kmcOption] = kmcOptions[kmcOption];
}
}
var jointCount = jointCountForMaterialId[materialId];
if (defined(jointCount)) {
materialsCommon.jointCount = jointCount;
}

var materialValues = material.values;
var diffuseColor, transparency;
if (defined(materialValues)) {
diffuseColor = materialValues.diffuse;
transparency = materialValues.transparency;
materialsCommon.values = materialValues;
}
var materialValues = material.values;
var diffuseColor, transparency;
if (defined(materialValues)) {
diffuseColor = materialValues.diffuse;
transparency = materialValues.transparency;
materialsCommon.values = materialValues;
}

// Check if we have transparency and set transparent flag
if ((defined(transparency) && transparency < 1.0) ||
(defined(diffuseColor) && Array.isArray(diffuseColor) && diffuseColor[3] < 1.0)) {
materialsCommon.values.transparent = true;
}
delete material.values;
// Check if we have transparency and set transparent flag
if ((defined(transparency) && transparency < 1.0) ||
(defined(diffuseColor) && Array.isArray(diffuseColor) && diffuseColor[3] < 1.0)) {
materialsCommon.values.transparent = true;
}
}
delete material.values;
});
delete gltf.techniques;
delete gltf.programs;
delete gltf.shaders;
return gltf;
}

function getJointCountForMaterials(gltf) {
var accessors = gltf.accessors;
var meshes = gltf.meshes;
var nodes = gltf.nodes;
var skins = gltf.skins;
var jointCountForMaterialId = {};

var nodesForSkinId = {};
for (var nodeId in nodes) {
if (nodes.hasOwnProperty(nodeId)) {
var node = nodes[nodeId];
if (defined(node.skin)) {
if (!defined(nodesForSkinId[node.skin])) {
nodesForSkinId[node.skin] = [];
}
nodesForSkinId[node.skin].push(node);
}
}
}

for (var skinId in skins) {
if (skins.hasOwnProperty(skinId)) {
var skin = skins[skinId];
var jointCount = 1;
if (defined(skin.inverseBindMatrices)) {
jointCount = accessors[skin.inverseBindMatrices].count;
}
var skinnedNodes = nodesForSkinId[skinId];
var skinnedNodesLength = skinnedNodes.length;
for (var i = 0; i < skinnedNodesLength; i++) {
var skinnedNode = skinnedNodes[i];
var nodeMeshes = skinnedNode.meshes;
var nodeMeshesLength = nodeMeshes.length;
for (var j = 0; j < nodeMeshesLength; j++) {
var meshId = nodeMeshes[j];
var mesh = meshes[meshId];
var primitives = mesh.primitives;
var primitivesLength = primitives.length;
for (var k = 0; k < primitivesLength; k++) {
var primitive = primitives[k];
jointCountForMaterialId[primitive.material] = jointCount;
}
}
}
}
}
return jointCountForMaterialId;
}
47 changes: 47 additions & 0 deletions lib/getJointCountForMaterials.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that it's a new file, does it need a spec?

var Cesium = require('cesium');
var ForEach = require('./ForEach');

var defined = Cesium.defined;

module.exports = getJointCountForMaterials;

function getJointCountForMaterials(gltf) {
var accessors = gltf.accessors;
var meshes = gltf.meshes;
var jointCountForMaterialId = {};

var nodesForSkinId = {};
ForEach.node(gltf, function(node) {
if (defined(node.skin)) {
if (!defined(nodesForSkinId[node.skin])) {
nodesForSkinId[node.skin] = [];
}
nodesForSkinId[node.skin].push(node);
}
});

ForEach.skin(gltf, function(skin, skinId) {
var jointCount = 1;
if (defined(skin.inverseBindMatrices)) {
jointCount = accessors[skin.inverseBindMatrices].count;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would make more sense to check skin.joints instead?

var skinnedNodes = nodesForSkinId[skinId];
var skinnedNodesLength = skinnedNodes.length;
for (var i = 0; i < skinnedNodesLength; i++) {
var skinnedNode = skinnedNodes[i];
var meshId = skinnedNode.mesh;
if (defined(meshId)) {
var mesh = meshes[meshId];
var primitives = mesh.primitives;
var primitivesLength = primitives.length;
for (var k = 0; k < primitivesLength; k++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ForEach.meshPrimitive

var primitive = primitives[k];
jointCountForMaterialId[primitive.material] = jointCount;
}
}
}
});

return jointCountForMaterialId;
}
119 changes: 119 additions & 0 deletions lib/pbrToMaterialsCommon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
'use strict';
var Cesium = require('cesium');
var addExtensionsRequired = require('./addExtensionsRequired');
var ForEach = require('./ForEach');
var getJointCountForMaterials = require('./getJointCountForMaterials');
var removeExtensionsUsed = require('./removeExtensionsUsed');

var defined = Cesium.defined;

module.exports = pbrToMaterialsCommon;

/**
* Convert PBR materials to use a KHR_materials_common BLINN shader.
* This is a lossy conversion, and as such should only be used for
* compatibility reasons. Normal texture and metallic roughness information
* will be lost, and some color or texture information may be lost.
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @returns {Object} The glTF asset with materials converted to KHR_materials_common
*/
function pbrToMaterialsCommon(gltf) {
var materialJointCount = getJointCountForMaterials(gltf);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, transparent should be incorporated into this.

ForEach.material(gltf, function(material, materialId) {
var values = {
ambient : [ 0.0, 0.0, 0.0, 1.0 ],
diffuse : [ 0.0, 0.0, 0.0, 1.0 ],
emission : [ 0.0, 0.0, 0.0, 1.0 ],
specular : [ 0.0, 0.0, 0.0, 1.0],
shininess : [ 0.0 ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forget, what's the latest on KHR_materials_common? Is shininess an array now or still a single float. Also should textures indexes be inside an array too?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh, that's massively out of date... I don't really have a good answer other than that glTF 2.0 materials pre-PBR required all values to be arrays. I will put this in line with what is there currently, but it will probably change to something closer to this when it gets updated.

Copy link
Contributor Author

@lasalvavida lasalvavida May 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm actually going to keep this as is, just considering the dated nature of the KHR_materials_common spec. For example, the spec doesn't include doubleSided or jointCount as properties.

If anyone feels strongly opposed to that, I'm definitely open to discussing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this will probably be replaced by: KhronosGroup/glTF#947 at some point, so I wouldn't worry about it too much

};
var pbrMetallicRoughness = material.pbrMetallicRoughness;
var isPBR = defined(pbrMetallicRoughness) ||
(defined(material.extensions) && defined(material.extensions.KHR_materials_pbrSpecularGlossiness) ||
defined(material.occlusionTexture) ||
defined(material.emissiveFactor) ||
defined(material.emissiveTexture) ||
defined(material.doubleSided));

if (defined(pbrMetallicRoughness)) {
var baseColorFactor = pbrMetallicRoughness.baseColorFactor;
if (defined(baseColorFactor)) {
values.diffuse = baseColorFactor;
}
var baseColorTexture = pbrMetallicRoughness.baseColorTexture;
if (defined(baseColorTexture)) {
values.diffuse = [baseColorTexture.index];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to estimate specular and shininess from roughness?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be possible to calculate, not estimate, I would expect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emackey do you know of any resources for this that I should be looking at?

}
var extensions = material.extensions;
if (defined(extensions)) {
var pbrSpecularGlossiness = extensions.KHR_materials_pbrSpecularGlossiness;
if (defined(pbrSpecularGlossiness)) {
var diffuseFactor = pbrSpecularGlossiness.diffuseFactor;
// Use baseColorTexture if it was defined
if (defined(diffuseFactor) && values.diffuse.length > 1) {
values.diffuse = diffuseFactor;
}
// diffuseTexture should be used instead of baseColorTexture if defined
var diffuseTexture = pbrSpecularGlossiness.diffuseTexture;
if (defined(diffuseTexture)) {
values.diffuse = [diffuseTexture.index];
}
var specularFactor = pbrSpecularGlossiness.specularFactor;
if (defined(specularFactor)) {
values.specular[0] = specularFactor[0];
values.specular[1] = specularFactor[1];
values.specular[2] = specularFactor[2];
}
var glossinessFactor = pbrSpecularGlossiness.glossinessFactor;
if (defined(glossinessFactor)) {
values.shininess[0] = glossinessFactor;
}
var specularGlossinessTexture = pbrSpecularGlossiness.specularGlossinessTexture;
if (defined(specularGlossinessTexture)) {
values.specular = [specularGlossinessTexture.index];
}
}
}
var occlusionTexture = material.occlusionTexture;
if (defined(occlusionTexture)) {
values.ambient = [occlusionTexture.index];
}
var emissiveFactor = material.emissiveFactor;
if (defined(emissiveFactor)) {
values.emission[0] = emissiveFactor[0];
values.emission[1] = emissiveFactor[1];
values.emission[2] = emissiveFactor[2];
}
var emissiveTexture = material.emissiveTexture;
if (defined(emissiveTexture)) {
values.emission = [emissiveTexture.index];
}
var doubleSided = material.doubleSided;
if (isPBR) {
delete material.doubleSided;
delete material.emissiveFactor;
delete material.emissiveTexture;
delete material.normalTexture;
delete material.occlusionTexture;
delete material.pbrMetallicRoughness;
var materialsCommon = {
technique: 'BLINN',
values: values
};
var jointCount = materialJointCount[materialId];
if (defined(jointCount)) {
materialsCommon.jointCount = jointCount;
}
if (defined(doubleSided)) {
materialsCommon.doubleSided = doubleSided;
}
material.extensions = {
KHR_materials_common: materialsCommon
};
addExtensionsRequired(gltf, 'KHR_materials_common');
removeExtensionsUsed(gltf, 'KHR_materials_pbrSpecularGlossiness');
}
});
}
Loading