166 lines
5.2 KiB
TypeScript
166 lines
5.2 KiB
TypeScript
import {TilesRenderer} from "3d-tiles-renderer";
|
|
import {GLTFExtensionsPlugin,GLTFMeshFeaturesExtension,GLTFStructuralMetadataExtension,TilesFadePlugin,DebugTilesPlugin,UnloadTilesPlugin} from "3d-tiles-renderer/plugins";
|
|
import Loader from "@/core/loader/Loader.ts";
|
|
import {PerspectiveCamera, WebGLRenderer, Group, JSONMeta} from "three";
|
|
import {deepAssign} from "@/utils";
|
|
|
|
export default class Tiles extends Group{
|
|
type = "TilesGroup";
|
|
isTilesGroup = true;
|
|
|
|
// 默认配置
|
|
options: ITiles.options = {
|
|
url:"",
|
|
reset2origin:true,
|
|
debug:false,
|
|
name:"Tiles",
|
|
errorTarget: 6,
|
|
LRUCache:{
|
|
maxSize: 4000,
|
|
minSize: 3000,
|
|
maxBytesSize: 0.4 * 2**30,
|
|
minBytesSize: 0.3 * 2**30,
|
|
}
|
|
};
|
|
|
|
renderer: TilesRenderer;
|
|
|
|
constructor(options:ITiles.options) {
|
|
super();
|
|
|
|
if(!options.url){
|
|
throw new Error('[Astral 3D]: No url provided.');
|
|
}
|
|
|
|
deepAssign(this.options,options);
|
|
|
|
this.name = this.options.name as string;
|
|
|
|
this.renderer = this.initRenderer();
|
|
this.add(this.renderer.group);
|
|
}
|
|
|
|
get group(){
|
|
return this.renderer.group;
|
|
}
|
|
|
|
/**
|
|
* 初始化Tiles渲染器
|
|
*/
|
|
initRenderer():TilesRenderer{
|
|
const tilesRenderer = new TilesRenderer(this.options.url);
|
|
tilesRenderer.fetchOptions.mode = 'cors';
|
|
tilesRenderer.errorTarget = this.options.errorTarget || 6;
|
|
// LRUCache
|
|
if(this.options.LRUCache){
|
|
tilesRenderer.lruCache.maxSize = this.options.LRUCache.maxSize || 800;
|
|
tilesRenderer.lruCache.minSize = this.options.LRUCache.minSize || 600;
|
|
tilesRenderer.lruCache.maxBytesSize = this.options.LRUCache.maxBytesSize || 0.4 * 2**30;
|
|
tilesRenderer.lruCache.minBytesSize = this.options.LRUCache.minBytesSize || 0.3 * 2**30;
|
|
}
|
|
|
|
// isTilesGroup是只读的,此处绕过 readonly,防止编译报错
|
|
(tilesRenderer.group as { isTilesGroup: boolean }).isTilesGroup = false;
|
|
(tilesRenderer.group as { type: string }).type = "Tiles";
|
|
tilesRenderer.group.isTiles = true;
|
|
tilesRenderer.group.proxy = this;
|
|
|
|
tilesRenderer.registerPlugin(new GLTFExtensionsPlugin({
|
|
dracoLoader: Loader.dracoLoader,
|
|
ktxLoader: Loader.ktx2Loader,
|
|
plugins:[() => new GLTFMeshFeaturesExtension(),() => new GLTFStructuralMetadataExtension()]
|
|
}));
|
|
// Loader.createGLTFLoader(tilesRenderer.manager).then(loader => {
|
|
// loader.register(() => new GLTFMeshFeaturesExtension());
|
|
// loader.register(() => new GLTFStructuralMetadataExtension());
|
|
// tilesRenderer.manager.addHandler( /\.(gltf|glb)$/g, loader );
|
|
// })
|
|
|
|
// 瓦片渐显隐
|
|
tilesRenderer.registerPlugin(new TilesFadePlugin());
|
|
// 从gpu卸载不可见瓦片数据,cpu上仍然存在
|
|
tilesRenderer.registerPlugin(new UnloadTilesPlugin());
|
|
if(this.options.debug){
|
|
// 注册调试插件
|
|
tilesRenderer.registerPlugin(new DebugTilesPlugin());
|
|
// 获取调试插件
|
|
const debugTilesPlugin = tilesRenderer.getPluginByName('DEBUG_TILES_PLUGIN') as DebugTilesPlugin;
|
|
// 显示包围盒的线框
|
|
debugTilesPlugin.displayBoxBounds = true;
|
|
}
|
|
|
|
// 子级瓦片加载
|
|
tilesRenderer.addEventListener('load-model', (e) => {
|
|
e.scene.traverse(c => {
|
|
c.isTiles = true;
|
|
// 子级瓦片不允许选中,添加proxy属性让点击此瓦片时选中此组
|
|
c.proxy = this;
|
|
|
|
if(c.type === "Group"){
|
|
(c as { type: string }).type = "Tiles";
|
|
}else{
|
|
(c as { type: string }).type = "Tile";
|
|
}
|
|
})
|
|
});
|
|
|
|
tilesRenderer.addEventListener("load-error", (e) => {
|
|
console.error(`${tilesRenderer.group.name} load error:`, e);
|
|
});
|
|
|
|
return tilesRenderer;
|
|
}
|
|
|
|
/**
|
|
* 设置相机和渲染器
|
|
*/
|
|
setCameraAndRenderer(camera:PerspectiveCamera,renderer:WebGLRenderer){
|
|
this.renderer.setCamera(camera);
|
|
this.renderer.setResolutionFromRenderer(camera, renderer);
|
|
}
|
|
|
|
/**
|
|
* 重写clone方法,因为要接收参数
|
|
*/
|
|
clone(recursive: boolean = true) {
|
|
// 断言为可构造类型
|
|
const Ctor = this.constructor as new (opts: ITiles.options) => this;
|
|
return new Ctor(this.options).copy(this, recursive);
|
|
}
|
|
|
|
/**
|
|
* 重写toJSON
|
|
*/
|
|
toJSON(meta?: JSONMeta){
|
|
const json = super.toJSON(meta);
|
|
json.object.type= "TilesGroup";
|
|
json.object.options = this.options;
|
|
|
|
return json;
|
|
}
|
|
|
|
static fromJSON(data: { options: ITiles.options,[s:string]:any },copyAttr = true){
|
|
const tiles = new Tiles(data.options);
|
|
|
|
if(copyAttr){
|
|
data.children = undefined;
|
|
Loader.objectLoader.copyAttrByData(tiles,data);
|
|
}
|
|
|
|
return tiles;
|
|
}
|
|
|
|
/**
|
|
* 更新/渲染Tiles
|
|
*/
|
|
update(){
|
|
this.renderer.update();
|
|
}
|
|
|
|
/**
|
|
* 自我销毁
|
|
*/
|
|
dispose(){
|
|
this.renderer.dispose();
|
|
}
|
|
} |