阅读 174

ThreeJs入门24-VTKLoader的内部加载过程解析

示例代码采用three.js-r73版本: cdnjs.cloudflare.com/ajax/libs/t…

yuque_diagram (1).jpg

我们已经实战了VTKLoader来加载我们的VTK模型,那么VTKLoader内部是怎么实现的呢,我们来一探究竟。

VTKLoader构造函数

THREE.VTKLoader = function (manager) { this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager; }; THREE.VTKLoader.prototype = { constructor: THREE.VTKLoader, } 复制代码

  • THREE.VTKLoader的原型上设置了构造函数,

    • 可以传入manager参数,这个参数可以自定义加载管理器

    • 如果没有传,就是THREE内部默认的加载管理器THREE.DefaultLoadingManager

THREE.DefaultLoadingManager

  • 我们来看下默认加载管理器做了什么事

THREE.DefaultLoadingManager = new THREE.LoadingManager(); 复制代码

  • 默认加载管理器是实例化的THREE.LoadingManager

THREE.LoadingManager

  • 这个函数中定义了一些变量

THREE.LoadingManager = function (onLoad, onProgress, onError) { // 外层 this 别名 var scope = this; var isLoading = false, itemsLoaded = 0,  // 代表已经加载字节数 itemsTotal = 0; // 代表加载字节总数 this.onStart = undefined;  // 初始化时这个函数没有定义,需要重写 this.onLoad = onLoad; // 加载完成的回调 this.onProgress = onProgress; // 加载进度的回调 this.onError = onError; // 加载错误的回调   .... } 复制代码

  • 需要注意的是itemsLoadeditemsTotal记录的是字节数

  • 整个函数的生命周期是这样的

    • itemStart  加载之前

    • onStart 加载载开始的回调

    • itemEnd 加载结束

    • onLoad 加载完成的回调

itemStart 和 itemEnd 在每次服务器返回数据时调用

// 加载 url  地址 this.itemStart = function (url) {   // 总共加载字节数   itemsTotal++;   // 如果没有加载   if (isLoading === false) {     //      if (scope.onStart !== undefined) {       // url 已经加载的数量 总共加载数量       scope.onStart(url, itemsLoaded, itemsTotal);     }   }   // 设置为正在加载   isLoading = true; }; 复制代码

  • itemStart每次调用会记录总共的加载字节数的总数

  • 如果没有加载,并且有onStart回调,就调用这个方法

  • 把记载状态记为加载中

this.itemEnd = function (url) {   // 已经加载字节数   itemsLoaded++;   if (scope.onProgress !== undefined) {     scope.onProgress(url, itemsLoaded, itemsTotal);   }   // 已经加载的字节数等于总的字节数   if (itemsLoaded === itemsTotal) {     isLoading = false;     if (scope.onLoad !== undefined) {       // 调用onLoad       scope.onLoad();     }   } }; 复制代码

  • itemEnd 会记录已经加载的字节数

  • 如果定义了onProgress回调函数,就调用

  • 如果已经加载的字节数等于了总的字节数,说明加载完成,调用onLoad回调函数

VTKLoader的load方法

  • 介绍完了构造函数,我们来看看VTKLoader的load方法

 /**  *   * @param {*} url url地址  * @param {*} onLoad 加载成功回调  * @param {*} onProgress 加载过程回调  * @param {*} onError 加载错误回调  */ load: function (url, onLoad, onProgress, onError) { var scope = this; // 调用THREE的XHR请求实例,传入了加载管理器 var loader = new THREE.XHRLoader(scope.manager); // 设置cross loader.setCrossOrigin(this.crossOrigin); // 调用加载函数,返回文本数据 loader.load(url, function (text) { // 通过parse解析文本数据,返回geometry onLoad(scope.parse(text)); }, onProgress, onError); }, 复制代码

  • load方法很简单,主要是传入url地址,然后请求资源,调用对应的回调函数

  • 实例化THREE.XHRLoader,请求数据成功之后,返回文本数据,通过parse函数进行解析(下节再详细解释),返回geometry

THREE.XHRLoader

  • 这是THREE内部基于XHR定义的请求加载器

THREE.XHRLoader = function (manager) { this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager; }; THREE.XHRLoader.prototype = { constructor: THREE.XHRLoader,   ... } 复制代码

  • THREE.XHRLoader的构造函数默认使用的也是THREE.DefaultLoadingManager

  • 主要看下load方法

load: function (url, onLoad, onProgress, onError) { var scope = this; // 获取缓存url的数据 var cached = THREE.Cache.get(url); // 如果有缓存的数据,就直接走缓存缓存 if (cached !== undefined) { if (onLoad) { setTimeout(function () { onLoad(cached); }, 0); } return cached; } // 创建 XHR 的 get 请求 var request = new XMLHttpRequest(); request.open('GET', url, true); // 监听加载状态 request.addEventListener('load', function (event) { // 获取到响应数据 var response = event.target.response; // 把url对应的数据缓存起来 THREE.Cache.add(url, response); // 调用 onLoad回调 返回数据 if (onLoad) onLoad(response); // 调用加载结束方法 scope.manager.itemEnd(url); }, false); // 如果我们定义了 onProgress 回调,监听加载进度 if (onProgress !== undefined) { request.addEventListener('progress', function (event) { onProgress(event); }, false); } // 监听加载错误 request.addEventListener('error', function (event) { // 如果定义了 onError回调 就返回对应的数据 if (onError) onError(event);       scope.manager.itemError(url);     }, false); // 设置 cross if (this.crossOrigin !== undefined) request.crossOrigin = this.crossOrigin; // 设置响应类型 if (this.responseType !== undefined) request.responseType = this.responseType; // 设置跨域是否携带凭据 if (this.withCredentials !== undefined) request.withCredentials = this.withCredentials; // 发送请求 request.send(null); // 调用 itemStart 生命周期 scope.manager.itemStart(url); return request; } 复制代码

  • 先是获取缓存数据,如果有缓存数据,就直接返回缓存数据

  • 然后通过创建 XHR 的 get 请求,获取数据,把获取的数据缓存起来

  • 调用生命周期方法,完成回调通知

THREE.Cache

  • three缓存方法实现

THREE.Cache = { enabled: false, // 是否开启缓存 files: {}, // 缓存数据 add: function (key, file) { if (this.enabled === false) return; this.files[key] = file; }, get: function (key) { if (this.enabled === false) return; return this.files[key]; }, remove: function (key) { delete this.files[key]; }, clear: function () { this.files = {}; } }; 复制代码

  • enabled:是否开启缓存的开关

  • files:缓存的数据其实是一个局部作用域的object对象

  • 定义了添加(add),获取(get),移除(remove),清空(clear)方法

函数执行流程

  • 核心函数介绍完了,我们来看下整个VTKloader函数的执行流程

image.png

总结

这一节我们主要讲了以下内容:

  • VTKLoader构造函数

  • THREE.DefaultLoadingManager默认加载器

  • THREE.LoadingManager加载构造器

  • THREE.XHRLoader请求loader

  • THREE.Cache缓存实现

  • VTKLoader请求资源过程


作者:张雨凡
链接:https://juejin.cn/post/7064374061886865421


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