@plastic-software/three 0.178.0 → 0.179.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/three.cjs +856 -196
- package/build/three.core.js +647 -123
- package/build/three.core.min.js +1 -1
- package/build/three.module.js +211 -76
- package/build/three.module.min.js +1 -1
- package/build/three.tsl.js +70 -21
- package/build/three.tsl.min.js +1 -1
- package/build/three.webgpu.js +1796 -557
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +1754 -557
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/jsm/Addons.js +1 -2
- package/examples/jsm/capabilities/WebGPU.js +1 -1
- package/examples/jsm/csm/CSMShadowNode.js +4 -4
- package/examples/jsm/environments/RoomEnvironment.js +8 -3
- package/examples/jsm/exporters/USDZExporter.js +676 -299
- package/examples/jsm/geometries/RoundedBoxGeometry.js +47 -8
- package/examples/jsm/interactive/HTMLMesh.js +5 -3
- package/examples/jsm/libs/meshopt_decoder.module.js +75 -58
- package/examples/jsm/lights/LightProbeGenerator.js +14 -3
- package/examples/jsm/loaders/EXRLoader.js +210 -22
- package/examples/jsm/loaders/FBXLoader.js +1 -1
- package/examples/jsm/loaders/MaterialXLoader.js +212 -30
- package/examples/jsm/loaders/TTFLoader.js +13 -1
- package/examples/jsm/loaders/USDLoader.js +219 -0
- package/examples/jsm/loaders/USDZLoader.js +4 -892
- package/examples/jsm/loaders/usd/USDAParser.js +741 -0
- package/examples/jsm/loaders/usd/USDCParser.js +17 -0
- package/examples/jsm/objects/LensflareMesh.js +3 -3
- package/examples/jsm/objects/SkyMesh.js +2 -2
- package/examples/jsm/physics/RapierPhysics.js +14 -5
- package/examples/jsm/postprocessing/GTAOPass.js +10 -9
- package/examples/jsm/postprocessing/OutlinePass.js +17 -17
- package/examples/jsm/postprocessing/SSAOPass.js +10 -9
- package/examples/jsm/shaders/UnpackDepthRGBAShader.js +11 -2
- package/examples/jsm/transpiler/GLSLDecoder.js +2 -2
- package/examples/jsm/tsl/display/BloomNode.js +8 -7
- package/examples/jsm/tsl/display/GaussianBlurNode.js +6 -8
- package/examples/jsm/tsl/display/{TRAAPassNode.js → TRAANode.js} +181 -172
- package/examples/jsm/tsl/lighting/TiledLightsNode.js +1 -1
- package/package.json +1 -1
- package/src/Three.Core.js +1 -0
- package/src/Three.TSL.js +69 -20
- package/src/animation/KeyframeTrack.js +1 -1
- package/src/animation/tracks/BooleanKeyframeTrack.js +1 -1
- package/src/animation/tracks/StringKeyframeTrack.js +1 -1
- package/src/cameras/Camera.js +14 -0
- package/src/cameras/OrthographicCamera.js +1 -1
- package/src/cameras/PerspectiveCamera.js +1 -1
- package/src/constants.js +1 -1
- package/{examples/jsm/misc → src/core}/Timer.js +4 -42
- package/src/extras/PMREMGenerator.js +11 -0
- package/src/helpers/CameraHelper.js +41 -11
- package/src/helpers/SkeletonHelper.js +35 -6
- package/src/lights/LightShadow.js +21 -8
- package/src/lights/PointLightShadow.js +1 -1
- package/src/loaders/FileLoader.js +25 -2
- package/src/loaders/ImageBitmapLoader.js +23 -0
- package/src/loaders/Loader.js +14 -0
- package/src/loaders/LoadingManager.js +23 -0
- package/src/materials/MeshBasicMaterial.js +1 -1
- package/src/materials/nodes/Line2NodeMaterial.js +0 -8
- package/src/materials/nodes/NodeMaterial.js +1 -1
- package/src/materials/nodes/PointsNodeMaterial.js +5 -0
- package/src/materials/nodes/manager/NodeMaterialObserver.js +87 -2
- package/src/math/Frustum.js +19 -8
- package/src/math/FrustumArray.js +10 -5
- package/src/math/Line3.js +129 -2
- package/src/math/Matrix4.js +48 -27
- package/src/math/Spherical.js +2 -2
- package/src/nodes/Nodes.js +1 -0
- package/src/nodes/TSL.js +1 -0
- package/src/nodes/accessors/Camera.js +12 -12
- package/src/nodes/accessors/Normal.js +11 -11
- package/src/nodes/accessors/ReferenceNode.js +18 -3
- package/src/nodes/accessors/SceneNode.js +1 -1
- package/src/nodes/accessors/StorageTextureNode.js +1 -1
- package/src/nodes/accessors/TextureNode.js +12 -0
- package/src/nodes/core/ArrayNode.js +12 -0
- package/src/nodes/core/AssignNode.js +3 -0
- package/src/nodes/core/ContextNode.js +20 -1
- package/src/nodes/core/Node.js +14 -2
- package/src/nodes/core/NodeBuilder.js +25 -20
- package/src/nodes/core/NodeUtils.js +4 -1
- package/src/nodes/core/StackNode.js +42 -0
- package/src/nodes/core/UniformNode.js +63 -5
- package/src/nodes/core/VarNode.js +91 -2
- package/src/nodes/display/PassNode.js +148 -2
- package/src/nodes/display/ViewportTextureNode.js +67 -7
- package/src/nodes/functions/PhysicalLightingModel.js +2 -2
- package/src/nodes/gpgpu/AtomicFunctionNode.js +1 -1
- package/src/nodes/gpgpu/ComputeNode.js +67 -23
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +28 -3
- package/src/nodes/lighting/ProjectorLightNode.js +19 -6
- package/src/nodes/lighting/ShadowFilterNode.js +1 -1
- package/src/nodes/materialx/MaterialXNodes.js +131 -2
- package/src/nodes/materialx/lib/mx_noise.js +165 -1
- package/src/nodes/math/ConditionalNode.js +1 -1
- package/src/nodes/math/MathNode.js +78 -54
- package/src/nodes/math/OperatorNode.js +22 -22
- package/src/nodes/tsl/TSLCore.js +64 -9
- package/src/nodes/utils/DebugNode.js +1 -1
- package/src/nodes/utils/EventNode.js +83 -0
- package/src/nodes/utils/RTTNode.js +9 -0
- package/src/objects/BatchedMesh.js +4 -2
- package/src/renderers/WebGLRenderer.js +21 -22
- package/src/renderers/common/Bindings.js +19 -18
- package/src/renderers/common/Color4.js +2 -2
- package/src/renderers/common/PostProcessing.js +60 -5
- package/src/renderers/common/Renderer.js +18 -15
- package/src/renderers/common/SampledTexture.js +3 -71
- package/src/renderers/common/Sampler.js +79 -0
- package/src/renderers/common/Storage3DTexture.js +21 -0
- package/src/renderers/common/StorageArrayTexture.js +21 -0
- package/src/renderers/common/StorageTexture.js +19 -0
- package/src/renderers/common/Textures.js +19 -3
- package/src/renderers/common/XRManager.js +26 -8
- package/src/renderers/common/nodes/NodeSampledTexture.js +0 -12
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +20 -2
- package/src/renderers/shaders/ShaderLib/depth.glsl.js +11 -2
- package/src/renderers/webgl/WebGLCapabilities.js +2 -2
- package/src/renderers/webgl/WebGLMaterials.js +6 -6
- package/src/renderers/webgl/WebGLProgram.js +22 -16
- package/src/renderers/webgl/WebGLPrograms.js +4 -4
- package/src/renderers/webgl/WebGLShadowMap.js +11 -1
- package/src/renderers/webgl/WebGLTextures.js +19 -7
- package/src/renderers/webgl-fallback/WebGLBackend.js +22 -12
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +2 -2
- package/src/renderers/webgpu/WebGPUBackend.js +54 -15
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +53 -73
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +35 -31
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +1 -1
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +11 -64
- package/src/renderers/webgpu/utils/WebGPUUtils.js +2 -17
- package/src/renderers/webxr/WebXRDepthSensing.js +6 -10
- package/src/renderers/webxr/WebXRManager.js +68 -8
- package/src/textures/ExternalTexture.js +45 -0
- package/src/textures/FramebufferTexture.js +2 -2
- package/src/textures/Source.js +11 -1
- package/src/textures/VideoTexture.js +30 -2
|
@@ -9,6 +9,121 @@ import {
|
|
|
9
9
|
zipSync,
|
|
10
10
|
} from '../libs/fflate.module.js';
|
|
11
11
|
|
|
12
|
+
class USDNode {
|
|
13
|
+
|
|
14
|
+
constructor( name, type = '', metadata = [], properties = [] ) {
|
|
15
|
+
|
|
16
|
+
this.name = name;
|
|
17
|
+
this.type = type;
|
|
18
|
+
this.metadata = metadata;
|
|
19
|
+
this.properties = properties;
|
|
20
|
+
this.children = [];
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
addMetadata( key, value ) {
|
|
25
|
+
|
|
26
|
+
this.metadata.push( { key, value } );
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
addProperty( property, metadata = [] ) {
|
|
31
|
+
|
|
32
|
+
this.properties.push( { property, metadata } );
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
addChild( child ) {
|
|
37
|
+
|
|
38
|
+
this.children.push( child );
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
toString( indent = 0 ) {
|
|
43
|
+
|
|
44
|
+
const pad = '\t'.repeat( indent );
|
|
45
|
+
|
|
46
|
+
const formattedMetadata = this.metadata.map( ( item ) => {
|
|
47
|
+
|
|
48
|
+
const key = item.key;
|
|
49
|
+
const value = item.value;
|
|
50
|
+
|
|
51
|
+
if ( Array.isArray( value ) ) {
|
|
52
|
+
|
|
53
|
+
const lines = [];
|
|
54
|
+
lines.push( `${key} = {` );
|
|
55
|
+
value.forEach( ( line ) => {
|
|
56
|
+
|
|
57
|
+
lines.push( `${pad}\t\t${line}` );
|
|
58
|
+
|
|
59
|
+
} );
|
|
60
|
+
lines.push( `${pad}\t}` );
|
|
61
|
+
return lines.join( '\n' );
|
|
62
|
+
|
|
63
|
+
} else {
|
|
64
|
+
|
|
65
|
+
return `${key} = ${value}`;
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
} );
|
|
70
|
+
|
|
71
|
+
const meta = formattedMetadata.length
|
|
72
|
+
? ` (\n${formattedMetadata
|
|
73
|
+
.map( ( l ) => `${pad}\t${l}` )
|
|
74
|
+
.join( '\n' )}\n${pad})`
|
|
75
|
+
: '';
|
|
76
|
+
|
|
77
|
+
const properties = this.properties.map( ( l ) => {
|
|
78
|
+
|
|
79
|
+
const property = l.property;
|
|
80
|
+
const metadata = l.metadata.length
|
|
81
|
+
? ` (\n${l.metadata.map( ( m ) => `${pad}\t\t${m}` ).join( '\n' )}\n${pad}\t)`
|
|
82
|
+
: '';
|
|
83
|
+
return `${pad}\t${property}${metadata}`;
|
|
84
|
+
|
|
85
|
+
} );
|
|
86
|
+
const children = this.children.map( ( c ) => c.toString( indent + 1 ) );
|
|
87
|
+
|
|
88
|
+
const bodyLines = [];
|
|
89
|
+
|
|
90
|
+
if ( properties.length > 0 ) {
|
|
91
|
+
|
|
92
|
+
bodyLines.push( ...properties );
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if ( children.length > 0 ) {
|
|
97
|
+
|
|
98
|
+
if ( properties.length > 0 ) {
|
|
99
|
+
|
|
100
|
+
bodyLines.push( '' );
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for ( let i = 0; i < children.length; i ++ ) {
|
|
105
|
+
|
|
106
|
+
bodyLines.push( children[ i ] );
|
|
107
|
+
if ( i < children.length - 1 ) {
|
|
108
|
+
|
|
109
|
+
bodyLines.push( '' );
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const bodyContent = bodyLines.join( '\n' );
|
|
118
|
+
|
|
119
|
+
const type = this.type ? this.type + ' ' : '';
|
|
120
|
+
|
|
121
|
+
return `${pad}def ${type}"${this.name}"${meta}\n${pad}{\n${bodyContent}\n${pad}}`;
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
12
127
|
/**
|
|
13
128
|
* An exporter for USDZ.
|
|
14
129
|
*
|
|
@@ -74,15 +189,21 @@ class USDZExporter {
|
|
|
74
189
|
*/
|
|
75
190
|
async parseAsync( scene, options = {} ) {
|
|
76
191
|
|
|
77
|
-
options = Object.assign(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
192
|
+
options = Object.assign(
|
|
193
|
+
{
|
|
194
|
+
ar: {
|
|
195
|
+
anchoring: { type: 'plane' },
|
|
196
|
+
planeAnchoring: { alignment: 'horizontal' },
|
|
197
|
+
},
|
|
198
|
+
includeAnchoringProperties: true,
|
|
199
|
+
onlyVisible: true,
|
|
200
|
+
quickLookCompatible: false,
|
|
201
|
+
maxTextureSize: 1024,
|
|
81
202
|
},
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
203
|
+
options
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const usedNames = new Set();
|
|
86
207
|
|
|
87
208
|
const files = {};
|
|
88
209
|
const modelFileName = 'model.usda';
|
|
@@ -90,57 +211,50 @@ class USDZExporter {
|
|
|
90
211
|
// model file should be first in USDZ archive so we init it here
|
|
91
212
|
files[ modelFileName ] = null;
|
|
92
213
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const meshObject = buildMeshObject( geometry );
|
|
114
|
-
files[ geometryFileName ] = buildUSDFileAsString( meshObject );
|
|
214
|
+
const root = new USDNode( 'Root', 'Xform' );
|
|
215
|
+
const scenesNode = new USDNode( 'Scenes', 'Scope' );
|
|
216
|
+
scenesNode.addMetadata( 'kind', '"sceneLibrary"' );
|
|
217
|
+
root.addChild( scenesNode );
|
|
218
|
+
|
|
219
|
+
const sceneName = 'Scene';
|
|
220
|
+
const sceneNode = new USDNode( sceneName, 'Xform' );
|
|
221
|
+
sceneNode.addMetadata( 'customData', [
|
|
222
|
+
'bool preliminary_collidesWithEnvironment = 0',
|
|
223
|
+
`string sceneName = "${sceneName}"`,
|
|
224
|
+
] );
|
|
225
|
+
sceneNode.addMetadata( 'sceneName', `"${sceneName}"` );
|
|
226
|
+
if ( options.includeAnchoringProperties ) {
|
|
227
|
+
|
|
228
|
+
sceneNode.addProperty(
|
|
229
|
+
`token preliminary:anchoring:type = "${options.ar.anchoring.type}"`
|
|
230
|
+
);
|
|
231
|
+
sceneNode.addProperty(
|
|
232
|
+
`token preliminary:planeAnchoring:alignment = "${options.ar.planeAnchoring.alignment}"`
|
|
233
|
+
);
|
|
115
234
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if ( ! ( material.uuid in materials ) ) {
|
|
119
|
-
|
|
120
|
-
materials[ material.uuid ] = material;
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
output += buildXform( object, geometry, materials[ material.uuid ] );
|
|
125
|
-
|
|
126
|
-
} else {
|
|
127
|
-
|
|
128
|
-
console.warn( 'THREE.USDZExporter: Unsupported material type (USDZ only supports MeshStandardMaterial)', object );
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
} else if ( object.isCamera ) {
|
|
235
|
+
}
|
|
133
236
|
|
|
134
|
-
|
|
237
|
+
scenesNode.addChild( sceneNode );
|
|
135
238
|
|
|
136
|
-
|
|
239
|
+
let output;
|
|
137
240
|
|
|
138
|
-
}
|
|
241
|
+
const materials = {};
|
|
242
|
+
const textures = {};
|
|
139
243
|
|
|
244
|
+
buildHierarchy( scene, sceneNode, materials, usedNames, files, options );
|
|
140
245
|
|
|
141
|
-
|
|
246
|
+
const materialsNode = buildMaterials(
|
|
247
|
+
materials,
|
|
248
|
+
textures,
|
|
249
|
+
options.quickLookCompatible
|
|
250
|
+
);
|
|
142
251
|
|
|
143
|
-
output
|
|
252
|
+
output =
|
|
253
|
+
buildHeader() +
|
|
254
|
+
'\n' +
|
|
255
|
+
root.toString() +
|
|
256
|
+
'\n\n' +
|
|
257
|
+
materialsNode.toString();
|
|
144
258
|
|
|
145
259
|
files[ modelFileName ] = strToU8( output );
|
|
146
260
|
output = null;
|
|
@@ -153,7 +267,9 @@ class USDZExporter {
|
|
|
153
267
|
|
|
154
268
|
if ( this.textureUtils === null ) {
|
|
155
269
|
|
|
156
|
-
throw new Error(
|
|
270
|
+
throw new Error(
|
|
271
|
+
'THREE.USDZExporter: setTextureUtils() must be called to process compressed textures.'
|
|
272
|
+
);
|
|
157
273
|
|
|
158
274
|
} else {
|
|
159
275
|
|
|
@@ -163,10 +279,18 @@ class USDZExporter {
|
|
|
163
279
|
|
|
164
280
|
}
|
|
165
281
|
|
|
166
|
-
const canvas = imageToCanvas(
|
|
167
|
-
|
|
282
|
+
const canvas = imageToCanvas(
|
|
283
|
+
texture.image,
|
|
284
|
+
texture.flipY,
|
|
285
|
+
options.maxTextureSize
|
|
286
|
+
);
|
|
287
|
+
const blob = await new Promise( ( resolve ) =>
|
|
288
|
+
canvas.toBlob( resolve, 'image/png', 1 )
|
|
289
|
+
);
|
|
168
290
|
|
|
169
|
-
files[ `textures/Texture_${
|
|
291
|
+
files[ `textures/Texture_${id}.png` ] = new Uint8Array(
|
|
292
|
+
await blob.arrayBuffer()
|
|
293
|
+
);
|
|
170
294
|
|
|
171
295
|
}
|
|
172
296
|
|
|
@@ -203,12 +327,53 @@ class USDZExporter {
|
|
|
203
327
|
|
|
204
328
|
}
|
|
205
329
|
|
|
330
|
+
function getName( object, namesSet ) {
|
|
331
|
+
|
|
332
|
+
let name = object.name;
|
|
333
|
+
name = name.replace( /[^A-Za-z0-9_]/g, '' );
|
|
334
|
+
if ( /^[0-9]/.test( name ) ) {
|
|
335
|
+
|
|
336
|
+
name = '_' + name;
|
|
337
|
+
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if ( name === '' ) {
|
|
341
|
+
|
|
342
|
+
if ( object.isCamera ) {
|
|
343
|
+
|
|
344
|
+
name = 'Camera';
|
|
345
|
+
|
|
346
|
+
} else {
|
|
347
|
+
|
|
348
|
+
name = 'Object';
|
|
349
|
+
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if ( namesSet.has( name ) ) {
|
|
355
|
+
|
|
356
|
+
name = name + '_' + object.id;
|
|
357
|
+
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
namesSet.add( name );
|
|
361
|
+
|
|
362
|
+
return name;
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
|
|
206
366
|
function imageToCanvas( image, flipY, maxTextureSize ) {
|
|
207
367
|
|
|
208
|
-
if (
|
|
209
|
-
( typeof
|
|
210
|
-
|
|
211
|
-
( typeof
|
|
368
|
+
if (
|
|
369
|
+
( typeof HTMLImageElement !== 'undefined' &&
|
|
370
|
+
image instanceof HTMLImageElement ) ||
|
|
371
|
+
( typeof HTMLCanvasElement !== 'undefined' &&
|
|
372
|
+
image instanceof HTMLCanvasElement ) ||
|
|
373
|
+
( typeof OffscreenCanvas !== 'undefined' &&
|
|
374
|
+
image instanceof OffscreenCanvas ) ||
|
|
375
|
+
( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap )
|
|
376
|
+
) {
|
|
212
377
|
|
|
213
378
|
const scale = maxTextureSize / Math.max( image.width, image.height );
|
|
214
379
|
|
|
@@ -233,7 +398,9 @@ function imageToCanvas( image, flipY, maxTextureSize ) {
|
|
|
233
398
|
|
|
234
399
|
} else {
|
|
235
400
|
|
|
236
|
-
throw new Error(
|
|
401
|
+
throw new Error(
|
|
402
|
+
'THREE.USDZExporter: No valid image data found. Unable to process texture.'
|
|
403
|
+
);
|
|
237
404
|
|
|
238
405
|
}
|
|
239
406
|
|
|
@@ -254,79 +421,121 @@ function buildHeader() {
|
|
|
254
421
|
metersPerUnit = 1
|
|
255
422
|
upAxis = "Y"
|
|
256
423
|
)
|
|
257
|
-
|
|
258
424
|
`;
|
|
259
425
|
|
|
260
426
|
}
|
|
261
427
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
428
|
+
// Xform
|
|
429
|
+
|
|
430
|
+
function buildHierarchy( object, parentNode, materials, usedNames, files, options ) {
|
|
431
|
+
|
|
432
|
+
for ( let i = 0, l = object.children.length; i < l; i ++ ) {
|
|
433
|
+
|
|
434
|
+
const child = object.children[ i ];
|
|
435
|
+
|
|
436
|
+
if ( child.visible === false && options.onlyVisible === true ) continue;
|
|
437
|
+
|
|
438
|
+
let childNode;
|
|
439
|
+
|
|
440
|
+
if ( child.isMesh ) {
|
|
441
|
+
|
|
442
|
+
const geometry = child.geometry;
|
|
443
|
+
const material = child.material;
|
|
444
|
+
|
|
445
|
+
if ( material.isMeshStandardMaterial ) {
|
|
446
|
+
|
|
447
|
+
const geometryFileName = 'geometries/Geometry_' + geometry.id + '.usda';
|
|
448
|
+
|
|
449
|
+
if ( ! ( geometryFileName in files ) ) {
|
|
450
|
+
|
|
451
|
+
const meshObject = buildMeshObject( geometry );
|
|
452
|
+
files[ geometryFileName ] = strToU8(
|
|
453
|
+
buildHeader() + '\n' + meshObject.toString()
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if ( ! ( material.uuid in materials ) ) {
|
|
459
|
+
|
|
460
|
+
materials[ material.uuid ] = material;
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
childNode = buildMesh(
|
|
465
|
+
child,
|
|
466
|
+
geometry,
|
|
467
|
+
materials[ material.uuid ],
|
|
468
|
+
usedNames
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
} else {
|
|
472
|
+
|
|
473
|
+
console.warn(
|
|
474
|
+
'THREE.USDZExporter: Unsupported material type (USDZ only supports MeshStandardMaterial)',
|
|
475
|
+
child
|
|
476
|
+
);
|
|
477
|
+
|
|
278
478
|
}
|
|
279
|
-
sceneName = "Scene"
|
|
280
|
-
)
|
|
281
|
-
{${alignment}
|
|
282
|
-
`;
|
|
283
479
|
|
|
284
|
-
}
|
|
480
|
+
} else if ( child.isCamera ) {
|
|
285
481
|
|
|
286
|
-
|
|
482
|
+
childNode = buildCamera( child, usedNames );
|
|
483
|
+
|
|
484
|
+
} else {
|
|
485
|
+
|
|
486
|
+
childNode = buildXform( child, usedNames );
|
|
287
487
|
|
|
288
|
-
return `
|
|
289
488
|
}
|
|
489
|
+
|
|
490
|
+
if ( childNode ) {
|
|
491
|
+
|
|
492
|
+
parentNode.addChild( childNode );
|
|
493
|
+
buildHierarchy( child, childNode, materials, usedNames, files, options );
|
|
494
|
+
|
|
495
|
+
}
|
|
496
|
+
|
|
290
497
|
}
|
|
498
|
+
|
|
291
499
|
}
|
|
292
500
|
|
|
293
|
-
|
|
501
|
+
function buildXform( object, usedNames ) {
|
|
294
502
|
|
|
295
|
-
|
|
503
|
+
const name = getName( object, usedNames );
|
|
504
|
+
const transform = buildMatrix( object.matrix );
|
|
296
505
|
|
|
297
|
-
|
|
506
|
+
if ( object.matrix.determinant() < 0 ) {
|
|
298
507
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
508
|
+
console.warn(
|
|
509
|
+
'THREE.USDZExporter: USDZ does not support negative scales',
|
|
510
|
+
object
|
|
511
|
+
);
|
|
302
512
|
|
|
303
|
-
}
|
|
513
|
+
}
|
|
304
514
|
|
|
305
|
-
|
|
515
|
+
const node = new USDNode( name, 'Xform' );
|
|
306
516
|
|
|
307
|
-
|
|
517
|
+
node.addProperty( `matrix4d xformOp:transform = ${transform}` );
|
|
518
|
+
node.addProperty( 'uniform token[] xformOpOrder = ["xformOp:transform"]' );
|
|
308
519
|
|
|
309
|
-
|
|
310
|
-
const transform = buildMatrix( object.matrixWorld );
|
|
520
|
+
return node;
|
|
311
521
|
|
|
312
|
-
|
|
522
|
+
}
|
|
313
523
|
|
|
314
|
-
|
|
524
|
+
function buildMesh( object, geometry, material, usedNames ) {
|
|
315
525
|
|
|
316
|
-
|
|
526
|
+
const node = buildXform( object, usedNames );
|
|
317
527
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
matrix4d xformOp:transform = ${ transform }
|
|
324
|
-
uniform token[] xformOpOrder = ["xformOp:transform"]
|
|
528
|
+
node.addMetadata(
|
|
529
|
+
'prepend references',
|
|
530
|
+
`@./geometries/Geometry_${geometry.id}.usda@</Geometry>`
|
|
531
|
+
);
|
|
532
|
+
node.addMetadata( 'prepend apiSchemas', '["MaterialBindingAPI"]' );
|
|
325
533
|
|
|
326
|
-
|
|
327
|
-
|
|
534
|
+
node.addProperty(
|
|
535
|
+
`rel material:binding = </Materials/Material_${material.id}>`
|
|
536
|
+
);
|
|
328
537
|
|
|
329
|
-
|
|
538
|
+
return node;
|
|
330
539
|
|
|
331
540
|
}
|
|
332
541
|
|
|
@@ -334,13 +543,18 @@ function buildMatrix( matrix ) {
|
|
|
334
543
|
|
|
335
544
|
const array = matrix.elements;
|
|
336
545
|
|
|
337
|
-
return `( ${
|
|
546
|
+
return `( ${buildMatrixRow( array, 0 )}, ${buildMatrixRow(
|
|
547
|
+
array,
|
|
548
|
+
4
|
|
549
|
+
)}, ${buildMatrixRow( array, 8 )}, ${buildMatrixRow( array, 12 )} )`;
|
|
338
550
|
|
|
339
551
|
}
|
|
340
552
|
|
|
341
553
|
function buildMatrixRow( array, offset ) {
|
|
342
554
|
|
|
343
|
-
return `(${
|
|
555
|
+
return `(${array[ offset + 0 ]}, ${array[ offset + 1 ]}, ${array[ offset + 2 ]}, ${
|
|
556
|
+
array[ offset + 3 ]
|
|
557
|
+
})`;
|
|
344
558
|
|
|
345
559
|
}
|
|
346
560
|
|
|
@@ -348,43 +562,81 @@ function buildMatrixRow( array, offset ) {
|
|
|
348
562
|
|
|
349
563
|
function buildMeshObject( geometry ) {
|
|
350
564
|
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
`;
|
|
565
|
+
const node = new USDNode( 'Geometry' );
|
|
566
|
+
|
|
567
|
+
const meshNode = buildMeshNode( geometry );
|
|
568
|
+
node.addChild( meshNode );
|
|
569
|
+
|
|
570
|
+
return node;
|
|
358
571
|
|
|
359
572
|
}
|
|
360
573
|
|
|
361
|
-
function
|
|
574
|
+
function buildMeshNode( geometry ) {
|
|
362
575
|
|
|
363
576
|
const name = 'Geometry';
|
|
364
577
|
const attributes = geometry.attributes;
|
|
365
578
|
const count = attributes.position.count;
|
|
366
579
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
int[] faceVertexCounts = [${
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
${
|
|
377
|
-
|
|
580
|
+
const node = new USDNode( name, 'Mesh' );
|
|
581
|
+
|
|
582
|
+
node.addProperty(
|
|
583
|
+
`int[] faceVertexCounts = [${buildMeshVertexCount( geometry )}]`
|
|
584
|
+
);
|
|
585
|
+
node.addProperty(
|
|
586
|
+
`int[] faceVertexIndices = [${buildMeshVertexIndices( geometry )}]`
|
|
587
|
+
);
|
|
588
|
+
node.addProperty(
|
|
589
|
+
`normal3f[] normals = [${buildVector3Array( attributes.normal, count )}]`,
|
|
590
|
+
[ 'interpolation = "vertex"' ]
|
|
591
|
+
);
|
|
592
|
+
node.addProperty(
|
|
593
|
+
`point3f[] points = [${buildVector3Array( attributes.position, count )}]`
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
for ( let i = 0; i < 4; i ++ ) {
|
|
597
|
+
|
|
598
|
+
const id = i > 0 ? i : '';
|
|
599
|
+
const attribute = attributes[ 'uv' + id ];
|
|
600
|
+
if ( attribute !== undefined ) {
|
|
601
|
+
|
|
602
|
+
node.addProperty(
|
|
603
|
+
`texCoord2f[] primvars:st${id} = [${buildVector2Array( attribute )}]`,
|
|
604
|
+
[ 'interpolation = "vertex"' ]
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
}
|
|
608
|
+
|
|
378
609
|
}
|
|
379
|
-
|
|
610
|
+
|
|
611
|
+
const colorAttribute = attributes.color;
|
|
612
|
+
if ( colorAttribute !== undefined ) {
|
|
613
|
+
|
|
614
|
+
node.addProperty(
|
|
615
|
+
`color3f[] primvars:displayColor = [${buildVector3Array(
|
|
616
|
+
colorAttribute,
|
|
617
|
+
count
|
|
618
|
+
)}]`,
|
|
619
|
+
[ 'interpolation = "vertex"' ]
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
node.addProperty( 'uniform token subdivisionScheme = "none"' );
|
|
625
|
+
|
|
626
|
+
return node;
|
|
380
627
|
|
|
381
628
|
}
|
|
382
629
|
|
|
383
630
|
function buildMeshVertexCount( geometry ) {
|
|
384
631
|
|
|
385
|
-
const count =
|
|
632
|
+
const count =
|
|
633
|
+
geometry.index !== null
|
|
634
|
+
? geometry.index.count
|
|
635
|
+
: geometry.attributes.position.count;
|
|
386
636
|
|
|
387
|
-
return Array( count / 3 )
|
|
637
|
+
return Array( count / 3 )
|
|
638
|
+
.fill( 3 )
|
|
639
|
+
.join( ', ' );
|
|
388
640
|
|
|
389
641
|
}
|
|
390
642
|
|
|
@@ -434,7 +686,11 @@ function buildVector3Array( attribute, count ) {
|
|
|
434
686
|
const y = attribute.getY( i );
|
|
435
687
|
const z = attribute.getZ( i );
|
|
436
688
|
|
|
437
|
-
array.push(
|
|
689
|
+
array.push(
|
|
690
|
+
`(${x.toPrecision( PRECISION )}, ${y.toPrecision(
|
|
691
|
+
PRECISION
|
|
692
|
+
)}, ${z.toPrecision( PRECISION )})`
|
|
693
|
+
);
|
|
438
694
|
|
|
439
695
|
}
|
|
440
696
|
|
|
@@ -451,7 +707,9 @@ function buildVector2Array( attribute ) {
|
|
|
451
707
|
const x = attribute.getX( i );
|
|
452
708
|
const y = attribute.getY( i );
|
|
453
709
|
|
|
454
|
-
array.push(
|
|
710
|
+
array.push(
|
|
711
|
+
`(${x.toPrecision( PRECISION )}, ${1 - y.toPrecision( PRECISION )})`
|
|
712
|
+
);
|
|
455
713
|
|
|
456
714
|
}
|
|
457
715
|
|
|
@@ -459,65 +717,23 @@ function buildVector2Array( attribute ) {
|
|
|
459
717
|
|
|
460
718
|
}
|
|
461
719
|
|
|
462
|
-
function buildPrimvars( attributes ) {
|
|
463
|
-
|
|
464
|
-
let string = '';
|
|
465
|
-
|
|
466
|
-
for ( let i = 0; i < 4; i ++ ) {
|
|
467
|
-
|
|
468
|
-
const id = ( i > 0 ? i : '' );
|
|
469
|
-
const attribute = attributes[ 'uv' + id ];
|
|
470
|
-
|
|
471
|
-
if ( attribute !== undefined ) {
|
|
472
|
-
|
|
473
|
-
string += `
|
|
474
|
-
texCoord2f[] primvars:st${ id } = [${ buildVector2Array( attribute )}] (
|
|
475
|
-
interpolation = "vertex"
|
|
476
|
-
)`;
|
|
477
|
-
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// vertex colors
|
|
483
|
-
|
|
484
|
-
const colorAttribute = attributes.color;
|
|
485
|
-
|
|
486
|
-
if ( colorAttribute !== undefined ) {
|
|
487
|
-
|
|
488
|
-
const count = colorAttribute.count;
|
|
489
|
-
|
|
490
|
-
string += `
|
|
491
|
-
color3f[] primvars:displayColor = [${buildVector3Array( colorAttribute, count )}] (
|
|
492
|
-
interpolation = "vertex"
|
|
493
|
-
)`;
|
|
494
|
-
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
return string;
|
|
498
|
-
|
|
499
|
-
}
|
|
500
|
-
|
|
501
720
|
// Materials
|
|
502
721
|
|
|
503
722
|
function buildMaterials( materials, textures, quickLookCompatible = false ) {
|
|
504
723
|
|
|
505
|
-
const
|
|
724
|
+
const materialsNode = new USDNode( 'Materials' );
|
|
506
725
|
|
|
507
726
|
for ( const uuid in materials ) {
|
|
508
727
|
|
|
509
728
|
const material = materials[ uuid ];
|
|
510
729
|
|
|
511
|
-
|
|
730
|
+
materialsNode.addChild(
|
|
731
|
+
buildMaterial( material, textures, quickLookCompatible )
|
|
732
|
+
);
|
|
512
733
|
|
|
513
734
|
}
|
|
514
735
|
|
|
515
|
-
return
|
|
516
|
-
{
|
|
517
|
-
${ array.join( '' ) }
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
`;
|
|
736
|
+
return materialsNode;
|
|
521
737
|
|
|
522
738
|
}
|
|
523
739
|
|
|
@@ -525,11 +741,9 @@ function buildMaterial( material, textures, quickLookCompatible = false ) {
|
|
|
525
741
|
|
|
526
742
|
// https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html
|
|
527
743
|
|
|
528
|
-
const
|
|
529
|
-
const inputs = [];
|
|
530
|
-
const samplers = [];
|
|
744
|
+
const materialNode = new USDNode( `Material_${material.id}`, 'Material' );
|
|
531
745
|
|
|
532
|
-
function
|
|
746
|
+
function buildTextureNodes( texture, mapType, color ) {
|
|
533
747
|
|
|
534
748
|
const id = texture.source.id + '_' + texture.flipY;
|
|
535
749
|
|
|
@@ -540,7 +754,7 @@ function buildMaterial( material, textures, quickLookCompatible = false ) {
|
|
|
540
754
|
const WRAPPINGS = {
|
|
541
755
|
1000: 'repeat', // RepeatWrapping
|
|
542
756
|
1001: 'clamp', // ClampToEdgeWrapping
|
|
543
|
-
1002: 'mirror' // MirroredRepeatWrapping
|
|
757
|
+
1002: 'mirror', // MirroredRepeatWrapping
|
|
544
758
|
};
|
|
545
759
|
|
|
546
760
|
const repeat = texture.repeat.clone();
|
|
@@ -575,135 +789,248 @@ function buildMaterial( material, textures, quickLookCompatible = false ) {
|
|
|
575
789
|
|
|
576
790
|
}
|
|
577
791
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
792
|
+
const primvarReaderNode = new USDNode( `PrimvarReader_${mapType}`, 'Shader' );
|
|
793
|
+
primvarReaderNode.addProperty(
|
|
794
|
+
'uniform token info:id = "UsdPrimvarReader_float2"'
|
|
795
|
+
);
|
|
796
|
+
primvarReaderNode.addProperty( 'float2 inputs:fallback = (0.0, 0.0)' );
|
|
797
|
+
primvarReaderNode.addProperty( `token inputs:varname = "${uv}"` );
|
|
798
|
+
primvarReaderNode.addProperty( 'float2 outputs:result' );
|
|
799
|
+
|
|
800
|
+
const transform2dNode = new USDNode( `Transform2d_${mapType}`, 'Shader' );
|
|
801
|
+
transform2dNode.addProperty( 'uniform token info:id = "UsdTransform2d"' );
|
|
802
|
+
transform2dNode.addProperty(
|
|
803
|
+
`token inputs:in.connect = </Materials/Material_${material.id}/PrimvarReader_${mapType}.outputs:result>`
|
|
804
|
+
);
|
|
805
|
+
transform2dNode.addProperty(
|
|
806
|
+
`float inputs:rotation = ${( rotation * ( 180 / Math.PI ) ).toFixed(
|
|
807
|
+
PRECISION
|
|
808
|
+
)}`
|
|
809
|
+
);
|
|
810
|
+
transform2dNode.addProperty(
|
|
811
|
+
`float2 inputs:scale = ${buildVector2( repeat )}`
|
|
812
|
+
);
|
|
813
|
+
transform2dNode.addProperty(
|
|
814
|
+
`float2 inputs:translation = ${buildVector2( offset )}`
|
|
815
|
+
);
|
|
816
|
+
transform2dNode.addProperty( 'float2 outputs:result' );
|
|
817
|
+
|
|
818
|
+
const textureNode = new USDNode(
|
|
819
|
+
`Texture_${texture.id}_${mapType}`,
|
|
820
|
+
'Shader'
|
|
821
|
+
);
|
|
822
|
+
textureNode.addProperty( 'uniform token info:id = "UsdUVTexture"' );
|
|
823
|
+
textureNode.addProperty( `asset inputs:file = @textures/Texture_${id}.png@` );
|
|
824
|
+
textureNode.addProperty(
|
|
825
|
+
`float2 inputs:st.connect = </Materials/Material_${material.id}/Transform2d_${mapType}.outputs:result>`
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
if ( color !== undefined ) {
|
|
829
|
+
|
|
830
|
+
textureNode.addProperty( `float4 inputs:scale = ${buildColor4( color )}` );
|
|
831
|
+
|
|
585
832
|
}
|
|
586
833
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
834
|
+
textureNode.addProperty(
|
|
835
|
+
`token inputs:sourceColorSpace = "${
|
|
836
|
+
texture.colorSpace === NoColorSpace ? 'raw' : 'sRGB'
|
|
837
|
+
}"`
|
|
838
|
+
);
|
|
839
|
+
textureNode.addProperty(
|
|
840
|
+
`token inputs:wrapS = "${WRAPPINGS[ texture.wrapS ]}"`
|
|
841
|
+
);
|
|
842
|
+
textureNode.addProperty(
|
|
843
|
+
`token inputs:wrapT = "${WRAPPINGS[ texture.wrapT ]}"`
|
|
844
|
+
);
|
|
845
|
+
textureNode.addProperty( 'float outputs:r' );
|
|
846
|
+
textureNode.addProperty( 'float outputs:g' );
|
|
847
|
+
textureNode.addProperty( 'float outputs:b' );
|
|
848
|
+
textureNode.addProperty( 'float3 outputs:rgb' );
|
|
849
|
+
|
|
850
|
+
if ( material.transparent || material.alphaTest > 0.0 ) {
|
|
851
|
+
|
|
852
|
+
textureNode.addProperty( 'float outputs:a' );
|
|
853
|
+
|
|
595
854
|
}
|
|
596
855
|
|
|
597
|
-
|
|
598
|
-
{
|
|
599
|
-
uniform token info:id = "UsdUVTexture"
|
|
600
|
-
asset inputs:file = @textures/Texture_${ id }.png@
|
|
601
|
-
float2 inputs:st.connect = </Materials/Material_${ material.id }/Transform2d_${ mapType }.outputs:result>
|
|
602
|
-
${ color !== undefined ? 'float4 inputs:scale = ' + buildColor4( color ) : '' }
|
|
603
|
-
token inputs:sourceColorSpace = "${ texture.colorSpace === NoColorSpace ? 'raw' : 'sRGB' }"
|
|
604
|
-
token inputs:wrapS = "${ WRAPPINGS[ texture.wrapS ] }"
|
|
605
|
-
token inputs:wrapT = "${ WRAPPINGS[ texture.wrapT ] }"
|
|
606
|
-
float outputs:r
|
|
607
|
-
float outputs:g
|
|
608
|
-
float outputs:b
|
|
609
|
-
float3 outputs:rgb
|
|
610
|
-
${ material.transparent || material.alphaTest > 0.0 ? 'float outputs:a' : '' }
|
|
611
|
-
}`;
|
|
856
|
+
return [ primvarReaderNode, transform2dNode, textureNode ];
|
|
612
857
|
|
|
613
858
|
}
|
|
614
859
|
|
|
615
|
-
|
|
616
860
|
if ( material.side === DoubleSide ) {
|
|
617
861
|
|
|
618
|
-
console.warn(
|
|
862
|
+
console.warn(
|
|
863
|
+
'THREE.USDZExporter: USDZ does not support double sided materials',
|
|
864
|
+
material
|
|
865
|
+
);
|
|
619
866
|
|
|
620
867
|
}
|
|
621
868
|
|
|
869
|
+
const previewSurfaceNode = new USDNode( 'PreviewSurface', 'Shader' );
|
|
870
|
+
previewSurfaceNode.addProperty( 'uniform token info:id = "UsdPreviewSurface"' );
|
|
871
|
+
|
|
622
872
|
if ( material.map !== null ) {
|
|
623
873
|
|
|
624
|
-
|
|
874
|
+
previewSurfaceNode.addProperty(
|
|
875
|
+
`color3f inputs:diffuseColor.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:rgb>`
|
|
876
|
+
);
|
|
625
877
|
|
|
626
878
|
if ( material.transparent ) {
|
|
627
879
|
|
|
628
|
-
|
|
880
|
+
previewSurfaceNode.addProperty(
|
|
881
|
+
`float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:a>`
|
|
882
|
+
);
|
|
629
883
|
|
|
630
884
|
} else if ( material.alphaTest > 0.0 ) {
|
|
631
885
|
|
|
632
|
-
|
|
633
|
-
|
|
886
|
+
previewSurfaceNode.addProperty(
|
|
887
|
+
`float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:a>`
|
|
888
|
+
);
|
|
889
|
+
previewSurfaceNode.addProperty(
|
|
890
|
+
`float inputs:opacityThreshold = ${material.alphaTest}`
|
|
891
|
+
);
|
|
634
892
|
|
|
635
893
|
}
|
|
636
894
|
|
|
637
|
-
|
|
895
|
+
const textureNodes = buildTextureNodes(
|
|
896
|
+
material.map,
|
|
897
|
+
'diffuse',
|
|
898
|
+
material.color
|
|
899
|
+
);
|
|
900
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
638
901
|
|
|
639
902
|
} else {
|
|
640
903
|
|
|
641
|
-
|
|
904
|
+
previewSurfaceNode.addProperty(
|
|
905
|
+
`color3f inputs:diffuseColor = ${buildColor( material.color )}`
|
|
906
|
+
);
|
|
642
907
|
|
|
643
908
|
}
|
|
644
909
|
|
|
645
910
|
if ( material.emissiveMap !== null ) {
|
|
646
911
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
912
|
+
previewSurfaceNode.addProperty(
|
|
913
|
+
`color3f inputs:emissiveColor.connect = </Materials/Material_${material.id}/Texture_${material.emissiveMap.id}_emissive.outputs:rgb>`
|
|
914
|
+
);
|
|
915
|
+
|
|
916
|
+
const emissiveColor = new Color(
|
|
917
|
+
material.emissive.r * material.emissiveIntensity,
|
|
918
|
+
material.emissive.g * material.emissiveIntensity,
|
|
919
|
+
material.emissive.b * material.emissiveIntensity
|
|
920
|
+
);
|
|
921
|
+
const textureNodes = buildTextureNodes(
|
|
922
|
+
material.emissiveMap,
|
|
923
|
+
'emissive',
|
|
924
|
+
emissiveColor
|
|
925
|
+
);
|
|
926
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
650
927
|
|
|
651
928
|
} else if ( material.emissive.getHex() > 0 ) {
|
|
652
929
|
|
|
653
|
-
|
|
930
|
+
previewSurfaceNode.addProperty(
|
|
931
|
+
`color3f inputs:emissiveColor = ${buildColor( material.emissive )}`
|
|
932
|
+
);
|
|
654
933
|
|
|
655
934
|
}
|
|
656
935
|
|
|
657
936
|
if ( material.normalMap !== null ) {
|
|
658
937
|
|
|
659
|
-
|
|
938
|
+
previewSurfaceNode.addProperty(
|
|
939
|
+
`normal3f inputs:normal.connect = </Materials/Material_${material.id}/Texture_${material.normalMap.id}_normal.outputs:rgb>`
|
|
940
|
+
);
|
|
660
941
|
|
|
661
|
-
|
|
942
|
+
const textureNodes = buildTextureNodes( material.normalMap, 'normal' );
|
|
943
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
662
944
|
|
|
663
945
|
}
|
|
664
946
|
|
|
665
947
|
if ( material.aoMap !== null ) {
|
|
666
948
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
949
|
+
previewSurfaceNode.addProperty(
|
|
950
|
+
`float inputs:occlusion.connect = </Materials/Material_${material.id}/Texture_${material.aoMap.id}_occlusion.outputs:r>`
|
|
951
|
+
);
|
|
952
|
+
|
|
953
|
+
const aoColor = new Color(
|
|
954
|
+
material.aoMapIntensity,
|
|
955
|
+
material.aoMapIntensity,
|
|
956
|
+
material.aoMapIntensity
|
|
957
|
+
);
|
|
958
|
+
const textureNodes = buildTextureNodes(
|
|
959
|
+
material.aoMap,
|
|
960
|
+
'occlusion',
|
|
961
|
+
aoColor
|
|
962
|
+
);
|
|
963
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
670
964
|
|
|
671
965
|
}
|
|
672
966
|
|
|
673
967
|
if ( material.roughnessMap !== null ) {
|
|
674
968
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
969
|
+
previewSurfaceNode.addProperty(
|
|
970
|
+
`float inputs:roughness.connect = </Materials/Material_${material.id}/Texture_${material.roughnessMap.id}_roughness.outputs:g>`
|
|
971
|
+
);
|
|
972
|
+
|
|
973
|
+
const roughnessColor = new Color(
|
|
974
|
+
material.roughness,
|
|
975
|
+
material.roughness,
|
|
976
|
+
material.roughness
|
|
977
|
+
);
|
|
978
|
+
const textureNodes = buildTextureNodes(
|
|
979
|
+
material.roughnessMap,
|
|
980
|
+
'roughness',
|
|
981
|
+
roughnessColor
|
|
982
|
+
);
|
|
983
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
678
984
|
|
|
679
985
|
} else {
|
|
680
986
|
|
|
681
|
-
|
|
987
|
+
previewSurfaceNode.addProperty(
|
|
988
|
+
`float inputs:roughness = ${material.roughness}`
|
|
989
|
+
);
|
|
682
990
|
|
|
683
991
|
}
|
|
684
992
|
|
|
685
993
|
if ( material.metalnessMap !== null ) {
|
|
686
994
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
995
|
+
previewSurfaceNode.addProperty(
|
|
996
|
+
`float inputs:metallic.connect = </Materials/Material_${material.id}/Texture_${material.metalnessMap.id}_metallic.outputs:b>`
|
|
997
|
+
);
|
|
998
|
+
|
|
999
|
+
const metalnessColor = new Color(
|
|
1000
|
+
material.metalness,
|
|
1001
|
+
material.metalness,
|
|
1002
|
+
material.metalness
|
|
1003
|
+
);
|
|
1004
|
+
const textureNodes = buildTextureNodes(
|
|
1005
|
+
material.metalnessMap,
|
|
1006
|
+
'metallic',
|
|
1007
|
+
metalnessColor
|
|
1008
|
+
);
|
|
1009
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
690
1010
|
|
|
691
1011
|
} else {
|
|
692
1012
|
|
|
693
|
-
|
|
1013
|
+
previewSurfaceNode.addProperty(
|
|
1014
|
+
`float inputs:metallic = ${material.metalness}`
|
|
1015
|
+
);
|
|
694
1016
|
|
|
695
1017
|
}
|
|
696
1018
|
|
|
697
1019
|
if ( material.alphaMap !== null ) {
|
|
698
1020
|
|
|
699
|
-
|
|
700
|
-
|
|
1021
|
+
previewSurfaceNode.addProperty(
|
|
1022
|
+
`float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.alphaMap.id}_opacity.outputs:r>`
|
|
1023
|
+
);
|
|
1024
|
+
previewSurfaceNode.addProperty( 'float inputs:opacityThreshold = 0.0001' );
|
|
701
1025
|
|
|
702
|
-
|
|
1026
|
+
const textureNodes = buildTextureNodes( material.alphaMap, 'opacity' );
|
|
1027
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
703
1028
|
|
|
704
1029
|
} else {
|
|
705
1030
|
|
|
706
|
-
|
|
1031
|
+
previewSurfaceNode.addProperty(
|
|
1032
|
+
`float inputs:opacity = ${material.opacity}`
|
|
1033
|
+
);
|
|
707
1034
|
|
|
708
1035
|
}
|
|
709
1036
|
|
|
@@ -711,115 +1038,164 @@ function buildMaterial( material, textures, quickLookCompatible = false ) {
|
|
|
711
1038
|
|
|
712
1039
|
if ( material.clearcoatMap !== null ) {
|
|
713
1040
|
|
|
714
|
-
|
|
715
|
-
|
|
1041
|
+
previewSurfaceNode.addProperty(
|
|
1042
|
+
`float inputs:clearcoat.connect = </Materials/Material_${material.id}/Texture_${material.clearcoatMap.id}_clearcoat.outputs:r>`
|
|
1043
|
+
);
|
|
1044
|
+
|
|
1045
|
+
const clearcoatColor = new Color(
|
|
1046
|
+
material.clearcoat,
|
|
1047
|
+
material.clearcoat,
|
|
1048
|
+
material.clearcoat
|
|
1049
|
+
);
|
|
1050
|
+
const textureNodes = buildTextureNodes(
|
|
1051
|
+
material.clearcoatMap,
|
|
1052
|
+
'clearcoat',
|
|
1053
|
+
clearcoatColor
|
|
1054
|
+
);
|
|
1055
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
716
1056
|
|
|
717
1057
|
} else {
|
|
718
1058
|
|
|
719
|
-
|
|
1059
|
+
previewSurfaceNode.addProperty(
|
|
1060
|
+
`float inputs:clearcoat = ${material.clearcoat}`
|
|
1061
|
+
);
|
|
720
1062
|
|
|
721
1063
|
}
|
|
722
1064
|
|
|
723
1065
|
if ( material.clearcoatRoughnessMap !== null ) {
|
|
724
1066
|
|
|
725
|
-
|
|
726
|
-
|
|
1067
|
+
previewSurfaceNode.addProperty(
|
|
1068
|
+
`float inputs:clearcoatRoughness.connect = </Materials/Material_${material.id}/Texture_${material.clearcoatRoughnessMap.id}_clearcoatRoughness.outputs:g>`
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1071
|
+
const clearcoatRoughnessColor = new Color(
|
|
1072
|
+
material.clearcoatRoughness,
|
|
1073
|
+
material.clearcoatRoughness,
|
|
1074
|
+
material.clearcoatRoughness
|
|
1075
|
+
);
|
|
1076
|
+
const textureNodes = buildTextureNodes(
|
|
1077
|
+
material.clearcoatRoughnessMap,
|
|
1078
|
+
'clearcoatRoughness',
|
|
1079
|
+
clearcoatRoughnessColor
|
|
1080
|
+
);
|
|
1081
|
+
textureNodes.forEach( ( node ) => materialNode.addChild( node ) );
|
|
727
1082
|
|
|
728
1083
|
} else {
|
|
729
1084
|
|
|
730
|
-
|
|
1085
|
+
previewSurfaceNode.addProperty(
|
|
1086
|
+
`float inputs:clearcoatRoughness = ${material.clearcoatRoughness}`
|
|
1087
|
+
);
|
|
731
1088
|
|
|
732
1089
|
}
|
|
733
1090
|
|
|
734
|
-
|
|
1091
|
+
previewSurfaceNode.addProperty( `float inputs:ior = ${material.ior}` );
|
|
735
1092
|
|
|
736
1093
|
}
|
|
737
1094
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
{
|
|
741
|
-
def Shader "PreviewSurface"
|
|
742
|
-
{
|
|
743
|
-
uniform token info:id = "UsdPreviewSurface"
|
|
744
|
-
${ inputs.join( '\n' ) }
|
|
745
|
-
int inputs:useSpecularWorkflow = 0
|
|
746
|
-
token outputs:surface
|
|
747
|
-
}
|
|
1095
|
+
previewSurfaceNode.addProperty( 'int inputs:useSpecularWorkflow = 0' );
|
|
1096
|
+
previewSurfaceNode.addProperty( 'token outputs:surface' );
|
|
748
1097
|
|
|
749
|
-
|
|
1098
|
+
materialNode.addChild( previewSurfaceNode );
|
|
750
1099
|
|
|
751
|
-
|
|
1100
|
+
materialNode.addProperty(
|
|
1101
|
+
`token outputs:surface.connect = </Materials/Material_${material.id}/PreviewSurface.outputs:surface>`
|
|
1102
|
+
);
|
|
752
1103
|
|
|
753
|
-
|
|
754
|
-
`;
|
|
1104
|
+
return materialNode;
|
|
755
1105
|
|
|
756
1106
|
}
|
|
757
1107
|
|
|
758
1108
|
function buildColor( color ) {
|
|
759
1109
|
|
|
760
|
-
return `(${
|
|
1110
|
+
return `(${color.r}, ${color.g}, ${color.b})`;
|
|
761
1111
|
|
|
762
1112
|
}
|
|
763
1113
|
|
|
764
1114
|
function buildColor4( color ) {
|
|
765
1115
|
|
|
766
|
-
return `(${
|
|
1116
|
+
return `(${color.r}, ${color.g}, ${color.b}, 1.0)`;
|
|
767
1117
|
|
|
768
1118
|
}
|
|
769
1119
|
|
|
770
1120
|
function buildVector2( vector ) {
|
|
771
1121
|
|
|
772
|
-
return `(${
|
|
1122
|
+
return `(${vector.x}, ${vector.y})`;
|
|
773
1123
|
|
|
774
1124
|
}
|
|
775
1125
|
|
|
1126
|
+
function buildCamera( camera, usedNames ) {
|
|
776
1127
|
|
|
777
|
-
|
|
1128
|
+
const name = getName( camera, usedNames );
|
|
778
1129
|
|
|
779
|
-
const
|
|
1130
|
+
const transform = buildMatrix( camera.matrix );
|
|
780
1131
|
|
|
781
|
-
|
|
1132
|
+
if ( camera.matrix.determinant() < 0 ) {
|
|
782
1133
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
1134
|
+
console.warn(
|
|
1135
|
+
'THREE.USDZExporter: USDZ does not support negative scales',
|
|
1136
|
+
camera
|
|
1137
|
+
);
|
|
786
1138
|
|
|
787
1139
|
}
|
|
788
1140
|
|
|
1141
|
+
const node = new USDNode( name, 'Camera' );
|
|
1142
|
+
node.addProperty( `matrix4d xformOp:transform = ${transform}` );
|
|
1143
|
+
node.addProperty( 'uniform token[] xformOpOrder = ["xformOp:transform"]' );
|
|
1144
|
+
|
|
1145
|
+
const projection = camera.isOrthographicCamera
|
|
1146
|
+
? 'orthographic'
|
|
1147
|
+
: 'perspective';
|
|
1148
|
+
node.addProperty( `token projection = "${projection}"` );
|
|
1149
|
+
|
|
1150
|
+
const clippingRange = `(${camera.near.toPrecision(
|
|
1151
|
+
PRECISION
|
|
1152
|
+
)}, ${camera.far.toPrecision( PRECISION )})`;
|
|
1153
|
+
node.addProperty( `float2 clippingRange = ${clippingRange}` );
|
|
1154
|
+
|
|
1155
|
+
let horizontalAperture;
|
|
789
1156
|
if ( camera.isOrthographicCamera ) {
|
|
790
1157
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1158
|
+
horizontalAperture = (
|
|
1159
|
+
( Math.abs( camera.left ) + Math.abs( camera.right ) ) *
|
|
1160
|
+
10
|
|
1161
|
+
).toPrecision( PRECISION );
|
|
795
1162
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1163
|
+
} else {
|
|
1164
|
+
|
|
1165
|
+
horizontalAperture = camera.getFilmWidth().toPrecision( PRECISION );
|
|
1166
|
+
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
node.addProperty( `float horizontalAperture = ${horizontalAperture}` );
|
|
1170
|
+
|
|
1171
|
+
let verticalAperture;
|
|
1172
|
+
if ( camera.isOrthographicCamera ) {
|
|
801
1173
|
|
|
802
|
-
|
|
1174
|
+
verticalAperture = (
|
|
1175
|
+
( Math.abs( camera.top ) + Math.abs( camera.bottom ) ) *
|
|
1176
|
+
10
|
|
1177
|
+
).toPrecision( PRECISION );
|
|
803
1178
|
|
|
804
1179
|
} else {
|
|
805
1180
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
float2 clippingRange = (${ camera.near.toPrecision( PRECISION ) }, ${ camera.far.toPrecision( PRECISION ) })
|
|
812
|
-
float focalLength = ${ camera.getFocalLength().toPrecision( PRECISION ) }
|
|
813
|
-
float focusDistance = ${ camera.focus.toPrecision( PRECISION ) }
|
|
814
|
-
float horizontalAperture = ${ camera.getFilmWidth().toPrecision( PRECISION ) }
|
|
815
|
-
token projection = "perspective"
|
|
816
|
-
float verticalAperture = ${ camera.getFilmHeight().toPrecision( PRECISION ) }
|
|
817
|
-
}
|
|
1181
|
+
verticalAperture = camera.getFilmHeight().toPrecision( PRECISION );
|
|
1182
|
+
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
node.addProperty( `float verticalAperture = ${verticalAperture}` );
|
|
818
1186
|
|
|
819
|
-
|
|
1187
|
+
if ( camera.isPerspectiveCamera ) {
|
|
1188
|
+
|
|
1189
|
+
const focalLength = camera.getFocalLength().toPrecision( PRECISION );
|
|
1190
|
+
node.addProperty( `float focalLength = ${focalLength}` );
|
|
1191
|
+
|
|
1192
|
+
const focusDistance = camera.focus.toPrecision( PRECISION );
|
|
1193
|
+
node.addProperty( `float focusDistance = ${focusDistance}` );
|
|
820
1194
|
|
|
821
1195
|
}
|
|
822
1196
|
|
|
1197
|
+
return node;
|
|
1198
|
+
|
|
823
1199
|
}
|
|
824
1200
|
|
|
825
1201
|
/**
|
|
@@ -828,6 +1204,7 @@ function buildCamera( camera ) {
|
|
|
828
1204
|
* @typedef {Object} USDZExporter~Options
|
|
829
1205
|
* @property {number} [maxTextureSize=1024] - The maximum texture size that is going to be exported.
|
|
830
1206
|
* @property {boolean} [includeAnchoringProperties=true] - Whether to include anchoring properties or not.
|
|
1207
|
+
* @property {boolean} [onlyVisible=true] - Export only visible 3D objects.
|
|
831
1208
|
* @property {Object} [ar] - If `includeAnchoringProperties` is set to `true`, the anchoring type and alignment
|
|
832
1209
|
* can be configured via `ar.anchoring.type` and `ar.planeAnchoring.alignment`.
|
|
833
1210
|
* @property {boolean} [quickLookCompatible=false] - Whether to make the exported USDZ compatible to QuickLook
|