(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "../libs/fflate.module.js"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("../libs/fflate.module.js")); } else { var mod = { exports: {} }; factory(mod.exports, global.fflateModule); global.USDZExporter = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, fflate) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.USDZExporter = void 0; fflate = _interopRequireWildcard(fflate); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } var USDZExporter = /*#__PURE__*/function () { function USDZExporter() { _classCallCheck(this, USDZExporter); } _createClass(USDZExporter, [{ key: "parse", value: function () { var _parse = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(scene) { var files, modelFileName, output, materials, textures, _loop, id, offset, filename, file, headerSize, offsetMod64, padLength, padding; return regeneratorRuntime.wrap(function _callee$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: files = {}; modelFileName = 'model.usda'; // model file should be first in USDZ archive so we init it here files[modelFileName] = null; output = buildHeader(); materials = {}; textures = {}; scene.traverseVisible(function (object) { if (object.isMesh) { if (object.material.isMeshStandardMaterial) { var geometry = object.geometry; var material = object.material; var geometryFileName = 'geometries/Geometry_' + geometry.id + '.usd'; if (!(geometryFileName in files)) { var meshObject = buildMeshObject(geometry); files[geometryFileName] = buildUSDFileAsString(meshObject); } if (!(material.uuid in materials)) { materials[material.uuid] = material; } output += buildXform(object, geometry, material); } else { console.warn('THREE.USDZExporter: Unsupported material type (USDZ only supports MeshStandardMaterial)', object); } } }); output += buildMaterials(materials, textures); files[modelFileName] = fflate.strToU8(output); output = null; _loop = /*#__PURE__*/regeneratorRuntime.mark(function _loop(id) { var texture, color, isRGBA, canvas, blob; return regeneratorRuntime.wrap(function _loop$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: texture = textures[id]; color = id.split('_')[1]; isRGBA = texture.format === 1023; canvas = imageToCanvas(texture.image, color); _context.next = 6; return new Promise(function (resolve) { return canvas.toBlob(resolve, isRGBA ? 'image/png' : 'image/jpeg', 1); }); case 6: blob = _context.sent; _context.t0 = Uint8Array; _context.next = 10; return blob.arrayBuffer(); case 10: _context.t1 = _context.sent; files["textures/Texture_".concat(id, ".").concat(isRGBA ? 'png' : 'jpg')] = new _context.t0(_context.t1); case 12: case "end": return _context.stop(); } } }, _loop); }); _context2.t0 = regeneratorRuntime.keys(textures); case 12: if ((_context2.t1 = _context2.t0()).done) { _context2.next = 17; break; } id = _context2.t1.value; return _context2.delegateYield(_loop(id), "t2", 15); case 15: _context2.next = 12; break; case 17: // 64 byte alignment // https://github.com/101arrowz/fflate/issues/39#issuecomment-777263109 offset = 0; for (filename in files) { file = files[filename]; headerSize = 34 + filename.length; offset += headerSize; offsetMod64 = offset & 63; if (offsetMod64 !== 4) { padLength = 64 - offsetMod64; padding = new Uint8Array(padLength); files[filename] = [file, { extra: { 12345: padding } }]; } offset = file.length; } return _context2.abrupt("return", fflate.zipSync(files, { level: 0 })); case 20: case "end": return _context2.stop(); } } }, _callee); })); function parse(_x) { return _parse.apply(this, arguments); } return parse; }() }]); return USDZExporter; }(); _exports.USDZExporter = USDZExporter; function imageToCanvas(image, color) { if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) { var scale = 1024 / Math.max(image.width, image.height); var canvas = document.createElement('canvas'); canvas.width = image.width * Math.min(1, scale); canvas.height = image.height * Math.min(1, scale); var context = canvas.getContext('2d'); context.drawImage(image, 0, 0, canvas.width, canvas.height); if (color !== undefined) { var hex = parseInt(color, 16); var r = (hex >> 16 & 255) / 255; var g = (hex >> 8 & 255) / 255; var b = (hex & 255) / 255; var imagedata = context.getImageData(0, 0, canvas.width, canvas.height); var data = imagedata.data; for (var i = 0; i < data.length; i += 4) { data[i + 0] = data[i + 0] * r; data[i + 1] = data[i + 1] * g; data[i + 2] = data[i + 2] * b; } context.putImageData(imagedata, 0, 0); } return canvas; } } // var PRECISION = 7; function buildHeader() { return "#usda 1.0\n(\n customLayerData = {\n string creator = \"Three.js USDZExporter\"\n }\n metersPerUnit = 1\n upAxis = \"Y\"\n)\n\n"; } function buildUSDFileAsString(dataToInsert) { var output = buildHeader(); output += dataToInsert; return fflate.strToU8(output); } // Xform function buildXform(object, geometry, material) { var name = 'Object_' + object.id; var transform = buildMatrix(object.matrixWorld); if (object.matrixWorld.determinant() < 0) { console.warn('THREE.USDZExporter: USDZ does not support negative scales', object); } return "def Xform \"".concat(name, "\" (\n prepend references = @./geometries/Geometry_").concat(geometry.id, ".usd@\n)\n{\n matrix4d xformOp:transform = ").concat(transform, "\n uniform token[] xformOpOrder = [\"xformOp:transform\"]\n\n rel material:binding = \n}\n\n"); } function buildMatrix(matrix) { var array = matrix.elements; return "( ".concat(buildMatrixRow(array, 0), ", ").concat(buildMatrixRow(array, 4), ", ").concat(buildMatrixRow(array, 8), ", ").concat(buildMatrixRow(array, 12), " )"); } function buildMatrixRow(array, offset) { return "(".concat(array[offset + 0], ", ").concat(array[offset + 1], ", ").concat(array[offset + 2], ", ").concat(array[offset + 3], ")"); } // Mesh function buildMeshObject(geometry) { var mesh = buildMesh(geometry); return "\ndef \"Geometry\"\n{\n ".concat(mesh, "\n}\n"); } function buildMesh(geometry) { var name = 'Geometry'; var attributes = geometry.attributes; var count = attributes.position.count; return "\n def Mesh \"".concat(name, "\"\n {\n int[] faceVertexCounts = [").concat(buildMeshVertexCount(geometry), "]\n int[] faceVertexIndices = [").concat(buildMeshVertexIndices(geometry), "]\n normal3f[] normals = [").concat(buildVector3Array(attributes.normal, count), "] (\n interpolation = \"vertex\"\n )\n point3f[] points = [").concat(buildVector3Array(attributes.position, count), "]\n float2[] primvars:st = [").concat(buildVector2Array(attributes.uv, count), "] (\n interpolation = \"vertex\"\n )\n uniform token subdivisionScheme = \"none\"\n }\n"); } function buildMeshVertexCount(geometry) { var count = geometry.index !== null ? geometry.index.count : geometry.attributes.position.count; return Array(count / 3).fill(3).join(', '); } function buildMeshVertexIndices(geometry) { var index = geometry.index; var array = []; if (index !== null) { for (var i = 0; i < index.count; i++) { array.push(index.getX(i)); } } else { var length = geometry.attributes.position.count; for (var _i = 0; _i < length; _i++) { array.push(_i); } } return array.join(', '); } function buildVector3Array(attribute, count) { if (attribute === undefined) { console.warn('USDZExporter: Normals missing.'); return Array(count).fill('(0, 0, 0)').join(', '); } var array = []; for (var i = 0; i < attribute.count; i++) { var x = attribute.getX(i); var y = attribute.getY(i); var z = attribute.getZ(i); array.push("(".concat(x.toPrecision(PRECISION), ", ").concat(y.toPrecision(PRECISION), ", ").concat(z.toPrecision(PRECISION), ")")); } return array.join(', '); } function buildVector2Array(attribute, count) { if (attribute === undefined) { console.warn('USDZExporter: UVs missing.'); return Array(count).fill('(0, 0)').join(', '); } var array = []; for (var i = 0; i < attribute.count; i++) { var x = attribute.getX(i); var y = attribute.getY(i); array.push("(".concat(x.toPrecision(PRECISION), ", ").concat(1 - y.toPrecision(PRECISION), ")")); } return array.join(', '); } // Materials function buildMaterials(materials, textures) { var array = []; for (var uuid in materials) { var material = materials[uuid]; array.push(buildMaterial(material, textures)); } return "def \"Materials\"\n{\n".concat(array.join(''), "\n}\n\n"); } function buildMaterial(material, textures) { // https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html var pad = ' '; var inputs = []; var samplers = []; function buildTexture(texture, mapType, color) { var id = texture.id + (color ? '_' + color.getHexString() : ''); var isRGBA = texture.format === 1023; textures[id] = texture; return "\n def Shader \"Transform2d_".concat(mapType, "\" (\n sdrMetadata = {\n string role = \"math\"\n }\n )\n {\n uniform token info:id = \"UsdTransform2d\"\n float2 inputs:in.connect = \n float2 inputs:scale = ").concat(buildVector2(texture.repeat), "\n float2 inputs:translation = ").concat(buildVector2(texture.offset), "\n float2 outputs:result\n }\n\n def Shader \"Texture_").concat(texture.id, "_").concat(mapType, "\"\n {\n uniform token info:id = \"UsdUVTexture\"\n asset inputs:file = @textures/Texture_").concat(id, ".").concat(isRGBA ? 'png' : 'jpg', "@\n float2 inputs:st.connect = \n token inputs:wrapS = \"repeat\"\n token inputs:wrapT = \"repeat\"\n float outputs:r\n float outputs:g\n float outputs:b\n float3 outputs:rgb\n }"); } if (material.map !== null) { inputs.push("".concat(pad, "color3f inputs:diffuseColor.connect = ")); samplers.push(buildTexture(material.map, 'diffuse', material.color)); } else { inputs.push("".concat(pad, "color3f inputs:diffuseColor = ").concat(buildColor(material.color))); } if (material.emissiveMap !== null) { inputs.push("".concat(pad, "color3f inputs:emissiveColor.connect = ")); samplers.push(buildTexture(material.emissiveMap, 'emissive')); } else if (material.emissive.getHex() > 0) { inputs.push("".concat(pad, "color3f inputs:emissiveColor = ").concat(buildColor(material.emissive))); } if (material.normalMap !== null) { inputs.push("".concat(pad, "normal3f inputs:normal.connect = ")); samplers.push(buildTexture(material.normalMap, 'normal')); } if (material.aoMap !== null) { inputs.push("".concat(pad, "float inputs:occlusion.connect = ")); samplers.push(buildTexture(material.aoMap, 'occlusion')); } if (material.roughnessMap !== null && material.roughness === 1) { inputs.push("".concat(pad, "float inputs:roughness.connect = ")); samplers.push(buildTexture(material.roughnessMap, 'roughness')); } else { inputs.push("".concat(pad, "float inputs:roughness = ").concat(material.roughness)); } if (material.metalnessMap !== null && material.metalness === 1) { inputs.push("".concat(pad, "float inputs:metallic.connect = ")); samplers.push(buildTexture(material.metalnessMap, 'metallic')); } else { inputs.push("".concat(pad, "float inputs:metallic = ").concat(material.metalness)); } if (material.alphaMap !== null) { inputs.push("".concat(pad, "float inputs:opacity.connect = ")); inputs.push("".concat(pad, "float inputs:opacityThreshold = 0.0001")); samplers.push(buildTexture(material.alphaMap, 'opacity')); } else { inputs.push("".concat(pad, "float inputs:opacity = ").concat(material.opacity)); } if (material.isMeshPhysicalMaterial) { inputs.push("".concat(pad, "float inputs:clearcoat = ").concat(material.clearcoat)); inputs.push("".concat(pad, "float inputs:clearcoatRoughness = ").concat(material.clearcoatRoughness)); inputs.push("".concat(pad, "float inputs:ior = ").concat(material.ior)); } return "\n def Material \"Material_".concat(material.id, "\"\n {\n def Shader \"PreviewSurface\"\n {\n uniform token info:id = \"UsdPreviewSurface\"\n").concat(inputs.join('\n'), "\n int inputs:useSpecularWorkflow = 0\n token outputs:surface\n }\n\n token outputs:surface.connect = \n token inputs:frame:stPrimvarName = \"st\"\n\n def Shader \"uvReader_st\"\n {\n uniform token info:id = \"UsdPrimvarReader_float2\"\n token inputs:varname.connect = \n float2 inputs:fallback = (0.0, 0.0)\n float2 outputs:result\n }\n\n").concat(samplers.join('\n'), "\n\n }\n"); } function buildColor(color) { return "(".concat(color.r, ", ").concat(color.g, ", ").concat(color.b, ")"); } function buildVector2(vector) { return "(".concat(vector.x, ", ").concat(vector.y, ")"); } });