You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
6.8 KiB
164 lines
6.8 KiB
import * as THREE from 'three';
|
|
import { GLTFLoader } from 'three/examples/jsm/Addons.js';
|
|
import { DRACOLoader } from 'three/examples/jsm/Addons.js';
|
|
import { createCustomJitterMaterial } from './materials/CustomJitterMaterial';
|
|
import { TextureLoader } from 'three';
|
|
|
|
export class ModelLoader {
|
|
constructor() {
|
|
this.gltfLoader = new GLTFLoader();
|
|
this.textureLoader = new TextureLoader();
|
|
const dracoLoader = new DRACOLoader();
|
|
dracoLoader.setDecoderPath('/draco/');
|
|
this.gltfLoader.setDRACOLoader(dracoLoader)
|
|
}
|
|
|
|
|
|
_applyCustomMaterial(object) {
|
|
let texture = null;
|
|
if (object.material && object.material.map) {
|
|
texture = object.material.map;
|
|
}
|
|
|
|
const canvas = document.createElement('canvas');
|
|
const context = canvas.getContext('2d');
|
|
|
|
if (texture && texture.image) {
|
|
canvas.width = texture.image.width;
|
|
canvas.height = texture.image.height;
|
|
context.drawImage(texture.image, 0, 0);
|
|
} else {
|
|
// Fallback if no texture is found
|
|
canvas.width = 1024;
|
|
canvas.height = 1024;
|
|
context.fillStyle = '#0044ffff';
|
|
context.fillRect(0, 0, 1024, 1024);
|
|
}
|
|
|
|
const drawableTexture = new THREE.CanvasTexture(canvas);
|
|
drawableTexture.flipY = false;
|
|
drawableTexture.needsUpdate = true;
|
|
drawableTexture.encoding = THREE.sRGBEncoding;
|
|
|
|
object.material = createCustomJitterMaterial(100, drawableTexture);
|
|
}
|
|
|
|
loadStaticWorld(modelURL, worldScale) {
|
|
return new Promise((resolve, reject) => {
|
|
this.gltfLoader.load(modelURL, (gltf) => {
|
|
const staticGroup = gltf.scene.getObjectByName('Static');
|
|
const processedObjects = [];
|
|
|
|
if (staticGroup) {
|
|
// We need to handle children carefully as we might be reparenting them
|
|
const children = [...staticGroup.children];
|
|
children.forEach(object => {
|
|
if (object.isMesh) {
|
|
// 1. Apply world scale to position and object scale
|
|
object.position.multiplyScalar(worldScale);
|
|
object.scale.multiplyScalar(worldScale);
|
|
|
|
// Detach from the original parent ('Static' group)
|
|
// so it can be added directly to the scene later.
|
|
gltf.scene.attach(object);
|
|
this._applyCustomMaterial(object);
|
|
processedObjects.push(object);
|
|
}
|
|
});
|
|
resolve(processedObjects);
|
|
} else {
|
|
console.warn("Could not find 'Static' group in the loaded model.");
|
|
resolve([]); // Resolve with an empty array if group not found
|
|
}
|
|
}, undefined, (error) => {
|
|
console.error('An error happened while loading the world model:', error);
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
loadDRACOModelURL(modelURL, textureURL, scale) {
|
|
return new Promise((resolve, reject) => {
|
|
const applyMaterial = (object, texture) => {
|
|
object.traverse((child) => {
|
|
if (child.isMesh) {
|
|
texture.encoding = THREE.sRGBEncoding;
|
|
texture.needsUpdate = true;
|
|
child.material = createCustomJitterMaterial(100, texture);
|
|
}
|
|
});
|
|
};
|
|
|
|
const processObject = (object, texture) => {
|
|
object.scale.copy(scale);
|
|
const box = new THREE.Box3().setFromObject(object);
|
|
const height = box.max.y - box.min.y;
|
|
object.position.y = height / 2;
|
|
object.position.x = 0;
|
|
applyMaterial(object, texture);
|
|
resolve(object);
|
|
};
|
|
|
|
if (textureURL) {
|
|
this.textureLoader.load(textureURL, function (baseTexture) {
|
|
baseTexture.flipY = false;
|
|
const canvas = document.createElement('canvas');
|
|
const context = canvas.getContext('2d');
|
|
canvas.width = baseTexture.image.width;
|
|
canvas.height = baseTexture.image.height;
|
|
context.drawImage(baseTexture.image, 0, 0);
|
|
const drawableTexture = new THREE.CanvasTexture(canvas);
|
|
drawableTexture.flipY = false;
|
|
|
|
this.gltfLoader.load(modelURL, function (gltf) {
|
|
processObject(gltf.scene, drawableTexture);
|
|
}, undefined, function (error) {
|
|
reject(error);
|
|
});
|
|
}, undefined, function (error) {
|
|
reject(error);
|
|
});
|
|
} else {
|
|
this.gltfLoader.load(modelURL, function (gltf) {
|
|
|
|
let extractedTexture = null;
|
|
gltf.scene.traverse((child) => {
|
|
|
|
if (child.isMesh && child.material && child.material.map) {
|
|
if (!extractedTexture) {
|
|
extractedTexture = child.material.map;
|
|
}
|
|
}
|
|
});
|
|
|
|
let finalTexture;
|
|
|
|
if (extractedTexture && extractedTexture.image) {
|
|
// The texture from the GLTF is valid, make it a drawable CanvasTexture
|
|
const canvas = document.createElement('canvas');
|
|
const context = canvas.getContext('2d');
|
|
canvas.width = extractedTexture.image.width;
|
|
canvas.height = extractedTexture.image.height;
|
|
context.drawImage(extractedTexture.image, 0, 0);
|
|
finalTexture = new THREE.CanvasTexture(canvas);
|
|
} else {
|
|
// fallback: create a white texture
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = 1024;
|
|
canvas.height = 1024;
|
|
const ctx = canvas.getContext('2d');
|
|
ctx.fillStyle = '#0044ffff';
|
|
ctx.fillRect(0, 0, 1024, 1024);
|
|
finalTexture = new THREE.CanvasTexture(canvas);
|
|
}
|
|
|
|
finalTexture.flipY = false;
|
|
|
|
processObject(gltf.scene, finalTexture);
|
|
}, undefined, function (error) {
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|