(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.MeshSurfaceSampler = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.MeshSurfaceSampler = 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; } /** * Utility class for sampling weighted random points on the surface of a mesh. * * Building the sampler is a one-time O(n) operation. Once built, any number of * random samples may be selected in O(logn) time. Memory usage is O(n). * * References: * - http://www.joesfer.com/?p=84 * - https://stackoverflow.com/a/4322940/1314762 */ var _face = new _three.Triangle(); var _color = new _three.Vector3(); var MeshSurfaceSampler = /*#__PURE__*/function () { function MeshSurfaceSampler(mesh) { _classCallCheck(this, MeshSurfaceSampler); var geometry = mesh.geometry; if (!geometry.isBufferGeometry || geometry.attributes.position.itemSize !== 3) { throw new Error('THREE.MeshSurfaceSampler: Requires BufferGeometry triangle mesh.'); } if (geometry.index) { console.warn('THREE.MeshSurfaceSampler: Converting geometry to non-indexed BufferGeometry.'); geometry = geometry.toNonIndexed(); } this.geometry = geometry; this.randomFunction = Math.random; this.positionAttribute = this.geometry.getAttribute('position'); this.colorAttribute = this.geometry.getAttribute('color'); this.weightAttribute = null; this.distribution = null; } _createClass(MeshSurfaceSampler, [{ key: "setWeightAttribute", value: function setWeightAttribute(name) { this.weightAttribute = name ? this.geometry.getAttribute(name) : null; return this; } }, { key: "build", value: function build() { var positionAttribute = this.positionAttribute; var weightAttribute = this.weightAttribute; var faceWeights = new Float32Array(positionAttribute.count / 3); // Accumulate weights for each mesh face. for (var i = 0; i < positionAttribute.count; i += 3) { var faceWeight = 1; if (weightAttribute) { faceWeight = weightAttribute.getX(i) + weightAttribute.getX(i + 1) + weightAttribute.getX(i + 2); } _face.a.fromBufferAttribute(positionAttribute, i); _face.b.fromBufferAttribute(positionAttribute, i + 1); _face.c.fromBufferAttribute(positionAttribute, i + 2); faceWeight *= _face.getArea(); faceWeights[i / 3] = faceWeight; } // Store cumulative total face weights in an array, where weight index // corresponds to face index. this.distribution = new Float32Array(positionAttribute.count / 3); var cumulativeTotal = 0; for (var _i = 0; _i < faceWeights.length; _i++) { cumulativeTotal += faceWeights[_i]; this.distribution[_i] = cumulativeTotal; } return this; } }, { key: "setRandomGenerator", value: function setRandomGenerator(randomFunction) { this.randomFunction = randomFunction; return this; } }, { key: "sample", value: function sample(targetPosition, targetNormal, targetColor) { var cumulativeTotal = this.distribution[this.distribution.length - 1]; var faceIndex = this.binarySearch(this.randomFunction() * cumulativeTotal); return this.sampleFace(faceIndex, targetPosition, targetNormal, targetColor); } }, { key: "binarySearch", value: function binarySearch(x) { var dist = this.distribution; var start = 0; var end = dist.length - 1; var index = -1; while (start <= end) { var mid = Math.ceil((start + end) / 2); if (mid === 0 || dist[mid - 1] <= x && dist[mid] > x) { index = mid; break; } else if (x < dist[mid]) { end = mid - 1; } else { start = mid + 1; } } return index; } }, { key: "sampleFace", value: function sampleFace(faceIndex, targetPosition, targetNormal, targetColor) { var u = this.randomFunction(); var v = this.randomFunction(); if (u + v > 1) { u = 1 - u; v = 1 - v; } _face.a.fromBufferAttribute(this.positionAttribute, faceIndex * 3); _face.b.fromBufferAttribute(this.positionAttribute, faceIndex * 3 + 1); _face.c.fromBufferAttribute(this.positionAttribute, faceIndex * 3 + 2); targetPosition.set(0, 0, 0).addScaledVector(_face.a, u).addScaledVector(_face.b, v).addScaledVector(_face.c, 1 - (u + v)); if (targetNormal !== undefined) { _face.getNormal(targetNormal); } if (targetColor !== undefined && this.colorAttribute !== undefined) { _face.a.fromBufferAttribute(this.colorAttribute, faceIndex * 3); _face.b.fromBufferAttribute(this.colorAttribute, faceIndex * 3 + 1); _face.c.fromBufferAttribute(this.colorAttribute, faceIndex * 3 + 2); _color.set(0, 0, 0).addScaledVector(_face.a, u).addScaledVector(_face.b, v).addScaledVector(_face.c, 1 - (u + v)); targetColor.r = _color.x; targetColor.g = _color.y; targetColor.b = _color.z; } return this; } }]); return MeshSurfaceSampler; }(); _exports.MeshSurfaceSampler = MeshSurfaceSampler; });