上一章是关于压缩数据的一种方式,本章讲解第二种使用draco压缩过的几何数据,这部分分两个阶段,第一个阶段是使用wasm+worker的过程,这个过程解析完成后还会在vs中在进行数据处理才能变成普通的顶点属性数据。
对于draco压缩数据使用的是gltf的extensionsRequired.KHR_draco_mesh_compression扩展,在model.js解析gltf的json中检测到这个标志就会使用wasm+worker处理。
在model.js中关于draco压缩的数据引用DracoLoader.js类来处理。在model.js中使用了
-
DracoLoader.hasExtension
-
DracoLoader.parse
-
DracoLoader.decodeModel
-
DracoLoader.cacheDataForModel
-
DracoLoader.destroyCachedDataForModel
1、对于DracoLoader.hasExtension,主要是用来检测gltf中是否使用了KHR_draco_mesh_compression扩展。
// 使用了Draco压缩扩展
DracoLoader.hasExtension = function (model) {
return (
defined(model.extensionsRequired.KHR_draco_mesh_compression) ||
defined(model.extensionsUsed.KHR_draco_mesh_compression)
);
};
2、DracoLoader.parse用来收集gltf中使用draco压缩过的数据到primitivesToDecode,将这些数据保存在一个队列中,等收集完成后,将所有的数据一个一个的进行解压缩,收集数据的代码如下:
// 解析数据
DracoLoader.parse = function (model, context) {
// 是否存在扩展
if (!DracoLoader.hasExtension(model)) {
return;
}
// 加载资源
var loadResources = model._loadResources;
// 缓存key
var cacheKey = model.cacheKey;
// 缓存
if (defined(cacheKey)) {
// 解码缓存中没有数据
if (!defined(DracoLoader._decodedModelResourceCache)) {
// 上下文的缓存中也没有这个数据
if (!defined(context.cache.modelDecodingCache)) {
// 上下文中创建解码缓存
context.cache.modelDecodingCache = {};
}
// 指向上下文解码缓存
DracoLoader._decodedModelResourceCache = context.cache.modelDecodingCache;
}
// Decoded data for model will be loaded from cache
// 缓存中加载
var cachedData = DracoLoader._decodedModelResourceCache[cacheKey];
if (defined(cachedData)) {
// 引用计数增加
cachedData.count++;
// 正在处理解码缓存
loadResources.pendingDecodingCache = true;
return;
}
}
// 着色器中解析
var dequantizeInShader = model._dequantizeInShader;
var gltf = model.gltf;
// 遍历mesh
ForEach.mesh(gltf, function (mesh, meshId) {
// 遍历primitive
ForEach.meshPrimitive(mesh, function (primitive, primitiveId) {
// 没有扩展
if (!defined(primitive.extensions)) {
return;
}
// 不是压缩过的数据就不用处理了
var compressionData = primitive.extensions.KHR_draco_mesh_compression;
if (!defined(compressionData)) {
return;
}
// 获取bufferView数据
var bufferView = gltf.bufferViews[compressionData.bufferView];
// 获取数据块
var typedArray = arraySlice(
gltf.buffers[bufferView.buffer].extras._pipeline.source,
bufferView.byteOffset,
bufferView.byteOffset + bufferView.byteLength
);
// 存储待解压的draco数据
loadResources.primitivesToDecode.enqueue({
mesh: meshId, // 数据属于哪一个mesh
primitive: primitiveId, // 数据是哪一个primitive的
array: typedArray, // 数据
bufferView: bufferView, // 数据的归属
compressedAttributes: compressionData.attributes, // 压缩过的属性,这些属性对应的数据
dequantizeInShader: dequantizeInShader, // 是否在着色器中解码
});
});
});
};
3、DracoLoader.decodeModel解码draco数据
// 解码模型
DracoLoader.decodeModel = function (model, context) {
// 数据是否压缩过
if (!DracoLoader.hasExtension(model)) {
return when.resolve();
}
// 加载资源
var loadResources = model._loadResources;
// 缓存key
var cacheKey = model.cacheKey;
if (defined(cacheKey) && defined(DracoLoader._decodedModelResourceCache)) {
// 缓存过的数据,不用解码
var cachedData = DracoLoader._decodedModelResourceCache[cacheKey];
// Load decoded data for model when cache is ready
if (defined(cachedData) && loadResources.pendingDecodingCache) {
return when(cachedData.ready, function () {
model._decodedData = cachedData.data;
loadResources.pendingDecodingCache = false;
});
}
// Decoded data for model should be cached when ready
// 还没有准备好
DracoLoader._decodedModelResourceCache[cacheKey] = {
ready: false,
count: 1,
data: undefined,
};
}
// 压缩过的数据不存在就返回
if (loadResources.primitivesToDecode.length === 0) {
// No more tasks to schedule
return when.resolve();
}
// 任务处理器
var decoderTaskProcessor = DracoLoader._getDecoderTaskProcessor();
var decodingPromises = [];
// 调度
var promise = scheduleDecodingTask(
decoderTaskProcessor, // 调度任务
model, // 模型类
loadResources, //

该章节详细介绍了如何使用Draco压缩技术来减小3D模型的体积,通过gltf的KHR_draco_mesh_compression扩展在WebGL环境中进行解码。DracoLoader.js负责检测和处理gltf中的Draco压缩数据,利用WebAssembly和Web Worker进行后台解码,然后将解码后的数据转换回gltf规范的顶点属性。整个过程包括数据收集、解码任务调度和解码结果的格式化,确保模型数据在WebGL中正确渲染。
最低0.47元/天 解锁文章
3204

被折叠的 条评论
为什么被折叠?



