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

Add draco mesh compression #353

Merged
merged 47 commits into from Apr 26, 2018

Conversation

FrankGalligan
Copy link
Contributor

The Draco glTF files created with gltf-pipeline will be created according to the KHR_draco_mesh_compression specification located
here:
https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md

@lilleyse
Copy link
Contributor

Awesome @FrankGalligan and @fanzhanggoogle. One of us should have a chance to review pretty soon.

Is it possible to clean up the git history a bit?

@lilleyse
Copy link
Contributor

Fixes #348

Copy link
Member

@shehzan10 shehzan10 left a comment

Choose a reason for hiding this comment

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

Thanks for opening this PR. I did a quick 1st pass overview and things generally look pretty good. Mostly just formatting changes for now.

README.md Outdated
|`--draco.quantizeTexcoord`|Quantization bits for texture coordinate attribute when using Draco compression.|No, default `12`|
|`--draco.quantizeColor`|Quantization bits for color attribute when using Draco compression.|No, default `8`|
|`--draco.quantizeSkin`|Quantization bits for skinning attribute (joint indices and joint weights) when using Draco compression.|No, default `12`|
|`--draco.unifiedQuantization`|Quantize positions of all primitives using the same quantization grid defined by the unified bounding box of all primitives. If this option is not set, quantization is applied on each primitive separately which can result in gaps appearing between different primitives.|No, default `false`|
Copy link
Member

Choose a reason for hiding this comment

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

Can we shorten the description of this? Probably too long for an options table. We could also put it just before the table with a *.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

