Buckets:
| import { Loader, FileLoader, BufferGeometry, Float32BufferAttribute } from "three"; | |
| import { decodeText } from "../_polyfill/LoaderUtils.js"; | |
| class PLYLoader extends Loader { | |
| constructor(manager) { | |
| super(manager); | |
| this.propertyNameMapping = {}; | |
| } | |
| load(url, onLoad, onProgress, onError) { | |
| const scope = this; | |
| const loader = new FileLoader(this.manager); | |
| loader.setPath(this.path); | |
| loader.setResponseType("arraybuffer"); | |
| loader.setRequestHeader(this.requestHeader); | |
| loader.setWithCredentials(this.withCredentials); | |
| loader.load( | |
| url, | |
| function(text) { | |
| try { | |
| onLoad(scope.parse(text)); | |
| } catch (e) { | |
| if (onError) { | |
| onError(e); | |
| } else { | |
| console.error(e); | |
| } | |
| scope.manager.itemError(url); | |
| } | |
| }, | |
| onProgress, | |
| onError | |
| ); | |
| } | |
| setPropertyNameMapping(mapping) { | |
| this.propertyNameMapping = mapping; | |
| } | |
| parse(data) { | |
| function parseHeader(data2) { | |
| const patternHeader = /ply([\s\S]*)end_header\r?\n/; | |
| let headerText = ""; | |
| let headerLength = 0; | |
| const result = patternHeader.exec(data2); | |
| if (result !== null) { | |
| headerText = result[1]; | |
| headerLength = new Blob([result[0]]).size; | |
| } | |
| const header = { | |
| comments: [], | |
| elements: [], | |
| headerLength, | |
| objInfo: "" | |
| }; | |
| const lines = headerText.split("\n"); | |
| let currentElement; | |
| function make_ply_element_property(propertValues, propertyNameMapping) { | |
| const property = { type: propertValues[0] }; | |
| if (property.type === "list") { | |
| property.name = propertValues[3]; | |
| property.countType = propertValues[1]; | |
| property.itemType = propertValues[2]; | |
| } else { | |
| property.name = propertValues[1]; | |
| } | |
| if (property.name in propertyNameMapping) { | |
| property.name = propertyNameMapping[property.name]; | |
| } | |
| return property; | |
| } | |
| for (let i = 0; i < lines.length; i++) { | |
| let line = lines[i]; | |
| line = line.trim(); | |
| if (line === "") | |
| continue; | |
| const lineValues = line.split(/\s+/); | |
| const lineType = lineValues.shift(); | |
| line = lineValues.join(" "); | |
| switch (lineType) { | |
| case "format": | |
| header.format = lineValues[0]; | |
| header.version = lineValues[1]; | |
| break; | |
| case "comment": | |
| header.comments.push(line); | |
| break; | |
| case "element": | |
| if (currentElement !== void 0) { | |
| header.elements.push(currentElement); | |
| } | |
| currentElement = {}; | |
| currentElement.name = lineValues[0]; | |
| currentElement.count = parseInt(lineValues[1]); | |
| currentElement.properties = []; | |
| break; | |
| case "property": | |
| currentElement.properties.push(make_ply_element_property(lineValues, scope.propertyNameMapping)); | |
| break; | |
| case "obj_info": | |
| header.objInfo = line; | |
| break; | |
| default: | |
| console.log("unhandled", lineType, lineValues); | |
| } | |
| } | |
| if (currentElement !== void 0) { | |
| header.elements.push(currentElement); | |
| } | |
| return header; | |
| } | |
| function parseASCIINumber(n, type) { | |
| switch (type) { | |
| case "char": | |
| case "uchar": | |
| case "short": | |
| case "ushort": | |
| case "int": | |
| case "uint": | |
| case "int8": | |
| case "uint8": | |
| case "int16": | |
| case "uint16": | |
| case "int32": | |
| case "uint32": | |
| return parseInt(n); | |
| case "float": | |
| case "double": | |
| case "float32": | |
| case "float64": | |
| return parseFloat(n); | |
| } | |
| } | |
| function parseASCIIElement(properties, line) { | |
| const values = line.split(/\s+/); | |
| const element = {}; | |
| for (let i = 0; i < properties.length; i++) { | |
| if (properties[i].type === "list") { | |
| const list = []; | |
| const n = parseASCIINumber(values.shift(), properties[i].countType); | |
| for (let j = 0; j < n; j++) { | |
| list.push(parseASCIINumber(values.shift(), properties[i].itemType)); | |
| } | |
| element[properties[i].name] = list; | |
| } else { | |
| element[properties[i].name] = parseASCIINumber(values.shift(), properties[i].type); | |
| } | |
| } | |
| return element; | |
| } | |
| function parseASCII(data2, header) { | |
| const buffer = { | |
| indices: [], | |
| vertices: [], | |
| normals: [], | |
| uvs: [], | |
| faceVertexUvs: [], | |
| colors: [] | |
| }; | |
| let result; | |
| const patternBody = /end_header\s([\s\S]*)$/; | |
| let body = ""; | |
| if ((result = patternBody.exec(data2)) !== null) { | |
| body = result[1]; | |
| } | |
| const lines = body.split("\n"); | |
| let currentElement = 0; | |
| let currentElementCount = 0; | |
| for (let i = 0; i < lines.length; i++) { | |
| let line = lines[i]; | |
| line = line.trim(); | |
| if (line === "") { | |
| continue; | |
| } | |
| if (currentElementCount >= header.elements[currentElement].count) { | |
| currentElement++; | |
| currentElementCount = 0; | |
| } | |
| const element = parseASCIIElement(header.elements[currentElement].properties, line); | |
| handleElement(buffer, header.elements[currentElement].name, element); | |
| currentElementCount++; | |
| } | |
| return postProcess(buffer); | |
| } | |
| function postProcess(buffer) { | |
| let geometry2 = new BufferGeometry(); | |
| if (buffer.indices.length > 0) { | |
| geometry2.setIndex(buffer.indices); | |
| } | |
| geometry2.setAttribute("position", new Float32BufferAttribute(buffer.vertices, 3)); | |
| if (buffer.normals.length > 0) { | |
| geometry2.setAttribute("normal", new Float32BufferAttribute(buffer.normals, 3)); | |
| } | |
| if (buffer.uvs.length > 0) { | |
| geometry2.setAttribute("uv", new Float32BufferAttribute(buffer.uvs, 2)); | |
| } | |
| if (buffer.colors.length > 0) { | |
| geometry2.setAttribute("color", new Float32BufferAttribute(buffer.colors, 3)); | |
| } | |
| if (buffer.faceVertexUvs.length > 0) { | |
| geometry2 = geometry2.toNonIndexed(); | |
| geometry2.setAttribute("uv", new Float32BufferAttribute(buffer.faceVertexUvs, 2)); | |
| } | |
| geometry2.computeBoundingSphere(); | |
| return geometry2; | |
| } | |
| function handleElement(buffer, elementName, element) { | |
| if (elementName === "vertex") { | |
| buffer.vertices.push(element.x, element.y, element.z); | |
| if ("nx" in element && "ny" in element && "nz" in element) { | |
| buffer.normals.push(element.nx, element.ny, element.nz); | |
| } | |
| if ("s" in element && "t" in element) { | |
| buffer.uvs.push(element.s, element.t); | |
| } | |
| if ("red" in element && "green" in element && "blue" in element) { | |
| buffer.colors.push(element.red / 255, element.green / 255, element.blue / 255); | |
| } | |
| } else if (elementName === "face") { | |
| const vertex_indices = element.vertex_indices || element.vertex_index; | |
| const texcoord = element.texcoord; | |
| if (vertex_indices.length === 3) { | |
| buffer.indices.push(vertex_indices[0], vertex_indices[1], vertex_indices[2]); | |
| if (texcoord && texcoord.length === 6) { | |
| buffer.faceVertexUvs.push(texcoord[0], texcoord[1]); | |
| buffer.faceVertexUvs.push(texcoord[2], texcoord[3]); | |
| buffer.faceVertexUvs.push(texcoord[4], texcoord[5]); | |
| } | |
| } else if (vertex_indices.length === 4) { | |
| buffer.indices.push(vertex_indices[0], vertex_indices[1], vertex_indices[3]); | |
| buffer.indices.push(vertex_indices[1], vertex_indices[2], vertex_indices[3]); | |
| } | |
| } | |
| } | |
| function binaryRead(dataview, at, type, little_endian) { | |
| switch (type) { | |
| case "int8": | |
| case "char": | |
| return [dataview.getInt8(at), 1]; | |
| case "uint8": | |
| case "uchar": | |
| return [dataview.getUint8(at), 1]; | |
| case "int16": | |
| case "short": | |
| return [dataview.getInt16(at, little_endian), 2]; | |
| case "uint16": | |
| case "ushort": | |
| return [dataview.getUint16(at, little_endian), 2]; | |
| case "int32": | |
| case "int": | |
| return [dataview.getInt32(at, little_endian), 4]; | |
| case "uint32": | |
| case "uint": | |
| return [dataview.getUint32(at, little_endian), 4]; | |
| case "float32": | |
| case "float": | |
| return [dataview.getFloat32(at, little_endian), 4]; | |
| case "float64": | |
| case "double": | |
| return [dataview.getFloat64(at, little_endian), 8]; | |
| } | |
| } | |
| function binaryReadElement(dataview, at, properties, little_endian) { | |
| const element = {}; | |
| let result, read = 0; | |
| for (let i = 0; i < properties.length; i++) { | |
| if (properties[i].type === "list") { | |
| const list = []; | |
| result = binaryRead(dataview, at + read, properties[i].countType, little_endian); | |
| const n = result[0]; | |
| read += result[1]; | |
| for (let j = 0; j < n; j++) { | |
| result = binaryRead(dataview, at + read, properties[i].itemType, little_endian); | |
| list.push(result[0]); | |
| read += result[1]; | |
| } | |
| element[properties[i].name] = list; | |
| } else { | |
| result = binaryRead(dataview, at + read, properties[i].type, little_endian); | |
| element[properties[i].name] = result[0]; | |
| read += result[1]; | |
| } | |
| } | |
| return [element, read]; | |
| } | |
| function parseBinary(data2, header) { | |
| const buffer = { | |
| indices: [], | |
| vertices: [], | |
| normals: [], | |
| uvs: [], | |
| faceVertexUvs: [], | |
| colors: [] | |
| }; | |
| const little_endian = header.format === "binary_little_endian"; | |
| const body = new DataView(data2, header.headerLength); | |
| let result, loc = 0; | |
| for (let currentElement = 0; currentElement < header.elements.length; currentElement++) { | |
| for (let currentElementCount = 0; currentElementCount < header.elements[currentElement].count; currentElementCount++) { | |
| result = binaryReadElement(body, loc, header.elements[currentElement].properties, little_endian); | |
| loc += result[1]; | |
| const element = result[0]; | |
| handleElement(buffer, header.elements[currentElement].name, element); | |
| } | |
| } | |
| return postProcess(buffer); | |
| } | |
| let geometry; | |
| const scope = this; | |
| if (data instanceof ArrayBuffer) { | |
| const text = decodeText(new Uint8Array(data)); | |
| const header = parseHeader(text); | |
| geometry = header.format === "ascii" ? parseASCII(text, header) : parseBinary(data, header); | |
| } else { | |
| geometry = parseASCII(data, parseHeader(data)); | |
| } | |
| return geometry; | |
| } | |
| } | |
| export { | |
| PLYLoader | |
| }; | |
| //# sourceMappingURL=PLYLoader.js.map | |
Xet Storage Details
- Size:
- 11 kB
- Xet hash:
- d23bd701bf854474c1c8926f1b67eca05ec661561a4fe4e6160a4d1de10e0309
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.