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 Fixes #6341

Merged
merged 7 commits into from
Mar 19, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
Binary file added Apps/SampleData/models/DracoCompressed/0.bin
Binary file not shown.
574 changes: 574 additions & 0 deletions Apps/SampleData/models/DracoCompressed/CesiumMilkTruck.gltf

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions Apps/Sandcastle/gallery/3D Models.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
onselect : function() {
createModel('../../SampleData/models/CesiumMan/Cesium_Man.glb', 0);
}
}, {
text : 'Draco Compressed Model',
onselect : function() {
createModel('../../SampleData/models/DracoCompressed/CesiumMilkTruck.gltf', 0);
}
}];

Sandcastle.addToolbarMenu(options);
Expand Down
97 changes: 46 additions & 51 deletions Source/Scene/DracoLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,44 +43,62 @@ define([
|| defined(model.extensionsUsed.KHR_draco_mesh_compression));
}

function addBufferToModelResources(model, buffer) {
var resourceBuffers = model._rendererResources.buffers;
var bufferViewId = Object.keys(resourceBuffers).length;
resourceBuffers[bufferViewId] = buffer;
model._geometryByteLength += buffer.sizeInBytes;
function addBufferToLoadResources(loadResources, typedArray) {
// Create a new id to differentiate from original glTF bufferViews
var bufferViewId = 'runtime.' + Object.keys(loadResources.createdBufferViews).length;

var loadResourceBuffers = loadResources.buffers;
var id = Object.keys(loadResourceBuffers).length;
loadResourceBuffers[id] = typedArray;
loadResources.createdBufferViews[bufferViewId] = {
buffer : id,
byteOffset : 0,
byteLength : typedArray.byteLength
};

return bufferViewId;
}

function addNewVertexBuffer(typedArray, model, context) {
var vertexBuffer = Buffer.createVertexBuffer({
context : context,
typedArray : typedArray,
usage : BufferUsage.STATIC_DRAW
});
vertexBuffer.vertexArrayDestroyable = false;

return addBufferToModelResources(model, vertexBuffer);
var loadResources = model._loadResources;
var id = addBufferToLoadResources(loadResources, typedArray);
loadResources.vertexBuffersToCreate.enqueue(id);
return id;
}

function addNewIndexBuffer(typedArray, model, context) {
var indexBuffer = Buffer.createIndexBuffer({
context : context,
typedArray : typedArray,
usage : BufferUsage.STATIC_DRAW,
indexDatatype : ComponentDatatype.fromTypedArray(typedArray)
function addNewIndexBuffer(indexArray, model, context) {
var typedArray = indexArray.typedArray;
var loadResources = model._loadResources;
var id = addBufferToLoadResources(loadResources, typedArray);
loadResources.indexBuffersToCreate.enqueue({
id : id,
componentType : ComponentDatatype.fromTypedArray(typedArray)
});
indexBuffer.vertexArrayDestroyable = false;

var bufferViewId = addBufferToModelResources(model, indexBuffer);
return {
bufferViewId: bufferViewId,
numberOfIndices : indexBuffer.numberOfIndices
bufferViewId : id,
numberOfIndices : indexArray.numberOfIndices
};
}

function addDecodededBuffers(primitive, model, context) {
return function (result) {
function scheduleDecodingTask(decoderTaskProcessor, model, loadResources, context) {
var taskData = loadResources.primitivesToDecode.peek();
if (!defined(taskData)) {
// All primitives are processing
return;
}

var promise = decoderTaskProcessor.scheduleTask(taskData, [taskData.array.buffer]);
if (!defined(promise)) {
// Cannot schedule another task this frame
return;
}

loadResources.activeDecodingTasks++;
loadResources.primitivesToDecode.dequeue();
return promise.then(function (result) {
loadResources.activeDecodingTasks--;

var decodedIndexBuffer = addNewIndexBuffer(result.indexArray, model, context);

var attributes = {};
Expand All @@ -98,29 +116,12 @@ define([
}
}

model._decodedData[primitive.mesh + '.primitive.' + primitive.primitive] = {
model._decodedData[taskData.mesh + '.primitive.' + taskData.primitive] = {
bufferView : decodedIndexBuffer.bufferViewId,
numberOfIndices : decodedIndexBuffer.numberOfIndices,
attributes : attributes
};
};
}

function scheduleDecodingTask(decoderTaskProcessor, model, loadResources, context) {
var taskData = loadResources.primitivesToDecode.peek();
if (!defined(taskData)) {
// All primitives are processing
return;
}

var promise = decoderTaskProcessor.scheduleTask(taskData, [taskData.array.buffer]);
if (!defined(promise)) {
// Cannot schedule another task this frame
return;
}

loadResources.primitivesToDecode.dequeue();
return promise.then(addDecodededBuffers(taskData, model, context));
});
}

/**
Expand All @@ -135,8 +136,6 @@ define([
}

var loadResources = model._loadResources;
loadResources.decoding = true;

var gltf = model.gltf;
ForEach.mesh(gltf, function(mesh, meshId) {
ForEach.meshPrimitive(mesh, function(primitive, primitiveId) {
Expand All @@ -151,7 +150,6 @@ define([

var bufferView = gltf.bufferViews[compressionData.bufferView];
var typedArray = arraySlice(gltf.buffers[bufferView.buffer].extras._pipeline.source, bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength);

loadResources.primitivesToDecode.enqueue({
mesh : meshId,
primitive : primitiveId,
Expand Down Expand Up @@ -187,10 +185,7 @@ define([
promise = scheduleDecodingTask(decoderTaskProcessor, model, loadResources, context);
}

return when.all(decodingPromises).then(function () {
// Done decoding when there are no more active tasks
loadResources.decoding = (decoderTaskProcessor._activeTasks !== 0);
});
return when.all(decodingPromises);
};

return DracoLoader;
Expand Down
67 changes: 52 additions & 15 deletions Source/Scene/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,21 @@ define([
* resources are created.
* </p>
* <p>
* For high-precision rendering, Cesium supports the CESIUM_RTC extension, which introduces the
* Cesium supports glTF assets with the following extensions:
* <ul>
* <li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_binary_glTF/README.md|KHR_binary_glTF}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_materials_common/README.md|KHR_materials_common}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression}
* </li>
* </ul>
* </p>
* <p>
* For high-precision rendering, Cesium supports the {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/CESIUM_RTC/README.md|CESIUM_RTC} extension, which introduces the
* CESIUM_RTC_MODELVIEW parameter semantic that says the node is in WGS84 coordinates translated
* relative to a local origin.
* </p>
Expand Down Expand Up @@ -1072,7 +1086,21 @@ define([
* KHR_binary_glTF extension with a .glb extension.
* </p>
* <p>
* For high-precision rendering, Cesium supports the CESIUM_RTC extension, which introduces the
* Cesium supports glTF assets with the following extensions:
* <ul>
* <li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_binary_glTF/README.md|KHR_binary_glTF}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_materials_common/README.md|KHR_materials_common}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression}
* </li>
* </ul>
* </p>
* <p>
* For high-precision rendering, Cesium supports the {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/CESIUM_RTC/README.md|CESIUM_RTC} extension, which introduces the
* CESIUM_RTC_MODELVIEW parameter semantic that says the node is in WGS84 coordinates translated
* relative to a local origin.
* </p>
Expand Down Expand Up @@ -1715,6 +1743,11 @@ define([
var bufferViews = model.gltf.bufferViews;
var bufferView = bufferViews[bufferViewId];

// Use bufferView created at runtime
if (!defined(bufferView)) {
bufferView = loadResources.createdBufferViews[bufferViewId];
}

var vertexBuffer = Buffer.createVertexBuffer({
context : context,
typedArray : loadResources.getBuffer(bufferView),
Expand Down Expand Up @@ -1752,6 +1785,11 @@ define([
var bufferViews = model.gltf.bufferViews;
var bufferView = bufferViews[bufferViewId];

// Use bufferView created at runtime
if (!defined(bufferView)) {
bufferView = loadResources.createdBufferViews[bufferViewId];
}

var indexBuffer = Buffer.createIndexBuffer({
context : context,
typedArray : loadResources.getBuffer(bufferView),
Expand Down Expand Up @@ -4206,21 +4244,8 @@ define([
processModelMaterialsCommon(this.gltf, options);
processPbrMetallicRoughness(this.gltf, options);

// Start draco decoding
DracoLoader.parse(this);

loadResources.initialized = true;
}

if (!loadResources.finishedDecoding()) {
DracoLoader.decode(this, context)
.otherwise(getFailedLoadFunction(this, 'model', this.basePath));
}

if (loadResources.finishedDecoding() && !loadResources.resourcesParsed) {
// We do this after to make sure that the ids don't change
addBuffersToLoadResources(this);

if (!this._loadRendererResourcesFromCache) {
parseBufferViews(this);
parseShaders(this);
Expand All @@ -4231,6 +4256,18 @@ define([
parseMeshes(this);
parseNodes(this);

// Start draco decoding
DracoLoader.parse(this);

loadResources.initialized = true;
}

if (!loadResources.finishedDecoding()) {
DracoLoader.decode(this, context)
.otherwise(getFailedLoadFunction(this, 'model', this.basePath));
}

if (loadResources.finishedDecoding() && !loadResources.resourcesParsed) {
this._boundingSphere = computeBoundingSphere(this);
this._initialRadius = this._boundingSphere.radius;

Expand Down
5 changes: 3 additions & 2 deletions Source/Scene/ModelLoadResources.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ define([
this.createUniformMaps = true;
this.createRuntimeNodes = true;

this.decoding = false;
this.createdBufferViews = {};
this.primitivesToDecode = new Queue();
this.activeDecodingTasks = 0;

this.skinnedNodesIds = [];
}
Expand Down Expand Up @@ -89,7 +90,7 @@ define([
};

ModelLoadResources.prototype.finishedDecoding = function() {
return !this.decoding && this.primitivesToDecode.length === 0;
return this.primitivesToDecode.length === 0 && this.activeDecodingTasks === 0;
};

ModelLoadResources.prototype.finished = function() {
Expand Down
11 changes: 8 additions & 3 deletions Source/Workers/decodeDraco.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,25 @@ define([
var numFaces = dracoGeometry.num_faces();

var faceIndices = new draco.DracoInt32Array();
var indexArray = IndexDatatype.createTypedArray(numPoints, numFaces * 3);
var numIndices = numFaces * 3;
var indexArray = IndexDatatype.createTypedArray(numPoints, numIndices);

var offset = 0;
for (var i = 0; i < numFaces; ++i) {
dracoDecoder.GetFaceFromMesh(dracoGeometry, i, faceIndices);

var offset = i * 3;
indexArray[offset + 0] = faceIndices.GetValue(0);
indexArray[offset + 1] = faceIndices.GetValue(1);
indexArray[offset + 2] = faceIndices.GetValue(2);
offset += 3;
}

draco.destroy(faceIndices);

return indexArray;
return {
typedArray : indexArray,
numberOfIndices : numIndices
};
}

function decodeAttributeData(dracoGeometry, compressedAttributes) {
Expand Down