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

Draco with dequantization in shader #6357

Merged
merged 9 commits into from
Mar 27, 2018
Merged

Draco with dequantization in shader #6357

merged 9 commits into from
Mar 27, 2018

Conversation

ggetz
Copy link
Contributor

@ggetz ggetz commented Mar 21, 2018

@lilleyse Addresses #6191 (comment)

Skip dequantization in the draco module and instead dequantizes in the shader, for an optionally specified list of attribute types to skip.

@ggetz ggetz requested a review from lilleyse March 21, 2018 19:27
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.

The mechanics look solid here. Once quantization is on by default it might be good to go through all the draco sample models and make sure they still work. Another thing to try is loading the draco version of the NYC tileset and comparing the total memory usage in the 3D Tiles inspector with quantization on and off.

Finally, does it ever make sense to draco-encode a model with pre-quantized attributes? Or is the preferred method to do what is done here, converting draco-encoded to quantized form at runtime? I would think the second case, but just want to be sure.

@@ -130,7 +130,7 @@ define([
*
* @private
*/
DracoLoader.parse = function(model) {
DracoLoader.parse = function(model, dequantizeInShader) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we just grab model._dequantizeInShader instead of passing it through separately?

@@ -288,6 +288,7 @@ define([
* @param {Color} [options.silhouetteColor=Color.RED] The silhouette color. If more than 256 models have silhouettes enabled, there is a small chance that overlapping models will have minor artifacts.
* @param {Number} [options.silhouetteSize=0.0] The size of the silhouette in pixels.
* @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model.
* @param {String[]} [options.dequantizeInShader] The list of {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression} encoded attributes to dequantize in the shader.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is too fine grained of an option. It should just be a boolean and default to true, meaning all attributes will be dequantized in the shader. (Under the hood there might be exceptions, in case there's an issue with bone indices or something).

Also it should be set to false if the draco extension is not in use. In its current form a model crashes if it doesn't use draco but a value like ['POSITION'] is passed in 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.

We can only skip attributes by attribute type (https://github.com/google/draco/blob/master/src/draco/javascript/emscripten/draco_web_decoder.idl#L22), not each attribute. I think it may be best to limit to POSITION, NORMAL,
COLOR, and TEX_COORD.

(Three.js only skips quantization for position)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, hardcoding those to be quantized sounds fine.

@@ -1710,6 +1713,7 @@ define([
programPrimitives = [];
model._programPrimitives[programId] = programPrimitives;
}
primitive.id = id + '.primitive.' + i;
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 we should avoid dynamically adding a property to the glTF in this way.

I can't remember why we cache quantized primitives according to their program, but maybe the step can be simplified?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was implemented for WEB3D_quantized_attributes, I'll see if it can be simplified.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I turned the list into a dictionary, and used the id as the key, so I am no longer adding the id attribute to the primitive itself.


if (!defined(primitives)) {
return shader;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this check for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the program primitives weren't cached, they are not quantized, and the shader does not need to be modified.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add a comment if unclear.

@@ -82,6 +84,21 @@ define([
componentDatatype : ComponentDatatype.fromTypedArray(vertexArray)
}
};

transform = new draco.AttributeQuantizationTransform();
Copy link
Contributor

Choose a reason for hiding this comment

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

It should be ok to remove the var transform; above and have this be var transform = new draco.AttributeQuantizationTransform();


transform = new draco.AttributeQuantizationTransform();
if (transform.InitFromAttribute(attribute)) {
var minValues = new Float32Array(numComponents);
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't really matter, but could this be a plain Array instead? Since the array is pretty small using a Float32Array almost seems misleading.

@ggetz
Copy link
Contributor Author

ggetz commented Mar 22, 2018

Finally, does it ever make sense to draco-encode a model with pre-quantized attributes? Or is the preferred method to do what is done here, converting draco-encoded to quantized form at runtime? I would think the second case, but just want to be sure.

Preferred method is the second, see google/draco#18

@bagnell
Copy link
Contributor

bagnell commented Mar 22, 2018

Finally, does it ever make sense to draco-encode a model with pre-quantized attributes? Or is the preferred method to do what is done here, converting draco-encoded to quantized form at runtime? I would think the second case, but just want to be sure.

Preferred method is the second, see google/draco#18

Why isn't it the first? With the second, you would need to re-quantize after decompression. After reading that issue, it seems like you would quantize attributes and then draco compress with the option to remove the built-in quantization.

@ggetz
Copy link
Contributor Author

ggetz commented Mar 22, 2018

Why isn't it the first? With the second, you would need to re-quantize after decompression. After reading that issue, it seems like you would quantize attributes and then draco compress with the option to remove the built-in quantization.

With the second the quantization values are stored in the draco geometry itself, so there's not need to store them separately. With the current iteration in glTF-pipeline, I don't believe it is possible to quantize the attributes then draco encode.

@ggetz
Copy link
Contributor Author

ggetz commented Mar 23, 2018

Thanks @lilleyse, updated!

@ggetz
Copy link
Contributor Author

ggetz commented Mar 23, 2018

Numbers with NYC tileset:

Dequantize Memory GPU Memory
CPU 910,756K 684,219K
GPU 553,675K 664,426K

@ggetz ggetz force-pushed the draco-quantization branch from a4dd562 to 2044d9a Compare March 26, 2018 15:44
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.

Getting close! In a bit I should be able to test the final memory usage numbers.

@@ -131,11 +136,12 @@ define([
* @private
*/
DracoLoader.parse = function(model) {
if (!hasExtension(model)) {
if (!this.hasExtension(model)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's better style to use DracoLoader.hasExtension instead here and below since it is a static functions.

@@ -1429,7 +1433,7 @@ define([

// Only ARRAY_BUFFER here. ELEMENT_ARRAY_BUFFER created below.
ForEach.bufferView(model.gltf, function(bufferView, id) {
if (bufferView.target === WebGLConstants.ARRAY_BUFFER) {
if (bufferView.target === WebGLConstants.ARRAY_BUFFER && !DracoLoader.hasExtension(model)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the extension check needed? Did you run into a situation where a buffer view was marked as ARRAY_BUFFER but shouldn't have been?

@@ -4,13 +4,15 @@ define([
'../Core/IndexDatatype',
'../Core/RuntimeError',
'../ThirdParty/draco-decoder-gltf',
'../ThirdParty/GltfPipeline/byteLengthForComponentType',
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't matter in terms of functionality, but use the Cesium version instead: ComponentDatatype.getSizeInBytes

@@ -288,6 +288,7 @@ define([
* @param {Color} [options.silhouetteColor=Color.RED] The silhouette color. If more than 256 models have silhouettes enabled, there is a small chance that overlapping models will have minor artifacts.
* @param {Number} [options.silhouetteSize=0.0] The size of the silhouette in pixels.
* @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model.
* @param {Boolean} [options.dequantizeInShader=true] Determines if a {@link https://github.com/google/draco|Draco} encoded model is dequantized on the GPU. This decreases total memory usage for encoded models.
Copy link
Contributor

Choose a reason for hiding this comment

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

Mention in CHANGES.md that this flag is added. It can go alongside the Draco bullet.

attributeData = new draco.DracoInt32Array();
// Uint16Array is used becasue there is not currently a way to retreive the maximum
vertexArray = new Int16Array(vertexArrayLength);
dracoDecoder.GetAttributeInt32ForAllPoints(dracoGeometry, attribute, attributeData);
Copy link
Contributor

Choose a reason for hiding this comment

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

When the attribute is oct encoded I think we can use a smaller array length since the number of components should be 2 instead of 3.

Also quantization should use a Uint16Array while oct-encoding should use a Int16Array.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When the attribute is oct encoded, the loader already return 2 for the number of components, so the array length is being set to the correct length.

I have updated Uint16 vs Int16 however.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah ok, I should have checked that myself. Thanks!

@ggetz
Copy link
Contributor Author

ggetz commented Mar 27, 2018

Thanks @lilleyse, updated!

@lilleyse
Copy link
Contributor

Thanks, looks good.

@lilleyse lilleyse merged commit 593af7a into master Mar 27, 2018
@lilleyse lilleyse deleted the draco-quantization branch March 27, 2018 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants