-
Notifications
You must be signed in to change notification settings - Fork 250
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
gltfPrimitiveToCesiumGeometry fixes #100
Changes from all commits
7f4d0fb
167b36c
0e646db
a40badc
46de2d3
487a2de
360b183
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
'use strict'; | ||
var gltfPrimitiveToCesiumGeometry = require('./gltfPrimitiveToCesiumGeometry'); | ||
var cesiumGeometryToGltfPrimitive = require('./cesiumGeometryToGltfPrimitive'); | ||
var createAccessorUsageTables = require('./createAccessorUsageTables'); | ||
var Cesium = require('cesium'); | ||
var GeometryPipeline = Cesium.GeometryPipeline; | ||
var defined = Cesium.defined; | ||
|
||
module.exports = cacheOptimization; | ||
|
||
// Helper method to map accessor collections from the usageTable to an independent primitive (if there is one) | ||
function createIndicesToAttributeDictionary(gltf) { | ||
var dictionary = {}; | ||
var meshes = gltf.meshes; | ||
for (var meshId in meshes) { | ||
if (meshes.hasOwnProperty(meshId)) { | ||
var mesh = meshes[meshId]; | ||
var primitives = mesh.primitives; | ||
var primitivesLength = primitives.length; | ||
for (var i = 0; i < primitivesLength; i++) { | ||
var primitive = primitives[i]; | ||
var indicesId = primitive.indices; | ||
|
||
var primitivesOfIndicesId; | ||
if (!dictionary[indicesId]) { | ||
primitivesOfIndicesId = []; | ||
} else { | ||
primitivesOfIndicesId = dictionary[indicesId]; | ||
} | ||
primitivesOfIndicesId.push(primitive); | ||
|
||
dictionary[indicesId] = primitivesOfIndicesId; | ||
} | ||
} | ||
} | ||
return dictionary; | ||
} | ||
|
||
function getIndependentPrimitive(dictionary, indicesId, attributeAccessors) { | ||
var primitivesOfIndicesId = dictionary[indicesId]; | ||
for (var primitiveId in primitivesOfIndicesId) { | ||
if (primitivesOfIndicesId.hasOwnProperty(primitiveId)) { | ||
var primitive = primitivesOfIndicesId[primitiveId]; | ||
var attributes = primitive.attributes; | ||
|
||
var equalCount = 0; | ||
// Naive check to see if this primitive's attributes match | ||
for (var semantic in attributes) { | ||
if (attributes.hasOwnProperty(semantic)) { | ||
var accessorId = attributes[semantic]; | ||
if (defined(attributeAccessors[accessorId])) { | ||
equalCount++; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This second loop can be avoided. Just do something like this: for (var attributeSemantic in attributes) {
if (attributes.hasOwnProperty(attributeSemantic)) {
var accessorId = attributes[attributeSemantic];
if (defined(attributeAccessors[accessorId])) {
...
}
}
} |
||
} | ||
} | ||
var accessorsLength = Object.keys(attributeAccessors).length; | ||
// Ensure that this is an independent set of accessors | ||
if (equalCount === accessorsLength) { | ||
return primitive; | ||
} | ||
} | ||
} | ||
} | ||
|
||
function cacheOptimization(gltf, cacheSize) { | ||
// perform post vertex cache optimization | ||
var primitive; | ||
var geometry; | ||
var meshes = gltf.meshes; | ||
for (var meshId in meshes) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment. |
||
if (meshes.hasOwnProperty(meshId)) { | ||
var mesh = meshes[meshId]; | ||
var primitives = mesh.primitives; | ||
var primitivesLength = primitives.length; | ||
for (var i = 0; i < primitivesLength; i++) { | ||
primitive = primitives[i]; | ||
geometry = gltfPrimitiveToCesiumGeometry(gltf, primitive); | ||
GeometryPipeline.reorderForPostVertexCache(geometry, cacheSize); | ||
|
||
cesiumGeometryToGltfPrimitive(gltf, primitive, geometry); | ||
} | ||
} | ||
} | ||
// perform pre vertex cache optimization on each independent primitive | ||
var usageTables = createAccessorUsageTables(gltf); | ||
var dictionary = createIndicesToAttributeDictionary(gltf); | ||
// Iterate through each usage table | ||
for (var j = 0; j < usageTables.length; j++) { | ||
var indexAccessors = usageTables[j].indexAccessors; | ||
var attributeAccessors = usageTables[j].attributeAccessors; | ||
var keys = Object.keys(indexAccessors); | ||
// If a set of attributes accessors is only used by one indices accessor | ||
if (keys.length === 1) { | ||
var indicesId = keys[0]; | ||
// look through to see if an independent primitive exists for those attributes | ||
primitive = getIndependentPrimitive(dictionary, indicesId, attributeAccessors); | ||
// If there is, it can be safely pre vertex cache optimized | ||
if (defined(primitive)) { | ||
geometry = gltfPrimitiveToCesiumGeometry(gltf, primitive); | ||
GeometryPipeline.reorderForPreVertexCache(geometry); | ||
cesiumGeometryToGltfPrimitive(gltf, primitive, geometry); | ||
} | ||
} | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
'use strict'; | ||
var writeAccessor = require('./writeAccessor'); | ||
|
||
module.exports = cesiumGeometryToGltfPrimitive; | ||
|
||
// Get the first gltf attribute semantic of that type | ||
function getFirstAttributeSemantic(primitive, semantic) { | ||
var attributes = primitive.attributes; | ||
for (var attributeSemantic in attributes) { | ||
if (attributes.hasOwnProperty(attributeSemantic)) { | ||
if (attributeSemantic.indexOf(semantic) === 0) { | ||
return attributeSemantic; | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Helper method to write attributes to gltf primitive from cesium geometry | ||
function mapGeometryAttributeToPrimitive(gltf, primitive, geometry, semantic) { | ||
var attributeSemantic; | ||
var values; | ||
|
||
switch(semantic) { | ||
case 'position': | ||
attributeSemantic = getFirstAttributeSemantic(primitive, 'POSITION'); | ||
values = geometry.attributes.position.values; | ||
break; | ||
case 'normal': | ||
attributeSemantic = getFirstAttributeSemantic(primitive, 'NORMAL'); | ||
values = geometry.attributes.normal.values; | ||
break; | ||
case 'st': | ||
attributeSemantic = getFirstAttributeSemantic(primitive, 'TEXCOORD'); | ||
values = geometry.attributes.st.values; | ||
break; | ||
default: | ||
attributeSemantic = semantic; | ||
values = geometry.attributes[semantic].values; | ||
} | ||
var accessorId = primitive.attributes[attributeSemantic]; | ||
var accessor = gltf.accessors[accessorId]; | ||
writeAccessor(gltf, accessor, values); | ||
} | ||
|
||
function cesiumGeometryToGltfPrimitive(gltf, primitive, geometry) { | ||
var attributes = geometry.attributes; | ||
for (var semantic in attributes) { | ||
if (attributes.hasOwnProperty(semantic)) { | ||
mapGeometryAttributeToPrimitive(gltf, primitive, geometry, semantic); | ||
} | ||
} | ||
var indicesId = primitive.indices; | ||
var indicesAccessor = gltf.accessors[indicesId]; | ||
writeAccessor(gltf, indicesAccessor, geometry.indices); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,7 +129,7 @@ function createAccessorUsageTables(gltf) { | |
for (attribute in attributes) { | ||
if (attributes.hasOwnProperty(attribute)) { | ||
attributeAccessorId = attributes[attribute]; | ||
table.attributeAccessors[attributeAccessorId] = attribute; | ||
table.attributeAccessors[attributeAccessorId] = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for correcting that |
||
accessorTableMapping[attributeAccessorId] = mappedTableIndex; | ||
} | ||
} | ||
|
@@ -147,7 +147,7 @@ function createAccessorUsageTables(gltf) { | |
// Merge them into this one if they have been | ||
mergeUsageTables(tables, accessorTableMapping, tableIndex, attributeTableIndex); | ||
} | ||
table.attributeAccessors[attributeAccessorId] = attribute; | ||
table.attributeAccessors[attributeAccessorId] = true; | ||
accessorTableMapping[attributeAccessorId] = tableIndex; | ||
} | ||
} | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
'use strict'; | ||
var readAccessor = require('./readAccessor'); | ||
var numberOfComponentsForType = require('./numberOfComponentsForType'); | ||
var Cesium = require('cesium'); | ||
var Geometry = Cesium.Geometry; | ||
var GeometryAttribute = Cesium.GeometryAttribute; | ||
var ComponentDatatype = Cesium.ComponentDatatype; | ||
var Cartesian2 = Cesium.Cartesian2; | ||
var Cartesian3 = Cesium.Cartesian3; | ||
var Cartesian4 = Cesium.Cartesian4; | ||
var defined = Cesium.defined; | ||
|
||
module.exports = gltfPrimitiveToCesiumGeometry; | ||
|
||
// Helper method for packing Cartesians to arrays | ||
function packArray(values) { | ||
var length = values.data.length; | ||
var packed; | ||
var i; | ||
switch (values.type) { | ||
case 'Cartesian2': | ||
packed = new Array(length * 2); | ||
for (i = 0; i < length; ++i) { | ||
Cartesian2.pack(values.data[i], packed, i * 2); | ||
} | ||
return packed; | ||
case 'Cartesian3': | ||
packed = new Array(length * 3); | ||
for (i = 0; i < length; ++i) { | ||
Cartesian3.pack(values.data[i], packed, i * 3); | ||
} | ||
return packed; | ||
case 'Cartesian4': | ||
packed = new Array(length * 4); | ||
for (i = 0; i < length; ++i) { | ||
Cartesian4.pack(values.data[i], packed, i * 4); | ||
} | ||
return packed; | ||
} | ||
} | ||
|
||
// Helper method for taking a gltf primitive attribute and returning a geometry attribute | ||
function mapPrimitiveAttributeToGeometry(gltf, primitive, semantic, geometryAttributes) { | ||
var accessorId = primitive.attributes[semantic]; | ||
var accessor = gltf.accessors[accessorId]; | ||
var componentsPerAttribute = numberOfComponentsForType(accessor.type); | ||
var values = readAccessor(gltf, accessor); | ||
var packed = packArray(values); | ||
|
||
var attributeName; | ||
var finalValues; | ||
// Strip semantic of its index | ||
switch(semantic.replace(/([0-9]|_)/g, '')) { | ||
case 'POSITION': | ||
// Only use geometry semantic for one attribute, otherwise just create a generic attribute | ||
if (!defined(geometryAttributes.position)) { | ||
attributeName = 'position'; | ||
finalValues = new Float64Array(packed); | ||
} else { | ||
attributeName = semantic; | ||
finalValues = new Float64Array(packed); | ||
} | ||
break; | ||
case 'NORMAL': | ||
if (!defined(geometryAttributes.normal)) { | ||
attributeName = 'normal'; | ||
finalValues = new Float32Array(packed); | ||
} else { | ||
attributeName = semantic; | ||
finalValues = new Float32Array(packed); | ||
} | ||
break; | ||
case 'TEXCOORD': | ||
if (!defined(geometryAttributes.st)) { | ||
attributeName = 'st'; | ||
finalValues = new Float32Array(packed); | ||
} else { | ||
attributeName = semantic; | ||
finalValues = new Float32Array(packed); | ||
} | ||
break; | ||
default: | ||
attributeName = semantic; | ||
finalValues = new Float64Array(packed); | ||
} | ||
var options = { | ||
componentDatatype : ComponentDatatype.FLOAT, | ||
componentsPerAttribute : componentsPerAttribute, | ||
values : finalValues | ||
}; | ||
return { | ||
name : attributeName, | ||
attribute : new GeometryAttribute(options) | ||
}; | ||
} | ||
|
||
function gltfPrimitiveToCesiumGeometry(gltf, primitive) { | ||
var geometryAttributes = {}; | ||
var attributes = primitive.attributes; | ||
for (var semantic in attributes) { | ||
if (attributes.hasOwnProperty(semantic)) { | ||
var nameAndAttribute = mapPrimitiveAttributeToGeometry(gltf, primitive, semantic, geometryAttributes); | ||
geometryAttributes[nameAndAttribute.name] = nameAndAttribute.attribute; | ||
} | ||
} | ||
|
||
var indicesId = primitive.indices; | ||
var indicesAccessor = gltf.accessors[indicesId]; | ||
var indices = readAccessor(gltf, indicesAccessor); | ||
var primitiveType = primitive.mode; | ||
|
||
var geometry = new Geometry({ | ||
attributes : geometryAttributes, | ||
indices : new Uint32Array(indices.data), | ||
primitiveType : primitiveType | ||
}); | ||
|
||
return geometry; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this use
NodeHelpers.forEachPrimitiveInScene
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this currently in master? I cannot seem to find this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not; it is in the ao branch. I think forego using it for now since it is async and doesn't have a way to notify when it completes currently.