Files
SteelXR/src/lib/convertToGLB.ts
T
gpt-engineer-app[bot] 11f16eff5a Changes
2026-02-27 02:36:49 +00:00

68 lines
2.0 KiB
TypeScript

import * as THREE from 'three';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
type SupportedExt = 'glb' | 'obj' | 'stl' | 'ifc';
export function getSupportedExtension(fileName: string): SupportedExt | null {
const ext = fileName.split('.').pop()?.toLowerCase();
if (ext === 'glb' || ext === 'obj' || ext === 'stl' || ext === 'ifc') return ext;
return null;
}
export const ACCEPTED_EXTENSIONS = '.glb,.obj,.stl,.ifc';
/**
* Convert an OBJ or STL file (ArrayBuffer) into a GLB Blob.
* GLB files are returned as-is from their original blob.
*/
export async function convertToGLB(
buffer: ArrayBuffer,
ext: 'obj' | 'stl',
fileName: string
): Promise<{ blob: Blob; fileName: string; fileSize: number }> {
const scene = new THREE.Scene();
const material = new THREE.MeshStandardMaterial({
color: 0x8899aa,
metalness: 0.85,
roughness: 0.35,
});
if (ext === 'stl') {
const loader = new STLLoader();
const geometry = loader.parse(buffer);
geometry.computeVertexNormals();
const mesh = new THREE.Mesh(geometry, material);
mesh.name = fileName.replace(/\.stl$/i, '');
scene.add(mesh);
} else {
const loader = new OBJLoader();
const text = new TextDecoder().decode(buffer);
const obj = loader.parse(text);
obj.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material = material;
}
});
obj.name = fileName.replace(/\.obj$/i, '');
scene.add(obj);
}
const exporter = new GLTFExporter();
const glb = await new Promise<ArrayBuffer>((resolve, reject) => {
exporter.parse(
scene,
(result) => resolve(result as ArrayBuffer),
(error) => reject(error),
{ binary: true }
);
});
const glbFileName = fileName.replace(/\.(obj|stl)$/i, '.glb');
const blob = new Blob([glb], { type: 'model/gltf-binary' });
return { blob, fileName: glbFileName, fileSize: blob.size };
}