Threejs Loaders

calesthio/OpenMontage/.agents/skills/threejs-loaders

作者 calesthio9327439db69021ab4b0e2776729bf3b58fdb5a87无许可证65K 个星标收录于 2026年10月9日更新于 2026年10月9日仓库5天前更新

Three.js asset loading - GLTF, textures, images, models, async patterns. Use when loading 3D models, textures, HDR environments, or managing loading progress.

AI 生成的概览

Three.js 中加载 3D 模型、纹理和 HDR 环境的参考指南,包含异步与缓存模式。

功能
该技能是 Three.js 资源加载的代码参考。它演示如何加载 GLTF/GLB、OBJ/MTL、FBX、STL 和 PLY 模型、纹理、立方体贴图以及 HDR/EXR 环境,并用 LoadingManager 统一协调。内容还涵盖 Draco 与 KTX2 压缩、Promise 化与并行加载、缓存、错误处理和性能建议。
适用场景
在编写需要把外部 3D 模型、纹理或环境贴图载入场景的 Three.js 代码时使用。适合涉及加载进度、压缩资源,或资源缓存与错误处理的任务。
运行要求
需要一个 Three.js 项目,并可使用附加加载器(GLTFLoader、RGBELoader、DRACOLoader、KTX2Loader 等)。部分示例引用托管在 CDN 上的外部解码器和转码器文件,因此可能需要网络访问。该技能不附带脚本,仅为说明文档。

Three.js Loaders

Quick Start

javascript
import * as THREE from "three";import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
// Load GLTF modelconst loader = new GLTFLoader();loader.load("model.glb", (gltf) => {  scene.add(gltf.scene);});
// Load textureconst textureLoader = new THREE.TextureLoader();const texture = textureLoader.load("texture.jpg");

LoadingManager

Coordinate multiple loaders and track progress.

javascript
const manager = new THREE.LoadingManager();
// Callbacksmanager.onStart = (url, loaded, total) => {  console.log(`Started loading: ${url}`);};
manager.onLoad = () => {  console.log("All assets loaded!");  startGame();};
manager.onProgress = (url, loaded, total) => {  const progress = (loaded / total) * 100;  console.log(`Loading: ${progress.toFixed(1)}%`);  updateProgressBar(progress);};
manager.onError = (url) => {  console.error(`Error loading: ${url}`);};
// Use manager with loadersconst textureLoader = new THREE.TextureLoader(manager);const gltfLoader = new GLTFLoader(manager);
// Load assetstextureLoader.load("texture1.jpg");textureLoader.load("texture2.jpg");gltfLoader.load("model.glb");// onLoad fires when ALL are complete

Texture Loading

TextureLoader

javascript
const loader = new THREE.TextureLoader();
// Callback styleloader.load(  "texture.jpg",  (texture) => {    // onLoad    material.map = texture;    material.needsUpdate = true;  },  undefined, // onProgress - not supported for image loading  (error) => {    // onError    console.error("Error loading texture", error);  },);
// Synchronous (returns texture, loads async)const texture = loader.load("texture.jpg");material.map = texture;

Texture Configuration

javascript
const texture = loader.load("texture.jpg", (tex) => {  // Color space (important for color accuracy)  tex.colorSpace = THREE.SRGBColorSpace; // For color/albedo maps  // tex.colorSpace = THREE.LinearSRGBColorSpace;  // For data maps (normal, roughness)
  // Wrapping  tex.wrapS = THREE.RepeatWrapping;  tex.wrapT = THREE.RepeatWrapping;  // ClampToEdgeWrapping, RepeatWrapping, MirroredRepeatWrapping
  // Repeat/offset  tex.repeat.set(2, 2);  tex.offset.set(0.5, 0.5);  tex.rotation = Math.PI / 4;  tex.center.set(0.5, 0.5);
  // Filtering  tex.minFilter = THREE.LinearMipmapLinearFilter; // Default  tex.magFilter = THREE.LinearFilter; // Default  // NearestFilter - pixelated  // LinearFilter - smooth  // LinearMipmapLinearFilter - smooth with mipmaps
  // Anisotropic filtering (sharper at angles)  tex.anisotropy = renderer.capabilities.getMaxAnisotropy();
  // Flip Y (usually true for standard textures)  tex.flipY = true;
  tex.needsUpdate = true;});

CubeTextureLoader

For environment maps and skyboxes.

javascript
const loader = new THREE.CubeTextureLoader();
// Load 6 facesconst cubeTexture = loader.load([  "px.jpg",  "nx.jpg", // positive/negative X  "py.jpg",  "ny.jpg", // positive/negative Y  "pz.jpg",  "nz.jpg", // positive/negative Z]);
// Use as backgroundscene.background = cubeTexture;
// Use as environment mapscene.environment = cubeTexture;material.envMap = cubeTexture;

HDR/EXR Loading

