File size: 5,269 Bytes
ebb3bda 3b7903d ebb3bda 95af024 ebb3bda 95af024 ebb3bda 3b7903d ebb3bda bdef08e ebb3bda 4e1da8c ebb3bda bdef08e ebb3bda 3b7903d ebb3bda 3b7903d |
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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
import type { IViewer } from "./IViewer";
import * as BABYLON from "@babylonjs/core";
import "@babylonjs/loaders/glTF";
import "@babylonjs/loaders/OBJ";
export class BabylonViewer implements IViewer {
canvas: HTMLCanvasElement;
engine: BABYLON.Engine;
scene: BABYLON.Scene;
camera: BABYLON.ArcRotateCamera;
triangleCount: number = 0;
constructor(canvas: HTMLCanvasElement) {
this.canvas = canvas;
this.engine = new BABYLON.Engine(canvas, true);
this.scene = new BABYLON.Scene(this.engine);
this.scene.clearColor = BABYLON.Color4.FromHexString("#1A1B1EFF");
this.camera = new BABYLON.ArcRotateCamera(
"camera",
Math.PI / 3,
Math.PI / 3,
30,
BABYLON.Vector3.Zero(),
this.scene
);
this.camera.angularSensibilityY = 1000;
this.camera.panningSensibility = 500;
this.camera.wheelPrecision = 5;
this.camera.inertia = 0.9;
this.camera.panningInertia = 0.9;
this.camera.lowerRadiusLimit = 3;
this.camera.upperRadiusLimit = 100;
this.camera.setTarget(BABYLON.Vector3.Zero());
this.camera.attachControl(this.canvas, true);
this.camera.onAfterCheckInputsObservable.add(() => {
this.camera.wheelPrecision = 150 / this.camera.radius;
this.camera.panningSensibility = 10000 / this.camera.radius;
});
this.handleResize = this.handleResize.bind(this);
window.addEventListener("resize", this.handleResize);
}
handleResize() {
this.engine.resize();
}
async loadScene(url: string, loadingBarCallback?: (progress: number) => void) {
// Load scene
await BABYLON.SceneLoader.AppendAsync("", url, this.scene, (event) => {
const progress = event.loaded / event.total;
loadingBarCallback?.(progress);
});
// Dispose of all cameras and lights
this.scene.cameras.forEach((camera) => {
if (camera !== this.camera) {
camera.dispose();
}
});
this.scene.lights.forEach((light) => {
light.dispose();
});
// Add lights
const light = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), this.scene);
light.intensity = 1;
light.diffuse = new BABYLON.Color3(1, 1, 1);
light.groundColor = new BABYLON.Color3(0.3, 0.3, 0.3);
const sun = new BABYLON.DirectionalLight("sun", new BABYLON.Vector3(-0.5, -1, -0.5), this.scene);
sun.intensity = 2;
sun.diffuse = new BABYLON.Color3(1, 1, 1);
// Center and scale model
const parentNode = new BABYLON.TransformNode("parent", this.scene);
const standardSize = 10;
let scaleFactor = 1;
let center = BABYLON.Vector3.Zero();
if (this.scene.meshes.length > 0) {
let bounds = this.scene.meshes[0].getBoundingInfo().boundingBox;
let min = bounds.minimumWorld;
let max = bounds.maximumWorld;
for (let i = 1; i < this.scene.meshes.length; i++) {
bounds = this.scene.meshes[i].getBoundingInfo().boundingBox;
min = BABYLON.Vector3.Minimize(min, bounds.minimumWorld);
max = BABYLON.Vector3.Maximize(max, bounds.maximumWorld);
}
const extent = max.subtract(min).scale(0.5);
const size = extent.length();
center = BABYLON.Vector3.Center(min, max);
scaleFactor = standardSize / size;
}
this.triangleCount = 0;
this.scene.meshes.forEach((mesh) => {
mesh.setParent(parentNode);
if (mesh.getTotalVertices() > 0) {
this.triangleCount += mesh.getTotalIndices() / 3;
}
});
parentNode.position = center.scale(-1 * scaleFactor);
parentNode.scaling.scaleInPlace(scaleFactor);
// Run render loop
this.engine.runRenderLoop(() => {
this.scene.render();
});
}
dispose() {
if (this.scene) {
this.scene.dispose();
}
if (this.engine) {
this.engine.dispose();
}
window.removeEventListener("resize", this.handleResize);
}
async capture(): Promise<string | null> {
if (!this.engine || !this.camera) return null;
const cachedColor = this.scene.clearColor;
this.scene.clearColor = BABYLON.Color4.FromHexString("#00000000");
let data = await new Promise<string>((resolve) => {
BABYLON.Tools.CreateScreenshotUsingRenderTarget(this.engine, this.camera, 512, (result) => {
resolve(result);
});
});
this.scene.clearColor = cachedColor;
return data;
}
setRenderMode(mode: string) {
this.scene.forceWireframe = mode === "wireframe";
}
getStats(): { name: string; value: any }[] {
const fps = this.engine.getFps().toFixed();
const triangleCount = this.triangleCount.toLocaleString();
return [
{ name: "FPS", value: fps },
{ name: "Triangles", value: triangleCount },
];
}
}
|