File size: 2,702 Bytes
5b324f1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | import * as THREE from "three";
import { debounce } from "@/utils";
export class ThreeSceneBase {
protected canvasEl: HTMLCanvasElement;
protected containerEl: HTMLDivElement | undefined;
protected renderer: THREE.WebGLRenderer;
protected scene: THREE.Scene;
protected camera: THREE.PerspectiveCamera;
protected requestAnimationFrameId: number = -1;
private resizeObserver: ResizeObserver | undefined;
constructor(canvas: HTMLCanvasElement) {
this.canvasEl = canvas;
this.renderer = new THREE.WebGLRenderer({ canvas });
this.renderer.setSize(canvas.clientWidth, canvas.clientHeight);
this.renderer.setPixelRatio(window.devicePixelRatio);
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(75, canvas.clientWidth / canvas.clientHeight, 0.1, 1000);
// this.renderLoop();
const parentEl = canvas.parentElement;
if (parentEl) {
const tempDivEl = document.createElement("div");
Object.assign(tempDivEl.style, {
position: "relative",
width: "100%",
height: "100%",
});
Object.assign(canvas.style, {
position: "absolute ",
width: "100%",
height: "100%",
left: "0",
top: "0",
});
tempDivEl.append(canvas);
parentEl.append(tempDivEl);
this.containerEl = tempDivEl;
const callback: ResizeObserverCallback = (entries) => {
if (entries.length === 0) return;
const _parentEl = entries[0].target;
if (_parentEl) {
this.renderer.setSize(_parentEl.clientWidth, _parentEl.clientHeight);
this.camera.aspect = _parentEl.clientWidth / _parentEl.clientHeight;
this.camera.updateProjectionMatrix();
}
};
const resizeObserver = new ResizeObserver(debounce(callback.bind(this), 100));
resizeObserver.observe(tempDivEl, {});
this.resizeObserver = resizeObserver;
}
}
protected setLoadingMaskVisible(visible: boolean) {
if (this.containerEl) {
if (visible) this.containerEl.setAttribute("loading", "");
else this.containerEl.removeAttribute("loading");
}
}
protected render() {
this.renderer.render(this.scene, this.camera);
}
protected destroy() {
this.resizeObserver && this.resizeObserver.disconnect();
cancelAnimationFrame(this.requestAnimationFrameId);
this.scene.traverse((object) => {
//@ts-ignore
object.geometry && object.geometry.dispose();
//@ts-ignore
object.texture && object.texture.dispose();
//@ts-ignore
object.material && object.material.dispose();
});
this.scene.clear();
this.renderer.dispose();
this.renderer.forceContextLoss();
let gl = this.renderer.domElement.getContext("webgl");
if (gl) {
const e = gl.getExtension("WEBGL_lose_context");
e && e.loseContext();
gl = null;
}
}
}
|