Cesium 源码解析 Model(六)

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

        上一章是关于压缩数据的一种方式,本章讲解第二种使用draco压缩过的几何数据,这部分分两个阶段,第一个阶段是使用wasm+worker的过程,这个过程解析完成后还会在vs中在进行数据处理才能变成普通的顶点属性数据。

        对于draco压缩数据使用的是gltf的extensionsRequired.KHR_draco_mesh_compression扩展,在model.js解析gltf的json中检测到这个标志就会使用wasm+worker处理。

        在model.js中关于draco压缩的数据引用DracoLoader.js类来处理。在model.js中使用了

  1. DracoLoader.hasExtension

  2. DracoLoader.parse

  3. DracoLoader.decodeModel

  4. DracoLoader.cacheDataForModel

  5. 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,              //
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值