3D 场景预加载应用实现 | 图扑软件

预加载是在进入正式场景之前提前加载所需模型、材质、图片等资源的技术手段,其核心价值在于消除资源加载等待,确保场景首次渲染即可完整呈现,从而提供无缝、流畅的用户体验。在复杂的 Web 3D 可视化应用中,资源预加载尤为重要,可有效解决首次加载时的卡顿、白屏及交互延迟等问题。
01 预加载实现方案
基础实现原理
HT for Web 中所有资源的请求都会经过 ht.Default.convertURL 方法,该方法提供了统一的资源请求入口:
- 当返回字符串路径时,框架会按此路径发起资源请求;
- 当返回 {data: content} 格式对象时,框架会直接使用 content 作为资源内容。
基于此特性,我们可实现预加载机制。
// 资源缓存映射表 let sourceMap = {}; // 判断是否为本地资源 functionisLocalUrl(url) { return url.startsWith('data:') || url.startsWith('blob:'); } // 重写 convertURL 方法 let oldFunc = ht.Default.convertURL; ht.Default.convertURL = function(url) { if (isLocalUrl(url)) return url; let source = sourceMap[url]; if (source) { return { data: source }; } return oldFunc(url); };
资源加载策略
部分资源预加载
适用于资源量较大但部分关键资源需要优先加载的场景。
// 关键资源列表 let resources = [ "models/model.json", "assets/texture.png", "symbols/symbols.json" ]

全量资源预加载
获取所有已注册资源进行预加载:
functiongetAllResources() { return [ ...Object.keys(ht.Default.getImageMap()), ...Object.keys(ht.Default.getCompTypeMap()), ...Object.keys(ht.Default.getShape3dModelMap()), ...Object.keys(ht.Default.getMaterialMap()), ...Object.keys(ht.Default.getHdrTextureMap()) ]; } let allResources = getAllResources();

资源加载实现
// 资源类型判断 const ResourceType = { IMAGE: /\.(png|jpg|gif|jpeg|bmp|svg)$/i, BUFFER: /\.(fbx|gltf|glb)$/i, HDR: /\.hdr$/i, TGA: /\.tga$/i, JSON: /\.json$/i }; // 资源加载器 class ResourceLoader { constructor(resources) { this.resources = resources; this.loaded = 0; } load() { this.resources.forEach(url => { if (ResourceType.BUFFER.test(url)) { this.loadBuffer(url); } else if(ResourceType.IMAGE.test(url)) { this.loadImage(url); } // 其他资源类型处理... }); } loadBuffer(url) { ht.Default.xhrLoad(url, res => { this.onResourceLoaded(url, res); }, { responseType: 'arraybuffer' }); } // 其他加载方法... onResourceLoaded(url, res) { sourceMap[url] = res; this.loaded++; this.onProgress(this.loaded, this.resources.length); if (this.loaded === this.resources.length) { this.onAllLoaded(); } } // 加载进度回调 onProgress(loaded, total) { console.log(`加载进度: ${loaded}/${total}`); }; onAllLoaded() { console.log("所有资源预加载完成"); // 进入主场景... } }

02 加载页面优化
进度展示设计
class LoadingView { constructor() { this.initView(); } initView() { this.dm = new ht.DataModel(); this.view = new ht.graph.GraphView(this.dm); let style = this.view.getView().style; style.left = "0"; style.right = "0"; style.top = "0"; style.bottom = "0"; document.body.appendChild(this.view.getView()); } // 更新进度 updateProgress(percent) { } // 移除加载页面 remove() { setTimeout(() => { this.view.getView().remove(); this.enterMainScene(); }, 1); } // 进入主场景 enterMainScene() { } }
视觉优化建议
- 进度条设计:使用图标实现平滑动画。

- 背景动画:添加轻量级背景动画提升等待体验。

- 分段进度:将加载过程分为资源加载、场景初始化等阶段。
- 预估时间:基于已加载时间预测剩余时间。
03 性能优化方案
Service Worker 离线缓存
// sw.js let CACHE_NAME = 'ht-resources-v1'; self.addEventListener('fetch', event => { event.respondWith(caches.match(event.request).then(function (response) { if (response !== undefined) { return response; } else { return fetch(event.request).then(function (response) { if (event.request.url.indexOf('storage') != -1) { let responseClone = response.clone(); caches.open(CACHE_NAME).then(function (cache) { cache.put(event.request, responseClone); }); } return response; }).catch(function () { return caches.match('./'); }); } })); }); self.addEventListener('activate', function (event) { event.waitUntil(clients.claim()); event.waitUntil(caches.keys().then(function (keyList) { returnPromise.all(keyList.map(function (key) { if (key !== CACHE_NAME) { // 删除旧缓存 return caches.delete(key); } })); })); });
资源压缩策略
- 模型优化:轻量化模型,对模型进行减面。
- 图片优化:图片资源压缩。
04 效果对比与总结
加载效果对比
预加载方案虽然初始显示时间较长,但提供了更优的整体用户体验:
- 完整的场景一次性呈现,避免零碎加载造成的视觉割裂。
- 无卡顿的交互体验,所有资源已就绪。
- 可控的等待预期,进度反馈降低用户焦虑。
- 更稳定的性能表现,避免运行时资源加载导致的卡顿。

适用场景
- 大型 3D 场景:包含复杂模型和纹理的场景。

- 仪表盘应用:需要快速响应的监控系统。
- 移动端应用:网络条件不稳定的环境。
- 演示系统:需要流畅演示效果的场合。
实施建议
- 分阶段实施:先对关键资源预加载,再逐步扩展。
- 性能监控:添加加载时间统计和分析。
- A/B 测试:对比不同策略的实际效果。
总结
综上所述,本预加载方案能显著提升 HT for Web 应用的加载性能和用户体验,特别适合对流畅性要求高的可视化应用场景。在实际项目中,应根据资源规模和用户场景灵活调整预加载策略,平衡加载时间和用户体验。

浙公网安备 33010602011771号