diff --git a/examples/js/exporters/USDZExporter.js b/examples/js/exporters/USDZExporter.js index ea6434a8e5c5f25596c74612c9e8eb8be771f62f..1d00d88b3015d3bdf1adc97a2eb5e4f9beb4745f 100644 --- a/examples/js/exporters/USDZExporter.js +++ b/examples/js/exporters/USDZExporter.js @@ -4,7 +4,11 @@ async parse( scene ) { + const files = {}; + const modelFileName = 'model.usda'; + const geometryFileName = 'geometry.usd'; let output = buildHeader(); + const geometries = {}; const materials = {}; const textures = {}; scene.traverse( object => { @@ -13,23 +17,37 @@ const geometry = object.geometry; const material = object.material; - materials[ material.uuid ] = material; - if ( material.map !== null ) textures[ material.map.uuid ] = material.map; - if ( material.normalMap !== null ) textures[ material.normalMap.uuid ] = material.normalMap; - if ( material.aoMap !== null ) textures[ material.aoMap.uuid ] = material.aoMap; - if ( material.roughnessMap !== null ) textures[ material.roughnessMap.uuid ] = material.roughnessMap; - if ( material.metalnessMap !== null ) textures[ material.metalnessMap.uuid ] = material.metalnessMap; - if ( material.emissiveMap !== null ) textures[ material.emissiveMap.uuid ] = material.emissiveMap; - output += buildXform( object, buildMesh( geometry, material ) ); + + if ( ! ( geometry.uuid in geometries ) ) { + + geometries[ geometry.uuid ] = geometry; + + } + + if ( ! ( material.uuid in materials ) ) { + + materials[ material.uuid ] = material; + if ( material.map !== null ) textures[ material.map.uuid ] = material.map; + if ( material.normalMap !== null ) textures[ material.normalMap.uuid ] = material.normalMap; + if ( material.aoMap !== null ) textures[ material.aoMap.uuid ] = material.aoMap; + if ( material.roughnessMap !== null ) textures[ material.roughnessMap.uuid ] = material.roughnessMap; + if ( material.metalnessMap !== null ) textures[ material.metalnessMap.uuid ] = material.metalnessMap; + if ( material.emissiveMap !== null ) textures[ material.emissiveMap.uuid ] = material.emissiveMap; + + } + + const referencedMesh = `prepend references = @./${geometryFileName}@`; + const referencedMaterial = `rel material:binding = `; + output += buildXform( object, referencedMesh, referencedMaterial ); } } ); output += buildMaterials( materials ); output += buildTextures( textures ); - const files = { - 'model.usda': fflate.strToU8( output ) - }; + files[ modelFileName ] = fflate.strToU8( output ); + output = null; + files[ geometryFileName ] = fflate.strToU8( buildMeshFileString( geometries ) ); for ( const uuid in textures ) { @@ -109,16 +127,19 @@ } // Xform - function buildXform( object, define ) { + function buildXform( object, referencedMesh, referencedMaterial ) { const name = 'Object_' + object.id; const transform = buildMatrix( object.matrixWorld ); return `def Xform "${name}" +( + ${referencedMesh} +) { matrix4d xformOp:transform = ${transform} uniform token[] xformOpOrder = ["xformOp:transform"] - ${define} + ${referencedMaterial} } `; @@ -139,7 +160,35 @@ } // Mesh - function buildMesh( geometry, material ) { + function buildMeshFileString( geometries ) { + + let output = buildHeader(); + + for ( const uuid in geometries ) { + + const geometry = geometries[ uuid ]; + output += buildMeshObject( geometry ); + + } + + return output; + + } + + function buildMeshObject( geometry ) { + + const name = 'Geometry_' + geometry.id; + const mesh = buildMesh( geometry ); + return ` +def "${name}" +{ + ${mesh} +} +`; + + } + + function buildMesh( geometry ) { const name = 'Geometry_' + geometry.id; const attributes = geometry.attributes; @@ -151,11 +200,11 @@ } - return `def Mesh "${name}" + return ` + def Mesh "${name}" { int[] faceVertexCounts = [${buildMeshVertexCount( geometry )}] int[] faceVertexIndices = [${buildMeshVertexIndices( geometry )}] - rel material:binding = normal3f[] normals = [${buildVector3Array( attributes.normal, count )}] ( interpolation = "vertex" ) diff --git a/examples/jsm/exporters/USDZExporter.js b/examples/jsm/exporters/USDZExporter.js index db0f51190d864e75f9b4cf9788feca1d3867444c..9c34de9081be260075294897b74d94173961f1b8 100644 --- a/examples/jsm/exporters/USDZExporter.js +++ b/examples/jsm/exporters/USDZExporter.js @@ -4,8 +4,13 @@ class USDZExporter { async parse( scene ) { + const files = {}; + const modelFileName = 'model.usda'; + const geometryFileName = 'geometry.usd'; + let output = buildHeader(); + const geometries = {}; const materials = {}; const textures = {}; @@ -16,16 +21,27 @@ class USDZExporter { const geometry = object.geometry; const material = object.material; - materials[ material.uuid ] = material; + if ( ! ( geometry.uuid in geometries ) ) { + + geometries[ geometry.uuid ] = geometry; + + } + + if ( ! ( material.uuid in materials ) ) { - if ( material.map !== null ) textures[ material.map.uuid ] = material.map; - if ( material.normalMap !== null ) textures[ material.normalMap.uuid ] = material.normalMap; - if ( material.aoMap !== null ) textures[ material.aoMap.uuid ] = material.aoMap; - if ( material.roughnessMap !== null ) textures[ material.roughnessMap.uuid ] = material.roughnessMap; - if ( material.metalnessMap !== null ) textures[ material.metalnessMap.uuid ] = material.metalnessMap; - if ( material.emissiveMap !== null ) textures[ material.emissiveMap.uuid ] = material.emissiveMap; + materials[ material.uuid ] = material; + if ( material.map !== null ) textures[ material.map.uuid ] = material.map; + if ( material.normalMap !== null ) textures[ material.normalMap.uuid ] = material.normalMap; + if ( material.aoMap !== null ) textures[ material.aoMap.uuid ] = material.aoMap; + if ( material.roughnessMap !== null ) textures[ material.roughnessMap.uuid ] = material.roughnessMap; + if ( material.metalnessMap !== null ) textures[ material.metalnessMap.uuid ] = material.metalnessMap; + if ( material.emissiveMap !== null ) textures[ material.emissiveMap.uuid ] = material.emissiveMap; - output += buildXform( object, buildMesh( geometry, material ) ); + } + + const referencedMesh = `prepend references = @./${geometryFileName}@`; + const referencedMaterial = `rel material:binding = `; + output += buildXform( object, referencedMesh, referencedMaterial ); } @@ -34,7 +50,10 @@ class USDZExporter { output += buildMaterials( materials ); output += buildTextures( textures ); - const files = { 'model.usda': fflate.strToU8( output ) }; + files[ modelFileName ] = fflate.strToU8( output ); + output = null; + + files[ geometryFileName ] = fflate.strToU8( buildMeshFileString( geometries ) ); for ( const uuid in textures ) { @@ -120,17 +139,20 @@ function buildHeader() { // Xform -function buildXform( object, define ) { +function buildXform( object, referencedMesh, referencedMaterial ) { const name = 'Object_' + object.id; const transform = buildMatrix( object.matrixWorld ); return `def Xform "${ name }" +( + ${ referencedMesh } +) { matrix4d xformOp:transform = ${ transform } uniform token[] xformOpOrder = ["xformOp:transform"] - ${ define } + ${ referencedMaterial } } `; @@ -153,7 +175,35 @@ function buildMatrixRow( array, offset ) { // Mesh -function buildMesh( geometry, material ) { +function buildMeshFileString( geometries ) { + + let output = buildHeader(); + + for ( const uuid in geometries ) { + + const geometry = geometries[ uuid ]; + output += buildMeshObject( geometry ); + + } + + return output; + +} + +function buildMeshObject( geometry ) { + + const name = 'Geometry_' + geometry.id; + const mesh = buildMesh( geometry ); + return ` +def "${name}" +{ + ${mesh} +} +`; + +} + +function buildMesh( geometry ) { const name = 'Geometry_' + geometry.id; const attributes = geometry.attributes; @@ -165,11 +215,11 @@ function buildMesh( geometry, material ) { } - return `def Mesh "${ name }" + return ` + def Mesh "${ name }" { int[] faceVertexCounts = [${ buildMeshVertexCount( geometry ) }] int[] faceVertexIndices = [${ buildMeshVertexIndices( geometry ) }] - rel material:binding = normal3f[] normals = [${ buildVector3Array( attributes.normal, count )}] ( interpolation = "vertex" )