TkAstral3D/packages/sdk/lib/core/objects/Tile.ts
2025-10-04 23:36:07 +08:00

159 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {TilesRenderer} from "3d-tiles-renderer";
import {GLTFExtensionsPlugin,DebugTilesPlugin} 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: 5,
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,
}));
// Loader.createGLTFLoader(tilesRenderer.manager).then(loader => {
// tilesRenderer.manager.addHandler( /\.(gltf|glb)$/g, loader );
// })
// 子级瓦片加载
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);
});
if(this.options.debug){
// 注册调试插件
tilesRenderer.registerPlugin(new DebugTilesPlugin());
// 获取调试插件
const debugTilesPlugin = tilesRenderer.getPluginByName('DEBUG_TILES_PLUGIN') as DebugTilesPlugin;
// 显示包围盒的线框
debugTilesPlugin.displayBoxBounds = true;
}
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();
}
}