(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "three"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("three")); } else { var mod = { exports: {} }; factory(mod.exports, global.three); global.PLYExporter = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.PLYExporter = void 0; 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; } /** * https://github.com/gkjohnson/ply-exporter-js * * Usage: * const exporter = new PLYExporter(); * * // second argument is a list of options * exporter.parse(mesh, data => console.log(data), { binary: true, excludeAttributes: [ 'color' ], littleEndian: true }); * * Format Definition: * http://paulbourke.net/dataformats/ply/ */ var PLYExporter = /*#__PURE__*/function () { function PLYExporter() { _classCallCheck(this, PLYExporter); } _createClass(PLYExporter, [{ key: "parse", value: function parse(object, onDone, options) { if (onDone && typeof onDone === 'object') { console.warn('THREE.PLYExporter: The options parameter is now the third argument to the "parse" function. See the documentation for the new API.'); options = onDone; onDone = undefined; } // Iterate over the valid meshes in the object function traverseMeshes(cb) { object.traverse(function (child) { if (child.isMesh === true) { var mesh = child; var geometry = mesh.geometry; if (geometry.isBufferGeometry !== true) { throw new Error('THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.'); } if (geometry.hasAttribute('position') === true) { cb(mesh, geometry); } } }); } // Default options var defaultOptions = { binary: false, excludeAttributes: [], // normal, uv, color, index littleEndian: false }; options = Object.assign(defaultOptions, options); var excludeAttributes = options.excludeAttributes; var includeNormals = false; var includeColors = false; var includeUVs = false; // count the vertices, check which properties are used, // and cache the BufferGeometry var vertexCount = 0; var faceCount = 0; object.traverse(function (child) { if (child.isMesh === true) { var mesh = child; var geometry = mesh.geometry; if (geometry.isBufferGeometry !== true) { throw new Error('THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.'); } var vertices = geometry.getAttribute('position'); var normals = geometry.getAttribute('normal'); var uvs = geometry.getAttribute('uv'); var colors = geometry.getAttribute('color'); var indices = geometry.getIndex(); if (vertices === undefined) { return; } vertexCount += vertices.count; faceCount += indices ? indices.count / 3 : vertices.count / 3; if (normals !== undefined) includeNormals = true; if (uvs !== undefined) includeUVs = true; if (colors !== undefined) includeColors = true; } }); var includeIndices = excludeAttributes.indexOf('index') === -1; includeNormals = includeNormals && excludeAttributes.indexOf('normal') === -1; includeColors = includeColors && excludeAttributes.indexOf('color') === -1; includeUVs = includeUVs && excludeAttributes.indexOf('uv') === -1; if (includeIndices && faceCount !== Math.floor(faceCount)) { // point cloud meshes will not have an index array and may not have a // number of vertices that is divisble by 3 (and therefore representable // as triangles) console.error('PLYExporter: Failed to generate a valid PLY file with triangle indices because the ' + 'number of indices is not divisible by 3.'); return null; } var indexByteCount = 4; var header = 'ply\n' + "format ".concat(options.binary ? options.littleEndian ? 'binary_little_endian' : 'binary_big_endian' : 'ascii', " 1.0\n") + "element vertex ".concat(vertexCount, "\n") + // position 'property float x\n' + 'property float y\n' + 'property float z\n'; if (includeNormals === true) { // normal header += 'property float nx\n' + 'property float ny\n' + 'property float nz\n'; } if (includeUVs === true) { // uvs header += 'property float s\n' + 'property float t\n'; } if (includeColors === true) { // colors header += 'property uchar red\n' + 'property uchar green\n' + 'property uchar blue\n'; } if (includeIndices === true) { // faces header += "element face ".concat(faceCount, "\n") + 'property list uchar int vertex_index\n'; } header += 'end_header\n'; // Generate attribute data var vertex = new _three.Vector3(); var normalMatrixWorld = new _three.Matrix3(); var result = null; if (options.binary === true) { // Binary File Generation var headerBin = new TextEncoder().encode(header); // 3 position values at 4 bytes // 3 normal values at 4 bytes // 3 color channels with 1 byte // 2 uv values at 4 bytes var vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0)); // 1 byte shape desciptor // 3 vertex indices at ${indexByteCount} bytes var faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0; var output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength)); new Uint8Array(output.buffer).set(headerBin, 0); var vOffset = headerBin.length; var fOffset = headerBin.length + vertexListLength; var writtenVertices = 0; traverseMeshes(function (mesh, geometry) { var vertices = geometry.getAttribute('position'); var normals = geometry.getAttribute('normal'); var uvs = geometry.getAttribute('uv'); var colors = geometry.getAttribute('color'); var indices = geometry.getIndex(); normalMatrixWorld.getNormalMatrix(mesh.matrixWorld); for (var i = 0, l = vertices.count; i < l; i++) { vertex.x = vertices.getX(i); vertex.y = vertices.getY(i); vertex.z = vertices.getZ(i); vertex.applyMatrix4(mesh.matrixWorld); // Position information output.setFloat32(vOffset, vertex.x, options.littleEndian); vOffset += 4; output.setFloat32(vOffset, vertex.y, options.littleEndian); vOffset += 4; output.setFloat32(vOffset, vertex.z, options.littleEndian); vOffset += 4; // Normal information if (includeNormals === true) { if (normals != null) { vertex.x = normals.getX(i); vertex.y = normals.getY(i); vertex.z = normals.getZ(i); vertex.applyMatrix3(normalMatrixWorld).normalize(); output.setFloat32(vOffset, vertex.x, options.littleEndian); vOffset += 4; output.setFloat32(vOffset, vertex.y, options.littleEndian); vOffset += 4; output.setFloat32(vOffset, vertex.z, options.littleEndian); vOffset += 4; } else { output.setFloat32(vOffset, 0, options.littleEndian); vOffset += 4; output.setFloat32(vOffset, 0, options.littleEndian); vOffset += 4; output.setFloat32(vOffset, 0, options.littleEndian); vOffset += 4; } } // UV information if (includeUVs === true) { if (uvs != null) { output.setFloat32(vOffset, uvs.getX(i), options.littleEndian); vOffset += 4; output.setFloat32(vOffset, uvs.getY(i), options.littleEndian); vOffset += 4; } else if (includeUVs !== false) { output.setFloat32(vOffset, 0, options.littleEndian); vOffset += 4; output.setFloat32(vOffset, 0, options.littleEndian); vOffset += 4; } } // Color information if (includeColors === true) { if (colors != null) { output.setUint8(vOffset, Math.floor(colors.getX(i) * 255)); vOffset += 1; output.setUint8(vOffset, Math.floor(colors.getY(i) * 255)); vOffset += 1; output.setUint8(vOffset, Math.floor(colors.getZ(i) * 255)); vOffset += 1; } else { output.setUint8(vOffset, 255); vOffset += 1; output.setUint8(vOffset, 255); vOffset += 1; output.setUint8(vOffset, 255); vOffset += 1; } } } if (includeIndices === true) { // Create the face list if (indices !== null) { for (var _i = 0, _l = indices.count; _i < _l; _i += 3) { output.setUint8(fOffset, 3); fOffset += 1; output.setUint32(fOffset, indices.getX(_i + 0) + writtenVertices, options.littleEndian); fOffset += indexByteCount; output.setUint32(fOffset, indices.getX(_i + 1) + writtenVertices, options.littleEndian); fOffset += indexByteCount; output.setUint32(fOffset, indices.getX(_i + 2) + writtenVertices, options.littleEndian); fOffset += indexByteCount; } } else { for (var _i2 = 0, _l2 = vertices.count; _i2 < _l2; _i2 += 3) { output.setUint8(fOffset, 3); fOffset += 1; output.setUint32(fOffset, writtenVertices + _i2, options.littleEndian); fOffset += indexByteCount; output.setUint32(fOffset, writtenVertices + _i2 + 1, options.littleEndian); fOffset += indexByteCount; output.setUint32(fOffset, writtenVertices + _i2 + 2, options.littleEndian); fOffset += indexByteCount; } } } // Save the amount of verts we've already written so we can offset // the face index on the next mesh writtenVertices += vertices.count; }); result = output.buffer; } else { // Ascii File Generation // count the number of vertices var _writtenVertices = 0; var vertexList = ''; var faceList = ''; traverseMeshes(function (mesh, geometry) { var vertices = geometry.getAttribute('position'); var normals = geometry.getAttribute('normal'); var uvs = geometry.getAttribute('uv'); var colors = geometry.getAttribute('color'); var indices = geometry.getIndex(); normalMatrixWorld.getNormalMatrix(mesh.matrixWorld); // form each line for (var i = 0, l = vertices.count; i < l; i++) { vertex.x = vertices.getX(i); vertex.y = vertices.getY(i); vertex.z = vertices.getZ(i); vertex.applyMatrix4(mesh.matrixWorld); // Position information var line = vertex.x + ' ' + vertex.y + ' ' + vertex.z; // Normal information if (includeNormals === true) { if (normals != null) { vertex.x = normals.getX(i); vertex.y = normals.getY(i); vertex.z = normals.getZ(i); vertex.applyMatrix3(normalMatrixWorld).normalize(); line += ' ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z; } else { line += ' 0 0 0'; } } // UV information if (includeUVs === true) { if (uvs != null) { line += ' ' + uvs.getX(i) + ' ' + uvs.getY(i); } else if (includeUVs !== false) { line += ' 0 0'; } } // Color information if (includeColors === true) { if (colors != null) { line += ' ' + Math.floor(colors.getX(i) * 255) + ' ' + Math.floor(colors.getY(i) * 255) + ' ' + Math.floor(colors.getZ(i) * 255); } else { line += ' 255 255 255'; } } vertexList += line + '\n'; } // Create the face list if (includeIndices === true) { if (indices !== null) { for (var _i3 = 0, _l3 = indices.count; _i3 < _l3; _i3 += 3) { faceList += "3 ".concat(indices.getX(_i3 + 0) + _writtenVertices); faceList += " ".concat(indices.getX(_i3 + 1) + _writtenVertices); faceList += " ".concat(indices.getX(_i3 + 2) + _writtenVertices, "\n"); } } else { for (var _i4 = 0, _l4 = vertices.count; _i4 < _l4; _i4 += 3) { faceList += "3 ".concat(_writtenVertices + _i4, " ").concat(_writtenVertices + _i4 + 1, " ").concat(_writtenVertices + _i4 + 2, "\n"); } } faceCount += indices ? indices.count / 3 : vertices.count / 3; } _writtenVertices += vertices.count; }); result = "".concat(header).concat(vertexList).concat(includeIndices ? "".concat(faceList, "\n") : '\n'); } if (typeof onDone === 'function') requestAnimationFrame(function () { return onDone(result); }); return result; } }]); return PLYExporter; }(); _exports.PLYExporter = PLYExporter; });