javascript
import { RGBELoader } from "three/addons/loaders/RGBELoader.js";import { EXRLoader } from "three/addons/loaders/EXRLoader.js";
// HDRconst rgbeLoader = new RGBELoader();rgbeLoader.load("environment.hdr", (texture) => {  texture.mapping = THREE.EquirectangularReflectionMapping;  scene.environment = texture;  scene.background = texture;});
// EXRconst exrLoader = new EXRLoader();exrLoader.load("environment.exr", (texture) => {  texture.mapping = THREE.EquirectangularReflectionMapping;  scene.environment = texture;});

PMREMGenerator

Generate prefiltered environment maps for PBR.

javascript
import { RGBELoader } from "three/addons/loaders/RGBELoader.js";
const pmremGenerator = new THREE.PMREMGenerator(renderer);pmremGenerator.compileEquirectangularShader();
new RGBELoader().load("environment.hdr", (texture) => {  const envMap = pmremGenerator.fromEquirectangular(texture).texture;
  scene.environment = envMap;  scene.background = envMap;
  texture.dispose();  pmremGenerator.dispose();});

GLTF/GLB Loading

The most common 3D format for web.

javascript
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
const loader = new GLTFLoader();
loader.load("model.glb", (gltf) => {  // The loaded scene  const model = gltf.scene;  scene.add(model);
  // Animations  const animations = gltf.animations;  if (animations.length > 0) {    const mixer = new THREE.AnimationMixer(model);    animations.forEach((clip) => {      mixer.clipAction(clip).play();    });  }
  // Cameras (if any)  const cameras = gltf.cameras;
  // Asset info  console.log(gltf.asset); // Version, generator, etc.
  // User data from Blender/etc  console.log(gltf.userData);});

GLTF with Draco Compression

javascript
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
const dracoLoader = new DRACOLoader();dracoLoader.setDecoderPath(  "https://www.gstatic.com/draco/versioned/decoders/1.5.6/",);dracoLoader.preload();
const gltfLoader = new GLTFLoader();gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.load("compressed-model.glb", (gltf) => {  scene.add(gltf.scene);});

GLTF with KTX2 Textures

javascript
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";import { KTX2Loader } from "three/addons/loaders/KTX2Loader.js";
const ktx2Loader = new KTX2Loader();ktx2Loader.setTranscoderPath(  "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/libs/basis/",);ktx2Loader.detectSupport(renderer);
const gltfLoader = new GLTFLoader();gltfLoader.setKTX2Loader(ktx2Loader);
gltfLoader.load("model-with-ktx2.glb", (gltf) => {  scene.add(gltf.scene);});

Process GLTF Content

javascript
loader.load("model.glb", (gltf) => {  const model = gltf.scene;
  // Enable shadows  model.traverse((child) => {    if (child.isMesh) {      child.castShadow = true;      child.receiveShadow = true;    }  });
  // Find specific mesh  const head = model.getObjectByName("Head");
  // Adjust materials  model.traverse((child) => {    if (child.isMesh && child.material) {      child.material.envMapIntensity = 0.5;    }  });
  // Center and scale  const box = new THREE.Box3().setFromObject(model);  const center = box.getCenter(new THREE.Vector3());  const size = box.getSize(new THREE.Vector3());
  model.position.sub(center);  const maxDim = Math.max(size.x, size.y, size.z);  model.scale.setScalar(1 / maxDim);
  scene.add(model);});

Other Model Formats

OBJ + MTL

javascript
import { OBJLoader } from "three/addons/loaders/OBJLoader.js";import { MTLLoader } from "three/addons/loaders/MTLLoader.js";
const mtlLoader = new MTLLoader();mtlLoader.load("model.mtl", (materials) => {  materials.preload();
  const objLoader = new OBJLoader();  objLoader.setMaterials(materials);  objLoader.load("model.obj", (object) => {    scene.add(object);  });});

FBX

javascript
import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
const loader = new FBXLoader();loader.load("model.fbx", (object) => {  // FBX often has large scale  object.scale.setScalar(0.01);
  // Animations  const mixer = new THREE.AnimationMixer(object);  object.animations.forEach((clip) => {    mixer.clipAction(clip).play();  });
  scene.add(object);});

STL

javascript
import { STLLoader } from "three/addons/loaders/STLLoader.js";
const loader = new STLLoader();loader.load("model.stl", (geometry) => {  const material = new THREE.MeshStandardMaterial({ color: 0x888888 });  const mesh = new THREE.Mesh(geometry, material);  scene.add(mesh);});

PLY

javascript
import { PLYLoader } from "three/addons/loaders/PLYLoader.js";
const loader = new PLYLoader();loader.load("model.ply", (geometry) => {  geometry.computeVertexNormals();  const material = new THREE.MeshStandardMaterial({ vertexColors: true });  const mesh = new THREE.Mesh(geometry, material);  scene.add(mesh);});

Async/Promise Loading

Promisified Loader

javascript
function loadModel(url) {  return new Promise((resolve, reject) => {    loader.load(url, resolve, undefined, reject);  });}
// Usageasync function init() {  try {    const gltf = await loadModel("model.glb");    scene.add(gltf.scene);  } catch (error) {    console.error("Failed to load model:", error);  }}

Load Multiple Assets

javascript
async function loadAssets() {  const [modelGltf, envTexture, colorTexture] = await Promise.all([    loadGLTF("model.glb"),    loadRGBE("environment.hdr"),    loadTexture("color.jpg"),  ]);
  scene.add(modelGltf.scene);  scene.environment = envTexture;  material.map = colorTexture;}
// Helper functionsfunction loadGLTF(url) {  return new Promise((resolve, reject) => {    new GLTFLoader().load(url, resolve, undefined, reject);  });}
function loadRGBE(url) {  return new Promise((resolve, reject) => {    new RGBELoader().load(      url,      (texture) => {        texture.mapping = THREE.EquirectangularReflectionMapping;        resolve(texture);      },      undefined,      reject,    );  });}
function loadTexture(url) {  return new Promise((resolve, reject) => {    new THREE.TextureLoader().load(url, resolve, undefined, reject);  });}

Caching

Built-in Cache

javascript
// Enable cacheTHREE.Cache.enabled = true;
// Clear cacheTHREE.Cache.clear();
// Manual cache managementTHREE.Cache.add("key", data);THREE.Cache.get("key");THREE.Cache.remove("key");

Custom Asset Manager

javascript
class AssetManager {  constructor() {    this.textures = new Map();    this.models = new Map();    this.gltfLoader = new GLTFLoader();    this.textureLoader = new THREE.TextureLoader();  }
  async loadTexture(key, url) {    if (this.textures.has(key)) {      return this.textures.get(key);    }
    const texture = await new Promise((resolve, reject) => {      this.textureLoader.load(url, resolve, undefined, reject);    });
    this.textures.set(key, texture);    return texture;  }
  async loadModel(key, url) {    if (this.models.has(key)) {      return this.models.get(key).clone();    }
    const gltf = await new Promise((resolve, reject) => {      this.gltfLoader.load(url, resolve, undefined, reject);    });
    this.models.set(key, gltf.scene);    return gltf.scene.clone();  }
  dispose() {    this.textures.forEach((t) => t.dispose());    this.textures.clear();    this.models.clear();  }}
// Usageconst assets = new AssetManager();const texture = await assets.loadTexture("brick", "brick.jpg");const model = await assets.loadModel("tree", "tree.glb");

Loading from Different Sources

Data URL / Base64

javascript
const loader = new THREE.TextureLoader();const texture = loader.load("data:image/png;base64,iVBORw0KGgo...");

Blob URL

javascript
async function loadFromBlob(blob) {  const url = URL.createObjectURL(blob);  const texture = await loadTexture(url);  URL.revokeObjectURL(url);  return texture;}

ArrayBuffer

javascript
// From fetchconst response = await fetch("model.glb");const buffer = await response.arrayBuffer();
// Parse with loaderconst loader = new GLTFLoader();loader.parse(buffer, "", (gltf) => {  scene.add(gltf.scene);});

Custom Path/URL

javascript
// Set base pathloader.setPath("assets/models/");loader.load("model.glb"); // Loads from assets/models/model.glb
// Set resource path (for textures referenced in model)loader.setResourcePath("assets/textures/");
// Custom URL modifiermanager.setURLModifier((url) => {  return `https://cdn.example.com/${url}`;});

Error Handling

javascript
// Graceful fallbackasync function loadWithFallback(primaryUrl, fallbackUrl) {  try {    return await loadModel(primaryUrl);  } catch (error) {    console.warn(`Primary failed, trying fallback: ${error}`);    return await loadModel(fallbackUrl);  }}
// Retry logicasync function loadWithRetry(url, maxRetries = 3) {  for (let i = 0; i < maxRetries; i++) {    try {      return await loadModel(url);    } catch (error) {      if (i === maxRetries - 1) throw error;      await new Promise((r) => setTimeout(r, 1000 * (i + 1)));    }  }}
// Timeoutasync function loadWithTimeout(url, timeout = 30000) {  const controller = new AbortController();  const timeoutId = setTimeout(() => controller.abort(), timeout);
  try {    const response = await fetch(url, { signal: controller.signal });    clearTimeout(timeoutId);    return response;  } catch (error) {    if (error.name === "AbortError") {      throw new Error("Loading timed out");    }    throw error;  }}

Performance Tips

  1. Use compressed formats: DRACO for geometry, KTX2/Basis for textures
  2. Load progressively: Show placeholders while loading
  3. Lazy load: Only load what's needed
  4. Use CDN: Faster asset delivery
  5. Enable cache: THREE.Cache.enabled = true
javascript
// Progressive loading with placeholderconst placeholder = new THREE.Mesh(  new THREE.BoxGeometry(1, 1, 1),  new THREE.MeshBasicMaterial({ wireframe: true }),);scene.add(placeholder);
loadModel("model.glb").then((gltf) => {  scene.remove(placeholder);  scene.add(gltf.scene);});

See Also

  • threejs-textures - Texture configuration
  • threejs-animation - Playing loaded animations
  • threejs-materials - Material from loaded models

来源与署名

来源:calesthio/OpenMontage位于.agents/skills/threejs-loaders提交9327439

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架