Skip to content

Commit 32c4f23

Browse files
committed
Renamed USDZLoader to USDLoader and created USDAParser and USDCParser files.
1 parent c63f839 commit 32c4f23

File tree

7 files changed

+244
-234
lines changed

7 files changed

+244
-234
lines changed

editor/js/Loader.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -630,9 +630,9 @@ function Loader( editor ) {
630630

631631
const contents = event.target.result;
632632

633-
const { USDZLoader } = await import( 'three/addons/loaders/USDZLoader.js' );
633+
const { USDLoader } = await import( 'three/addons/loaders/USDLoader.js' );
634634

635-
const group = new USDZLoader().parse( contents );
635+
const group = new USDLoader().parse( contents );
636636
group.name = filename;
637637

638638
editor.execute( new AddObjectCommand( editor, group ) );
@@ -644,6 +644,7 @@ function Loader( editor ) {
644644

645645
}
646646

647+
case 'usdc':
647648
case 'usdz':
648649

649650
{
@@ -652,9 +653,9 @@ function Loader( editor ) {
652653

653654
const contents = event.target.result;
654655

655-
const { USDZLoader } = await import( 'three/addons/loaders/USDZLoader.js' );
656+
const { USDLoader } = await import( 'three/addons/loaders/USDLoader.js' );
656657

657-
const group = new USDZLoader().parse( contents );
658+
const group = new USDLoader().parse( contents );
658659
group.name = filename;
659660

660661
editor.execute( new AddObjectCommand( editor, group ) );

editor/sw.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ const assets = [
5252
'../examples/jsm/loaders/SVGLoader.js',
5353
'../examples/jsm/loaders/TGALoader.js',
5454
'../examples/jsm/loaders/TDSLoader.js',
55-
'../examples/jsm/loaders/USDZLoader.js',
55+
'../examples/jsm/loaders/USDLoader.js',
56+
'../examples/jsm/loaders/usd/USDAParser.js',
57+
'../examples/jsm/loaders/usd/USDCParser.js',
5658
'../examples/jsm/loaders/VOXLoader.js',
5759
'../examples/jsm/loaders/VRMLLoader.js',
5860
'../examples/jsm/loaders/VTKLoader.js',

examples/jsm/Addons.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export * from './loaders/TDSLoader.js';
117117
export * from './loaders/TGALoader.js';
118118
export * from './loaders/TIFFLoader.js';
119119
export * from './loaders/TTFLoader.js';
120-
export * from './loaders/USDZLoader.js';
120+
export * from './loaders/USDLoader.js';
121121
export * from './loaders/VOXLoader.js';
122122
export * from './loaders/VRMLLoader.js';
123123
export * from './loaders/VTKLoader.js';

examples/jsm/loaders/USDLoader.js

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import {
2+
FileLoader,
3+
Loader
4+
} from 'three';
5+
6+
import * as fflate from '../libs/fflate.module.js';
7+
import { USDAParser } from './usd/USDAParser.js';
8+
import { USDCParser } from './usd/USDCParser.js';
9+
10+
/**
11+
* A loader for the USDZ format.
12+
*
13+
* USDZ files that use USDC internally are not yet supported, only USDA.
14+
*
15+
* ```js
16+
* const loader = new USDZLoader();
17+
* const model = await loader.loadAsync( 'saeukkang.usdz' );
18+
* scene.add( model );
19+
* ```
20+
*
21+
* @augments Loader
22+
* @three_import import { USDLoader } from 'three/addons/loaders/USDLoader.js';
23+
*/
24+
class USDLoader extends Loader {
25+
26+
/**
27+
* Constructs a new USDZ loader.
28+
*
29+
* @param {LoadingManager} [manager] - The loading manager.
30+
*/
31+
constructor( manager ) {
32+
33+
super( manager );
34+
35+
}
36+
37+
/**
38+
* Starts loading from the given URL and passes the loaded USDZ asset
39+
* to the `onLoad()` callback.
40+
*
41+
* @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
42+
* @param {function(Group)} onLoad - Executed when the loading process has been finished.
43+
* @param {onProgressCallback} onProgress - Executed while the loading is in progress.
44+
* @param {onErrorCallback} onError - Executed when errors occur.
45+
*/
46+
load( url, onLoad, onProgress, onError ) {
47+
48+
const scope = this;
49+
50+
const loader = new FileLoader( scope.manager );
51+
loader.setPath( scope.path );
52+
loader.setResponseType( 'arraybuffer' );
53+
loader.setRequestHeader( scope.requestHeader );
54+
loader.setWithCredentials( scope.withCredentials );
55+
loader.load( url, function ( text ) {
56+
57+
try {
58+
59+
onLoad( scope.parse( text ) );
60+
61+
} catch ( e ) {
62+
63+
if ( onError ) {
64+
65+
onError( e );
66+
67+
} else {
68+
69+
console.error( e );
70+
71+
}
72+
73+
scope.manager.itemError( url );
74+
75+
}
76+
77+
}, onProgress, onError );
78+
79+
}
80+
81+
/**
82+
* Parses the given USDZ data and returns the resulting group.
83+
*
84+
* @param {ArrayBuffer|string} buffer - The raw USDZ data as an array buffer.
85+
* @return {Group} The parsed asset as a group.
86+
*/
87+
parse( buffer ) {
88+
89+
const usda = new USDAParser();
90+
const usdc = new USDCParser();
91+
92+
function parseAssets( zip ) {
93+
94+
const data = {};
95+
const loader = new FileLoader();
96+
loader.setResponseType( 'arraybuffer' );
97+
98+
for ( const filename in zip ) {
99+
100+
if ( filename.endsWith( 'png' ) ) {
101+
102+
const blob = new Blob( [ zip[ filename ] ], { type: 'image/png' } );
103+
data[ filename ] = URL.createObjectURL( blob );
104+
105+
}
106+
107+
if ( filename.endsWith( 'usd' ) || filename.endsWith( 'usda' ) || filename.endsWith( 'usdc' ) ) {
108+
109+
if ( isCrateFile( zip[ filename ] ) ) {
110+
111+
data[ filename ] = usdc.parse( zip[ filename ].buffer, data );
112+
113+
} else {
114+
115+
const text = fflate.strFromU8( zip[ filename ] );
116+
data[ filename ] = usda.parse( text, data );
117+
118+
}
119+
120+
}
121+
122+
}
123+
124+
return data;
125+
126+
}
127+
128+
function isCrateFile( buffer ) {
129+
130+
const crateHeader = new Uint8Array( [ 0x50, 0x58, 0x52, 0x2D, 0x55, 0x53, 0x44, 0x43 ] ); // PXR-USDC
131+
132+
if ( buffer.byteLength < crateHeader.length ) return false;
133+
134+
const view = new Uint8Array( buffer, 0, crateHeader.length );
135+
136+
for ( let i = 0; i < crateHeader.length; i ++ ) {
137+
138+
if ( view[ i ] !== crateHeader[ i ] ) return false;
139+
140+
}
141+
142+
return true;
143+
144+
}
145+
146+
function findUSD( zip ) {
147+
148+
if ( zip.length < 1 ) return undefined;
149+
150+
const firstFileName = Object.keys( zip )[ 0 ];
151+
let isCrate = false;
152+
153+
// As per the USD specification, the first entry in the zip archive is used as the main file ("UsdStage").
154+
// ASCII files can end in either .usda or .usd.
155+
// See https://openusd.org/release/spec_usdz.html#layout
156+
if ( firstFileName.endsWith( 'usda' ) ) return zip[ firstFileName ];
157+
158+
if ( firstFileName.endsWith( 'usdc' ) ) {
159+
160+
isCrate = true;
161+
162+
} else if ( firstFileName.endsWith( 'usd' ) ) {
163+
164+
// If this is not a crate file, we assume it is a plain USDA file.
165+
if ( ! isCrateFile( zip[ firstFileName ] ) ) {
166+
167+
return zip[ firstFileName ];
168+
169+
} else {
170+
171+
isCrate = true;
172+
173+
}
174+
175+
}
176+
177+
if ( isCrate ) {
178+
179+
return zip[ firstFileName ];
180+
181+
}
182+
183+
}
184+
185+
// USDA
186+
187+
if ( typeof buffer === 'string' ) {
188+
189+
return usda.parse( buffer, {} );
190+
191+
}
192+
193+
// USDC
194+
195+
if ( isCrateFile( buffer ) ) {
196+
197+
return usdc.parse( buffer );
198+
199+
}
200+
201+
// USDZ
202+
203+
const zip = fflate.unzipSync( new Uint8Array( buffer ) );
204+
205+
const assets = parseAssets( zip );
206+
207+
// console.log( assets );
208+
209+
const file = findUSD( zip );
210+
211+
const text = fflate.strFromU8( file );
212+
213+
return usda.parse( text, assets );
214+
215+
}
216+
217+
}
218+
219+
export { USDLoader };

0 commit comments

Comments
 (0)