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

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);
});
}
});
}
}