From cb07fddae11f3929ca3c92cc2c4cb2861305d52e Mon Sep 17 00:00:00 2001
From: Michael Herzog
Date: Mon, 18 May 2026 13:46:18 +0200
Subject: [PATCH 1/2] Manual: Improve Installation guide. (#33599)
---
manual/en/installation.html | 15 ++-------------
manual/fr/installation.html | 15 ++-------------
manual/zh/installation.html | 15 ++-------------
3 files changed, 6 insertions(+), 39 deletions(-)
diff --git a/manual/en/installation.html b/manual/en/installation.html
index 95696390532d55..558bb8b9466959 100644
--- a/manual/en/installation.html
+++ b/manual/en/installation.html
@@ -109,21 +109,10 @@ Development
- Improve your editor auto-completion with jsconfig or tsconfig
+ Using three.js with TypeScript
- Place a jsconfig.json (or tsconfig.json for TypeScript projects) in your project's root. Adding the configuration below helps your editor locate three.js files for enhanced auto-completion.
+ Community-maintained TypeScript type definitions for three.js are available at [link:https://github.com/three-types/three-ts-types three-types/three-ts-types].
-
-{
- "compilerOptions": {
- // other options...
- "paths": {
- "three/webgpu": ["node_modules/three/build/three.webgpu.js"],
- "three/tsl": ["node_modules/three/build/three.tsl.js"],
- },
- }
-}
-
diff --git a/manual/fr/installation.html b/manual/fr/installation.html
index 08e3c366f1a54b..2038c88ba8df8a 100644
--- a/manual/fr/installation.html
+++ b/manual/fr/installation.html
@@ -109,21 +109,10 @@ Développement
- Améliorez l'auto-complétion de votre éditeur avec jsconfig ou tsconfig
+ Using three.js with TypeScript
- Placez un fichier jsconfig.json (ou tsconfig.json pour les projets TypeScript) à la racine de votre projet. L'ajout de la configuration ci-dessous aide votre éditeur à localiser les fichiers three.js pour une auto-complétion améliorée.
+ Community-maintained TypeScript type definitions for three.js are available at [link:https://github.com/three-types/three-ts-types three-types/three-ts-types].
-
-{
- "compilerOptions": {
- // other options...
- "paths": {
- "three/webgpu": ["node_modules/three/build/three.webgpu.js"],
- "three/tsl": ["node_modules/three/build/three.tsl.js"],
- },
- }
-}
-
diff --git a/manual/zh/installation.html b/manual/zh/installation.html
index 8dd29d8612ce15..765b81b6b0f3e5 100644
--- a/manual/zh/installation.html
+++ b/manual/zh/installation.html
@@ -109,21 +109,10 @@ 开发
- 使用 jsconfig 或 tsconfig 改善编辑器自动补全
+ Using three.js with TypeScript
- 在项目根目录放置一个 jsconfig.json(TypeScript 项目则使用 tsconfig.json)。添加以下配置可以帮助编辑器定位 three.js 文件,从而增强自动补全功能。
+ Community-maintained TypeScript type definitions for three.js are available at [link:https://github.com/three-types/three-ts-types three-types/three-ts-types].
-
-{
- "compilerOptions": {
- // other options...
- "paths": {
- "three/webgpu": ["node_modules/three/build/three.webgpu.js"],
- "three/tsl": ["node_modules/three/build/three.tsl.js"],
- },
- }
-}
-
From 0edc965186ba1af11fd2d7cd45ecad3dbe38957f Mon Sep 17 00:00:00 2001
From: Michael Herzog
Date: Mon, 18 May 2026 14:05:29 +0200
Subject: [PATCH 2/2] USDZExporter: Add multi-material support. (#33598)
---
examples/jsm/exporters/USDZExporter.js | 102 +++++++++++++++++++------
1 file changed, 79 insertions(+), 23 deletions(-)
diff --git a/examples/jsm/exporters/USDZExporter.js b/examples/jsm/exporters/USDZExporter.js
index 6f3744429819d9..52a9ead3d961b3 100644
--- a/examples/jsm/exporters/USDZExporter.js
+++ b/examples/jsm/exporters/USDZExporter.js
@@ -567,35 +567,49 @@ function buildNode( object, parentNode, materials, usedNames, files, options ) {
if ( object.isMesh ) {
const geometry = object.geometry;
- const material = object.material;
+ const isMultiMaterial = Array.isArray( object.material );
- if ( ! material.isMeshStandardMaterial ) {
+ const meshMaterials = isMultiMaterial ? object.material : [ object.material ];
- console.warn( 'THREE.USDZExporter: Use MeshStandardMaterial for best results.' );
+ for ( let i = 0; i < meshMaterials.length; i ++ ) {
- }
+ const material = meshMaterials[ i ];
- const geometryFileName = 'geometries/Geometry_' + geometry.id + '.usda';
+ if ( ! material.isMeshStandardMaterial ) {
- if ( ! ( geometryFileName in files ) ) {
+ console.warn( 'THREE.USDZExporter: Use MeshStandardMaterial for best results.' );
- const meshObject = buildMeshObject( geometry );
- files[ geometryFileName ] = strToU8(
- buildHeader() + '\n' + meshObject.toString()
- );
+ }
+
+ if ( ! ( material.uuid in materials ) ) {
+
+ materials[ material.uuid ] = material;
+
+ }
}
- if ( ! ( material.uuid in materials ) ) {
+ const resolvedMaterials = meshMaterials.map( ( m ) => materials[ m.uuid ] );
+
+ if ( isMultiMaterial === false ) {
+
+ const geometryFileName = `geometries/Geometry_${geometry.id}.usda`;
+
+ if ( ! ( geometryFileName in files ) ) {
- materials[ material.uuid ] = material;
+ const meshObject = buildMeshObject( geometry );
+ files[ geometryFileName ] = strToU8(
+ buildHeader() + '\n' + meshObject.toString()
+ );
+
+ }
}
childNode = buildMesh(
object,
geometry,
- materials[ material.uuid ],
+ resolvedMaterials,
usedNames,
options
);
@@ -706,19 +720,26 @@ function buildXform( object, usedNames, options ) {
}
-function buildMesh( object, geometry, material, usedNames, options ) {
+function buildMesh( object, geometry, materials, usedNames, options ) {
const node = buildXform( object, usedNames, options );
- node.addMetadata(
- 'prepend references',
- `@./geometries/Geometry_${geometry.id}.usda@`
- );
- node.addMetadata( 'prepend apiSchemas', '["MaterialBindingAPI"]' );
+ if ( materials.length === 1 ) {
- node.addProperty(
- `rel material:binding = `
- );
+ node.addMetadata(
+ 'prepend references',
+ `@./geometries/Geometry_${geometry.id}.usda@`
+ );
+ node.addMetadata( 'prepend apiSchemas', '["MaterialBindingAPI"]' );
+ node.addProperty(
+ `rel material:binding = `
+ );
+
+ } else {
+
+ node.addChild( buildMeshNode( geometry, materials ) );
+
+ }
return node;
@@ -756,7 +777,7 @@ function buildMeshObject( geometry ) {
}
-function buildMeshNode( geometry ) {
+function buildMeshNode( geometry, materials = null ) {
const name = 'Geometry';
const attributes = geometry.attributes;
@@ -808,6 +829,41 @@ function buildMeshNode( geometry ) {
node.addProperty( 'uniform token subdivisionScheme = "none"' );
+ if ( materials !== null ) {
+
+ const groups = geometry.groups;
+
+ const totalFaces = ( geometry.index !== null
+ ? geometry.index.count
+ : attributes.position.count ) / 3;
+
+ for ( let i = 0; i < groups.length; i ++ ) {
+
+ const group = groups[ i ];
+ const material = materials[ group.materialIndex ];
+
+ if ( material === undefined ) continue;
+
+ const startFace = Math.floor( group.start / 3 );
+ const endFace = Math.min( startFace + Math.floor( group.count / 3 ), totalFaces );
+
+ const indices = [];
+ for ( let j = startFace; j < endFace; j ++ ) indices.push( j );
+
+ const subsetNode = new USDNode( `subset_${i}`, 'GeomSubset' );
+ subsetNode.addMetadata( 'prepend apiSchemas', '["MaterialBindingAPI"]' );
+ subsetNode.addProperty( 'uniform token elementType = "face"' );
+ subsetNode.addProperty( 'uniform token familyName = "materialBind"' );
+ subsetNode.addProperty( `int[] indices = [${indices.join( ', ' )}]` );
+ subsetNode.addProperty(
+ `rel material:binding = `
+ );
+ node.addChild( subsetNode );
+
+ }
+
+ }
+
return node;
}