*
* @private
*/
function getComponentReader(componentType) {
Copy link
Member

Choose a reason for hiding this comment

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

Does splitting this into it's own module warrant adding tests for it?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually the 2.0 branch doesn't have any unit tests now... but they will come before it is merged into master.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK I can add tests when needed.

@@ -0,0 +1,28 @@
module.exports = CreateDracoModule;
Copy link
Member

Choose a reason for hiding this comment

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

Camel case for the filename: draco_encoder_nodejs.js -> dracoEncoder.js.

Copy link
Member

Choose a reason for hiding this comment

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

I assume this file is copied as-is, but we should format the spacing/tables/empty lines to maintain consistency throughout the project.

Copy link
Contributor

Choose a reason for hiding this comment

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

Unless I'm missing something it looks like the JS encoder isn't being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. Removed this file.

var Cesium = require('cesium');
var hashObject = require('object-hash');
var ForEach = require('./ForEach');
var numberOfComponentsForType = require('./numberOfComponentsForType');
Copy link
Member

Choose a reason for hiding this comment

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

Minor pick: Let's order these (including the draco ones below) alphabetically.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


module.exports = compressMeshes;


Copy link
Member

Choose a reason for hiding this comment

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

Formatting: Remove extra empty line.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.



function TypeToName() {
}
Copy link
Member

Choose a reason for hiding this comment

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

Formatting: Empty function should have brackets in the same line (like you did for Remove).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.





Copy link
Member

Choose a reason for hiding this comment

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

Remove extra empty lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


return {
numComponents : componentsPerAttribute,
numVertices : accessor.count,
Copy link
Member

Choose a reason for hiding this comment

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

Naming: Use full words. numComponents -> numberOfComponents. Same for numVertices.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

console.log('Found duplicate!');
// Copy compressed primitive.
copyCompressedExtensionToPrimitive(
primitive, hashPrimitives[hashValue]);
Copy link
Member

Choose a reason for hiding this comment

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

Formatting: Combine into same line as the function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

const numFaces = indices.length / 3;
const numIndices = indices.length;

console.log("Num of faces: " + numFaces);
Copy link
Member

Choose a reason for hiding this comment

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

This should probably be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@FrankGalligan
Copy link
Contributor Author

@lilleyse For the history let me see what I can do. I tried to pull your 2.0 branch into my fork and then my "add_draco_mesh_compression" branch on top of that. But this PR does not reflect the history I would have liked.

@FrankGalligan FrankGalligan reopened this Mar 15, 2018
README.md Outdated
@@ -105,6 +108,13 @@ processGltf(gltf, options)
|`--separateTextures`, `-t`|Write out separate textures only.|No, default `false`|
|`--checkTransparency`|Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures are considered to be opaque.|No, default `false`|
|`--stats`|Print statistics to console for input and output glTF files.|No, default `false`|
|`--draco.compressionLevel`|Draco compression level [0-10], most is 10, least is 0.|No, default `7`|
Copy link
Member

Choose a reason for hiding this comment

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

Need to add compressMesh option.here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

if (encodedLen > 0) {
console.log("Encoded size is " + encodedLen);
} else {
console.log("Error: Encoding failed.");
Copy link
Member

Choose a reason for hiding this comment

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

These console.logs should be removed as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@FrankGalligan
Copy link
Contributor Author

OK, the history looks good.

- Shorten unifiedQuantization options table text.
- Add compressMesh to options table text.

This address a comment in CesiumGS#353
@shehzan10
Copy link
Member

@FrankGalligan
Copy link
Contributor Author

@shehzan10 I fixed the lint errors in compressMeshes.js, but the error in updateVersion.js is in code I did not touch and a little harder to fix as it is the first parameter that is not used.

So I can add some code like
if (!defined(accessorId)) { return; }

Or I could add a new function to ForEach.js like
ForEach.meshPrimitiveAttributeSemantic(primitive, function(semantic) {

Any suggestions?

@pjcozzi
Copy link
Contributor

pjcozzi commented Apr 3, 2018

We received a CLA from @FrankGalligan, thanks again!

Copy link
Contributor

@lilleyse lilleyse left a comment

Choose a reason for hiding this comment

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

Thanks for the updates. I have mostly small comments and one bigger comment about removing the uncompressed data.

default : false,
describe: 'Quantize positions of all primitives using the same quantization grid defined by the unified bounding box of all primitives. If this option is not set, quantization is applied on each primitive separately which can result in gaps appearing between different primitives. Default is false.',
type: 'boolean'
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove trailing comma.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

addExtensionsRequired(gltf, 'KHR_draco_mesh_compression');
var hashPrimitives = [];
options = defaultValue(options, {});
options.dracoOptions= defaultValue(options.dracoOptions, {});
Copy link
Contributor

Choose a reason for hiding this comment

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

Small tweak: options.dracoOptions =

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


// Add attributes to mesh.
var attributeToId = {};
var attributes = primitive.attributes;
Copy link
Contributor

Choose a reason for hiding this comment

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

This variable is unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


/**
* Removes unused elements from gltf.
* This function currenlty only works for accessors, buffers, and bufferViews.
Copy link
Contributor

Choose a reason for hiding this comment

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

currenlty typo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

* Contains functions for getting a list of element ids in use by the glTF asset.
* @constructor
*/
function getListOfElementsIdsInUse() {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks slightly clearer if getListOfElementsIdsInUse is capitalized.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So do you want it as 'GetListOfElementsIdsInUse', or 'getListOfElementsIDsInUse', or something else?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually it's probably fine as is.

/**
* Contains functions for getting a list of element ids in use by the glTF asset.
* @constructor
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

For each of the new classes mark as @private so they don't show up in the doc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


TypeToGltfElementName.bufferView = function() {
return 'bufferViews';
};
Copy link
Contributor

Choose a reason for hiding this comment

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

TypeToGltfElementName can be simplified to

var TypeToGltfElementName = {
    accessor : 'accessors',
    buffer : 'buffers',
    bufferView : 'bufferViews'
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

* This function currenlty only works for accessors, buffers, and bufferViews.
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @returns {Object} The glTF asset with the added pipeline extras.
Copy link
Contributor

Choose a reason for hiding this comment

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

Fix the description, looks like a copy-paste error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

ForEach.skin(gltf, function(skin) {
if (defined(skin.inverseBindMatrices)) {
usedAccessorIds[skin.inverseBindMatrices] = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The indentation in this block is slightly off.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@@ -0,0 +1,235 @@
'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.

Does the uncompressed data get spliced out of the original buffer in all cases?

It's possible that the uncompressed attributes and a texture may be stored in a buffer, and because that texture's bufferView references the buffer the buffer won't get removed in removeUnusedElements.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently yes. I have another branch that I think should fix this issue here:
https://github.com/FrankGalligan/gltf-pipeline/commits/fix_buffer_packing

I can merge that branch into this branch. I also have some other branches as well that I want to merge. Like a fix for JOINT_ATTRIBUTES not using integer, and a branch that will add support to go from Draco glTF -> glTF.

I was going to make PRs from them after this was landed as I think it would be easier to review, but I can merge them into this this PR if you want.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe open a PR for fix_buffer_packing that targets this branch? The others can wait for later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

- This fixes an issue raised in CesiumGS#353
by @shehzan10.
- Debug_checks were turned on and the check was wrong in an older version
of the JavaScript encoder.
@FrankGalligan
Copy link
Contributor Author

@shehzan10 I fixed the issue you were having with the encoder. I updated the npm package, so if you update your dependencies this should compress now. There isstill an issue with the writing of the gltf, which I'm looking into.

@shehzan10
Copy link
Member

Can confirm that the updates fix the crashing models.

There is still an issue with the writing of the gltf, which I'm looking into.

Writing to disk looks ok, I guess. But, it looks like the test model fails to load for compression level 7 and above and works for 6 and lower.

@FrankGalligan
Copy link
Contributor Author

@shehzan10 Yeah so the decoder has the dcheck as well. It the decoder is using the nodejs modules and they update it should be fine. Otherwise they will have to wait until we push the fixes to github. We are not pushing the changes until the week of 4/16.

-The old code would turn on Draco compression if the file had the text
"draco" in it.
-This fixes #18
@shehzan10
Copy link
Member

@FrankGalligan can you update this to draco 1.3 and fix the remaining comments from @lilleyse? I think we should be able to merge then.

- Also fixes some comments in CesiumGS#353
@FrankGalligan
Copy link
Contributor Author

@shehzan10 Updated to 1.3. Waiting on one comment form @lilleyse

The bufferView's for inlined images was not being processed.
@lilleyse
Copy link
Contributor

The code changes looks good. We're just going to do some final testing.

@lilleyse
Copy link
Contributor

All good here - thanks @FrankGalligan

@lilleyse lilleyse merged commit 668dcd1 into CesiumGS:2.0 Apr 26, 2018
@FrankGalligan FrankGalligan deleted the add_draco_mesh_compression branch April 26, 2018 17:44
@emackey emackey mentioned this pull request Apr 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants