68 lines
2.0 KiB
TypeScript
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';
|
|
|
|
export function getSupportedExtension(fileName: string): SupportedExt | null {
|
|
const ext = fileName.split('.').pop()?.toLowerCase();
|
|
if (ext === 'glb' || ext === 'obj' || ext === 'stl') return ext;
|
|
return null;
|
|
}
|
|
|
|
export const ACCEPTED_EXTENSIONS = '.glb,.obj,.stl';
|
|
|
|
/**
|
|
* 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 };
|
|
}
|