Files

194 lines
7.3 KiB
JavaScript

// GLB/GLTF 模型加载器
export class ModelLoader {
constructor(THREE) {
this.THREE = THREE;
this.loader = null;
}
async loadGLTFLoader() {
// 动态加载 GLTFLoader
if (this.loader) return this.loader;
return new Promise((resolve, reject) => {
// 检查是否已经加载
if (window.THREE && window.THREE.GLTFLoader) {
this.loader = new window.THREE.GLTFLoader();
resolve(this.loader);
return;
}
const script = document.createElement('script');
script.src = new URL('./lib/GLTFLoader.js', import.meta.url).href;
script.onload = () => {
if (window.THREE && window.THREE.GLTFLoader) {
this.loader = new window.THREE.GLTFLoader();
resolve(this.loader);
} else {
reject(new Error('GLTFLoader not found after loading script'));
}
};
script.onerror = () => reject(new Error('Failed to load GLTFLoader script'));
document.head.appendChild(script);
});
}
async loadModel(url) {
const loader = await this.loadGLTFLoader();
return new Promise((resolve, reject) => {
loader.load(
url,
(gltf) => resolve(gltf.scene),
undefined,
reject
);
});
}
// 创建程序化的简单人物模型(备用方案)
createSimpleHumanoid(THREE) {
const group = new THREE.Group();
// 材质
const frontMat = new THREE.MeshPhongMaterial({ color: 0x4A90D9 });
const backMat = new THREE.MeshPhongMaterial({ color: 0x2D5A8A });
// 头部
const head = new THREE.Mesh(new THREE.SphereGeometry(8, 16, 16), frontMat);
head.position.y = 28;
group.add(head);
// 颈部
const neck = new THREE.Mesh(new THREE.CylinderGeometry(3, 3, 4, 8), frontMat);
neck.position.y = 22;
group.add(neck);
// 躯干
const torso = new THREE.Mesh(new THREE.BoxGeometry(14, 20, 8), frontMat);
torso.position.y = 10;
group.add(torso);
// 臀部
const hips = new THREE.Mesh(new THREE.BoxGeometry(12, 6, 7), frontMat);
hips.position.y = -2;
group.add(hips);
// 左臂
const leftShoulder = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 8), frontMat);
leftShoulder.position.set(-8.5, 17, 0);
group.add(leftShoulder);
const leftUpperArm = new THREE.Mesh(new THREE.CylinderGeometry(2.5, 2, 10, 8), frontMat);
leftUpperArm.position.set(-8.5, 10, 0);
group.add(leftUpperArm);
const leftElbow = new THREE.Mesh(new THREE.SphereGeometry(2.5, 8, 8), frontMat);
leftElbow.position.set(-8.5, 5, 0);
group.add(leftElbow);
const leftForearm = new THREE.Mesh(new THREE.CylinderGeometry(2, 1.5, 9, 8), frontMat);
leftForearm.position.set(-8.5, 0, 0);
group.add(leftForearm);
const leftHand = new THREE.Mesh(new THREE.SphereGeometry(2, 8, 8), frontMat);
leftHand.position.set(-8.5, -4.5, 0);
group.add(leftHand);
// 右臂(镜像)
const rightShoulder = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 8), frontMat);
rightShoulder.position.set(8.5, 17, 0);
group.add(rightShoulder);
const rightUpperArm = new THREE.Mesh(new THREE.CylinderGeometry(2.5, 2, 10, 8), frontMat);
rightUpperArm.position.set(8.5, 10, 0);
group.add(rightUpperArm);
const rightElbow = new THREE.Mesh(new THREE.SphereGeometry(2.5, 8, 8), frontMat);
rightElbow.position.set(8.5, 5, 0);
group.add(rightElbow);
const rightForearm = new THREE.Mesh(new THREE.CylinderGeometry(2, 1.5, 9, 8), frontMat);
rightForearm.position.set(8.5, 0, 0);
group.add(rightForearm);
const rightHand = new THREE.Mesh(new THREE.SphereGeometry(2, 8, 8), frontMat);
rightHand.position.set(8.5, -4.5, 0);
group.add(rightHand);
// 左腿
const leftHip = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 8), frontMat);
leftHip.position.set(-4, -5, 0);
group.add(leftHip);
const leftThigh = new THREE.Mesh(new THREE.CylinderGeometry(3, 2.5, 12, 8), frontMat);
leftThigh.position.set(-4, -12, 0);
group.add(leftThigh);
const leftKnee = new THREE.Mesh(new THREE.SphereGeometry(2.5, 8, 8), frontMat);
leftKnee.position.set(-4, -18, 0);
group.add(leftKnee);
const leftShin = new THREE.Mesh(new THREE.CylinderGeometry(2.5, 2, 12, 8), frontMat);
leftShin.position.set(-4, -25, 0);
group.add(leftShin);
const leftFoot = new THREE.Mesh(new THREE.BoxGeometry(3, 2, 5), frontMat);
leftFoot.position.set(-4, -32, 1);
group.add(leftFoot);
// 右腿(镜像)
const rightHip = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 8), frontMat);
rightHip.position.set(4, -5, 0);
group.add(rightHip);
const rightThigh = new THREE.Mesh(new THREE.CylinderGeometry(3, 2.5, 12, 8), frontMat);
rightThigh.position.set(4, -12, 0);
group.add(rightThigh);
const rightKnee = new THREE.Mesh(new THREE.SphereGeometry(2.5, 8, 8), frontMat);
rightKnee.position.set(4, -18, 0);
group.add(rightKnee);
const rightShin = new THREE.Mesh(new THREE.CylinderGeometry(2.5, 2, 12, 8), frontMat);
rightShin.position.set(4, -25, 0);
group.add(rightShin);
const rightFoot = new THREE.Mesh(new THREE.BoxGeometry(3, 2, 5), frontMat);
rightFoot.position.set(4, -32, 1);
group.add(rightFoot);
// 添加正面标记
const canvas = document.createElement('canvas');
canvas.width = canvas.height = 128;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFD700';
ctx.font = 'bold 80px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('F', 64, 64);
const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: new THREE.CanvasTexture(canvas) }));
sprite.position.set(0, 10, 10);
sprite.scale.set(15, 15, 1);
group.add(sprite);
// 添加背面标记
const canvasBack = document.createElement('canvas');
canvasBack.width = canvasBack.height = 128;
const ctxBack = canvasBack.getContext('2d');
ctxBack.fillStyle = '#888';
ctxBack.font = 'bold 80px Arial';
ctxBack.textAlign = 'center';
ctxBack.textBaseline = 'middle';
ctxBack.fillText('B', 64, 64);
const spriteBack = new THREE.Sprite(new THREE.SpriteMaterial({ map: new THREE.CanvasTexture(canvasBack) }));
spriteBack.position.set(0, 10, -10);
spriteBack.scale.set(15, 15, 1);
group.add(spriteBack);
// 调整整体位置,使脚部在原点
group.position.y = 33;
return group;
}
}