多模型加载管理器LoadingManager
加载多个模型
在上一篇我们讲到,加载模型是个异步,那么,我们如果想监控多个模型的加载进度,是否就会变的麻烦
以下是笔者早期的写法
let r = 0;
let modelNum = 3;//你要加载几个模型
loader.load("model1",()=>{
r++;
//修改进度条
//加载后的逻辑...
if(r===3){
//全部加载完毕后的逻辑
onLoad();
}
});
loader.load("model2")...
loader.load("model3")...
function onLoad(){
//模型全部加载完成后的逻辑
}
或者我们可以使用ES6提供的异步的写法
function loadModel(path){
return new Promise((resolve)=>{
loader.load(path,(obj)=>{
resolve(obj)
})
})
}
async function addMesh(){
let model = await loadModel("./model1.obj");
let model2 = await loadModel("./model2.obj");
let model3 = await loadModel("./model2.obj");
//此处为模型的处理逻辑
scene.add(model);
scene.add(model2);
scene.add(model3);
}
以上方法均可以实现对多个模型的加载控制,但是官方有提供专有写法,LoadingManager
LoadingManager案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas{
display: block;
}
body {
margin: 0;
overscroll-behavior: none;
}
#btns{
position: absolute;
top:10%;
width: 500px;
height: 100px;
left: 50%;
transform:translateX(-50%);
}
</style>
</head>
<body>
<div id="btns"></div>
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "../../three.js-master/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from '../../three.js-master/build/three.module.js';
import {OrbitControls} from "../../three.js-master/examples/jsm/controls/OrbitControls.js";
import {OBJLoader} from "../../three.js-master/examples/jsm/loaders/OBJLoader.js";
let scene,renderer,camera,orbitControls;
let loadingManager = new THREE.LoadingManager();
let loader = new OBJLoader(loadingManager);
function init(){
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({
antialias:true
});
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.1,50000);
camera.position.set(10,10,10);
orbitControls = new OrbitControls(camera,renderer.domElement);
let helper = new THREE.AxesHelper(5);
scene.add(helper);
let light = new THREE.PointLight();
camera.add(light);
scene.add(camera);
loadingManager.onStart = (url,itemsLoaded,itemsTotal)=>{
//模型开始加载时执行的函数
console.log(`开始加载模型:${url},当前已加载模型:${itemsLoaded},总模型数:${itemsTotal}`);
}
loadingManager.onProgress = (url,itemsLoaded,itemsTotal)=>{
console.log(`${url}已加载完成,当前已加载模型:${itemsLoaded},总模型数:${itemsTotal}`);
}
loadingManager.onError = (url)=>{
console.log("加载模型时出现错误,错误的模型:"+url)
}
}
function addMesh(){
let modelList = [
"./tree.obj",
"./emerald.obj"
];
for(let i = 0;i< modelList.length;i++){
loader.load(modelList[i],(obj)=>{
scene.add(obj);
obj.position.x = Math.random() * 10 - 5;
obj.position.z = Math.random() * 10 - 5;
})
}
}
function render(){
renderer.render(scene,camera);
requestAnimationFrame(render);
}
init();
addMesh();
render();
</script>
</body>
</html>
案例效果
console内容
LoadingManager的主要用途是用于做进度条,当你加载的模型过多时,建议使用LoadingManager来做管理
平常的前端开发我们很少会遇到,但是我们在玩游戏的时候,经常会遇到一个东西,叫【加载资源中】,当加载资源的时候,一般这些程序都会给你一个进度条,这个进度条,其实就是类似于加载管理器这样的程序,在监控加载进度,这个进度包括了网络传输,以及文件上载到内存的这个过程,当整个过程全部完成后,我们就进入了游戏(程序)中
一般来说, 笔者建议把加载模型放到整个程序运行步骤的最前面,待模型整体加载完成后,然后再执行init()去初始化必要变量scene,renderer,camera等,这样可以保证我们的程序,不会在处理模型的代码上,遇到【模型未加载完成就使用】的相关问题
案例分析
其他的代码均在前面的文章中已经分析完毕,本文仅针对新出现的代码进行分析
function init(){
//...
loadingManager = new THREE.LoadingManager();
loader = new OBJLoader(loadingManager);
loadingManager.onStart = (url,itemsLoaded,itemsTotal)=>{
//模型开始加载时执行的函数
console.log(`开始加载模型:${url},当前已加载模型:${itemsLoaded},总模型数:${itemsTotal}`);
}
loadingManager.onProgress = (url,itemsLoaded,itemsTotal)=>{
console.log(`${url}已加载完成,当前已加载模型:${itemsLoaded},总模型数:${itemsTotal}`);
}
loadingManager.onError = (url)=>{
console.log("加载模型时出现错误,错误的模型:"+url)
}
}
构造器:LoadingManager( onLoad : Function, onProgress : Function, onError : Function )
onLoad:加载完成时执行的函数
onProgress:加载完成一个资源文件时执行的函数
onError:加载失败时执行的函数
这三个函数均为可选,可以都为空,这里建议为空,笔者更喜欢在下面修改它的这几个参数
属性名 | 值类型 | 默认值 | 函数返回值 | 说明 |
---|---|---|---|---|
onStart | 函数Function | null | url: 开始加载的模型地址 itemsLoaded: 当前已加载完的资源文件总数(根据不同的格式,模型的资源文件数量会有所不同,部分模型会压缩资源文件到一个单独的模型文件中) itemsTotal: 模型加载总数 | 该函数在所有的模型开始加载时启用,启用时,将显示当前已加载的模型总数,如果是第一次加载模型,itemsLoaded会显示为0,该函数会在开始加载模型时执行一次 |
onProgress | 函数Function | null | url,itemsLoaded,itemsTotal | onProgress是在一个资源文件加载完成时会执行,如果你的资源文件的数量大于1,这个函数将在整个加载过程中,执行多次,使用itemsLoaded/itemsTotal 会得到一个当前的加载比例,保留两位小数后,可以作为加载进度条的百分比数值来使用 |
onLoad | 函数Function | null | 无 | 该函数会在所有模型加载完成后执行 |
onError | 函数Function | null | error | 该函数会在任意模型发生错误时执行,且加载错误的模型不会影响整体的模型加载,比如你加载了5个模型,第三个模型发生错误,但是LoadingManager依旧会执行下去,并将加载错误的第三个模型的错误信息以该函数的返回值的形式返回 |
上述四个函数,与ObjLoader以及所有的文件相关的Loader的四个函数有一定区别,注意区分