Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 138 additions & 1 deletion src/handlers/threejs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import type { FileData, FileFormat, FormatHandler } from "../FormatHandler.ts";
import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { OBJLoader } from "three/addons/loaders/OBJLoader.js";
import { STLLoader } from "three/addons/loaders/STLLoader.js";
import { PLYLoader } from "three/addons/loaders/PLYLoader.js";
import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
import { ColladaLoader } from "three/addons/loaders/ColladaLoader.js";
import { TDSLoader } from "three/addons/loaders/TDSLoader.js";
import { VRMLLoader } from "three/addons/loaders/VRMLLoader.js";
import type { GLTF } from "three/addons/loaders/GLTFLoader.js";
import type { Collada } from "three/addons/loaders/ColladaLoader.js";

class threejsHandler implements FormatHandler {

Expand Down Expand Up @@ -43,6 +50,85 @@ class threejsHandler implements FormatHandler {
category: "model",
lossless: false,
},
{
name: "Stereolithography",
format: "stl",
extension: "stl",
mime: "model/stl",
from: true,
to: false,
internal: "stl",
category: "model",
lossless: false
},
{
name: "Polygon File Format",
format: "ply",
extension: "ply",
mime: "model/ply",
from: true,
to: false,
internal: "ply",
category: "model",
lossless: false
},
{
name: "Filmbox",
format: "fbx",
extension: "fbx",
mime: "model/fbx",
from: true,
to: false,
internal: "fbx",
category: "model",
lossless: false
},
{
name: "Collada",
format: "dae",
extension: "dae",
mime: "model/vnd.collada+xml",
from: true,
to: false,
internal: "dae",
category: "model",
lossless: false
},
// NEW FORMATS BELOW
{
name: "3D Studio",
format: "3ds",
extension: "3ds",
mime: "model/3ds",
from: true,
to: false,
internal: "3ds",
category: "model",
lossless: false
},
{
name: "VRML",
format: "wrl",
extension: "wrl",
mime: "model/vrml",
from: true,
to: false,
internal: "wrl",
category: "model",
lossless: false
},
{
name: "three.js JSON Object",
format: "json",
extension: "json",
mime: "application/json",
from: true,
to: false,
internal: "json",
category: "model",
lossless: false
},
// Image formats
CommonFormats.PNG.supported("png", false, true),
CommonFormats.JPEG.supported("jpeg", false, true),
CommonFormats.WEBP.supported("webp", false, true)
Expand Down Expand Up @@ -70,7 +156,7 @@ class threejsHandler implements FormatHandler {
const blob = new Blob([inputFile.bytes as BlobPart]);
const url = URL.createObjectURL(blob);

let object: THREE.Group<THREE.Object3DEventMap>;
let object: THREE.Group<THREE.Object3DEventMap> | THREE.Object3D;

switch (inputFormat.internal) {
case "glb": {
Expand All @@ -87,10 +173,60 @@ class threejsHandler implements FormatHandler {
loader.load(url, resolve, undefined, reject);
});
break;
case "stl": {
const geometry: THREE.BufferGeometry = await new Promise((resolve, reject) => {
const loader = new STLLoader();
loader.load(url, resolve, undefined, reject);
});
const material = new THREE.MeshPhongMaterial({ color: 0xaaaaaa });
object = new THREE.Mesh(geometry, material);
break;
}
case "ply": {
const geometry: THREE.BufferGeometry = await new Promise((resolve, reject) => {
const loader = new PLYLoader();
loader.load(url, resolve, undefined, reject);
});
const material = new THREE.MeshPhongMaterial({ color: 0xaaaaaa });
object = new THREE.Mesh(geometry, material);
break;
}
case "fbx":
object = await new Promise((resolve, reject) => {
const loader = new FBXLoader();
loader.load(url, resolve, undefined, reject);
});
break;
case "dae": {
const result: Collada = await new Promise((resolve, reject) => {
const loader = new ColladaLoader();
loader.load(url, resolve, undefined, reject);
});
object = result.scene;
break;
}
case "3ds":
object = await new Promise((resolve, reject) => {
const loader = new TDSLoader();
loader.load(url, resolve, undefined, reject);
});
break;
case "wrl":
object = await new Promise((resolve, reject) => {
const loader = new VRMLLoader();
loader.load(url, resolve, undefined, reject);
});
break;
case "json":
// Use ObjectLoader directly, as it needs the JSON object
const jsonString = new TextDecoder().decode(inputFile.bytes);
object = new THREE.ObjectLoader().parse(JSON.parse(jsonString));
break;
default:
throw new Error("Invalid input format");
}

// Camera placement & rendering
const bbox = new THREE.Box3().setFromObject(object);
bbox.getCenter(this.camera.position);
this.camera.position.z = bbox.max.z * 2;
Expand All @@ -109,6 +245,7 @@ class threejsHandler implements FormatHandler {
const name = inputFile.name.split(".").slice(0, -1).join(".") + "." + outputFormat.extension;
outputFiles.push({ bytes, name });

URL.revokeObjectURL(url);
}

return outputFiles;
Expand Down
Loading