当前位置: 代码迷 >> 综合 >> 【BABYLON】通过AssetContainer实现预加载模型
  详细解决方案

【BABYLON】通过AssetContainer实现预加载模型

热度:51   发布时间:2024-02-10 22:06:31.0

一、前言

任何的引擎,都离不开场景和资源的概念。实际上,所有的引擎都遵循这么个基本准则:在场景中加载资源,通过交互和逻辑操作资源,完成功能。

因此,要制作游戏或者三维业务系统,首要的工作是要想办法把资源加载到场景中。

加载场景这事,说简单很简单,说复杂也复杂。为什么这么说呢?因为基本上很多引擎都提供了加载的功能,加载、显示,一句话搞定,是不是比较简单?但遇到一些业务场景,最典型的就是在web上的资源动态加载和变化,如果我希望这个加载过程是越少时间越好,该怎么办?这个就不得不提到预加载这个操作。

什么是预加载?

按字面意义来说,就是预先加载的意思。什么时候需要执行预加载?比如说用户正在执行A操作,用到A资源,接下来准备进行B操作,B操作将会涉及B资源。当A操作完毕之后,再去远端服务器下载B资源,这个时候是不是会有一个加载的过程?这个加载的过程,显示在UI上就是一个loading,或者卡顿。这个明显不是一个很好的操作。因此,我们需要在A操作过程中,能预先判断即将进行B操作,然后把B资源下载下来,当B操作需要B资源的时候,能立马从内存中调用出来。这样的处理就会使得切换十分迅速。

所以,我们来看下在BABYLON里面如何实现预加载模型。

 

二、单个资源直接加载

我们先来看看单个资源直接加载是如何实现。SceneLoader对象提供了一个叫做Append的方法,这个方法能直接把资源下载下来,然后直接渲染到场景当中去。

写法如下:

BABYLON.SceneLoader.Append(folder, fileName, scene, function (scene) {// 模型添加成功后,执行场景对象的一些方法console.log("load success");
});

其中,foloder为根目录,fileName为文件名,scene则为目标场景。如果一个模型文件的路径为‘/static/a/file.glb’,则folder可以为‘/static/a/’,文件名为‘file.glb’。

加载之后可以直接在场景中现实。

 

三、资源预加载

资源预加载需要把“加载”和“显示”两个过程分开。显然,append做得太好了,一步到位。而且对于预加载来说,主要有方法能够管控住资源分别是什么。

这里我们使用LoadAssetContainer方法。LoadAssetContainer方法同样属于SceneLoader下的方法,前面三个参数声明都跟Append方法一样,只不过回调函数里面的参数变为了一个AssetContainer对象,而不是scene对象。

BABYLON.SceneLoader.LoadAssetContainer(folder, fileName, scene, function (container) {});

通过LoadAssetContainer方法,我们可以把资源文件下载到内存,并封装在AssetContainer对象里面。通过翻阅API文档,可以看到AssetContainer类支持2个方法,分别为addAllToScene和removeAllFromScene,分别能够将对应的资源加载到场景以及从场景中移除。这就十分便捷了。

下面完整的代码,演示了一个简单的案例,就是先把资源都下载下来,然后定时切换模型的显示。

$(function(){console.log('demo page is ready');var modelDataList = [{modelUrl:'/static/model/LNL/3/LNL3_F1.glb',},{modelUrl:'/static/model/LNL/LNL.glb',},{modelUrl:'/static/model/LNL/3/LNL3_F2.glb',}]var assetContainers = [];var currentSceneIndex = 0; var initScene = function (cameraType) {var canvas = document.getElementById('renderCanvas');var engine = new BABYLON.Engine(canvas, true);var createScene = function () {var scene = new BABYLON.Scene(engine);//默认用3Dvar camera;camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 100, BABYLON.Vector3.Zero(), scene);camera.setPosition(new BABYLON.Vector3(120, 120, 120));camera.attachControl(canvas, false, false);var hemisphericLight = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 100, 0), scene);let loadedModelCount = 0;   //加载成功的模型for (var i = 0; i < modelDataList.length; i++) {var modelData = modelDataList[i];var fullPath = modelData.modelUrl;if(!fullPath){loadedModelCount++;continue;}var idx = fullPath.lastIndexOf('/');var folder = fullPath.substring(0, idx + 1);var fileName = fullPath.substring(idx + 1);BABYLON.SceneLoader.LoadAssetContainer(folder, fileName, scene, function (container) {assetContainers.push(container);loadedModelCount++;if(loadedModelCount==modelDataList.length){//加载完毕}});}return scene;};var scene = createScene();engine.runRenderLoop(function () {scene.render();});window.addEventListener('resize', function () {engine.resize();});var customLoadingUI = new ZFBabylonLoadingScreen();engine.loadingScreen = customLoadingUI;  //改成自定义的loading界面return engine;};initScene();setInterval(function(){assetContainers[currentSceneIndex].removeAllFromScene();currentSceneIndex++;if(currentSceneIndex>=assetContainers.length){currentSceneIndex = 0;}assetContainers[currentSceneIndex].addAllToScene();},2000);});

 

【原创文章,欢迎转载,转载请注明来源】

【码字不易,欢迎关注,共同探讨技术】