greasedLineMesh.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. import { Vector3 } from "../../Maths/math.vector.js";
  2. import { Mesh } from "../mesh.js";
  3. import { Buffer, VertexBuffer } from "../../Buffers/buffer.js";
  4. import { PickingInfo } from "../../Collisions/pickingInfo.js";
  5. import { DeepCopier } from "../../Misc/deepCopier.js";
  6. import { GreasedLineTools } from "../../Misc/greasedLineTools.js";
  7. import { GreasedLineBaseMesh } from "./greasedLineBaseMesh.js";
  8. Mesh._GreasedLineMeshParser = (parsedMesh, scene) => {
  9. return GreasedLineMesh.Parse(parsedMesh, scene);
  10. };
  11. /**
  12. * GreasedLineMesh
  13. * Use the GreasedLineBuilder.CreateGreasedLine function to create an instance of this class.
  14. */
  15. export class GreasedLineMesh extends GreasedLineBaseMesh {
  16. /**
  17. * GreasedLineMesh
  18. * @param name name of the mesh
  19. * @param scene the scene
  20. * @param _options mesh options
  21. */
  22. constructor(name, scene, _options) {
  23. super(name, scene, _options);
  24. this.name = name;
  25. /**
  26. * Treshold used to pick the mesh
  27. */
  28. this.intersectionThreshold = 0.1;
  29. this._previousAndSide = [];
  30. this._nextAndCounters = [];
  31. if (_options.points) {
  32. this.addPoints(GreasedLineTools.ConvertPoints(_options.points));
  33. }
  34. }
  35. /**
  36. * "GreasedLineMesh"
  37. * @returns "GreasedLineMesh"
  38. */
  39. getClassName() {
  40. return "GreasedLineMesh";
  41. }
  42. _updateColorPointers() {
  43. if (this._options.colorPointers) {
  44. return;
  45. }
  46. let colorPointer = 0;
  47. this._colorPointers = [];
  48. this._points.forEach((p) => {
  49. for (let jj = 0; jj < p.length; jj += 3) {
  50. this._colorPointers.push(colorPointer);
  51. this._colorPointers.push(colorPointer++);
  52. }
  53. });
  54. }
  55. _updateWidths() {
  56. // intentionally left blank
  57. }
  58. _setPoints(points) {
  59. this._points = points;
  60. this._options.points = points;
  61. this._initGreasedLine();
  62. let indiceOffset = 0;
  63. let vertexPositionsLen = 0, indicesLength = 0, uvLength = 0, previousAndSideLength = 0;
  64. points.forEach((p) => {
  65. vertexPositionsLen += p.length * 2;
  66. indicesLength += (p.length - 3) * 2;
  67. uvLength += (p.length * 4) / 3;
  68. previousAndSideLength += (p.length * 8) / 3;
  69. });
  70. const vertexPositionsArr = new Float32Array(vertexPositionsLen);
  71. const indicesArr = vertexPositionsLen > 65535 ? new Uint32Array(indicesLength) : new Uint16Array(indicesLength);
  72. const uvArr = new Float32Array(uvLength);
  73. const previousAndSide = new Float32Array(previousAndSideLength);
  74. // it's the same length here
  75. const nextAndCounters = new Float32Array(previousAndSideLength);
  76. let vertexPositionsOffset = 0, indicesOffset = 0, uvOffset = 0, previousAndSideOffset = 0, nextAndCountersOffset = 0;
  77. points.forEach((p) => {
  78. const lengthArray = GreasedLineTools.GetLineLengthArray(p);
  79. const totalLength = lengthArray[lengthArray.length - 1];
  80. for (let j = 0, jj = 0; jj < p.length; j++, jj += 3) {
  81. const baseOffset = vertexPositionsOffset + jj * 2;
  82. vertexPositionsArr[baseOffset + 0] = p[jj + 0];
  83. vertexPositionsArr[baseOffset + 1] = p[jj + 1];
  84. vertexPositionsArr[baseOffset + 2] = p[jj + 2];
  85. vertexPositionsArr[baseOffset + 3] = p[jj + 0];
  86. vertexPositionsArr[baseOffset + 4] = p[jj + 1];
  87. vertexPositionsArr[baseOffset + 5] = p[jj + 2];
  88. if (jj < p.length - 3) {
  89. const n = j * 2 + indiceOffset;
  90. const baseIndicesOffset = indicesOffset + jj * 2;
  91. indicesArr[baseIndicesOffset + 0] = n;
  92. indicesArr[baseIndicesOffset + 1] = n + 1;
  93. indicesArr[baseIndicesOffset + 2] = n + 2;
  94. indicesArr[baseIndicesOffset + 3] = n + 2;
  95. indicesArr[baseIndicesOffset + 4] = n + 1;
  96. indicesArr[baseIndicesOffset + 5] = n + 3;
  97. }
  98. }
  99. indiceOffset += (p.length / 3) * 2;
  100. const currVertexPositionsOffsetLength = p.length * 2;
  101. const positions = vertexPositionsArr.subarray(vertexPositionsOffset, vertexPositionsOffset + currVertexPositionsOffsetLength);
  102. vertexPositionsOffset += currVertexPositionsOffsetLength;
  103. indicesOffset += (p.length - 3) * 2;
  104. const previous = new Float32Array(positions.length);
  105. const next = new Float32Array(positions.length);
  106. const l = positions.length / 6;
  107. let v;
  108. if (GreasedLineMesh._CompareV3(0, l - 1, positions)) {
  109. v = positions.subarray((l - 2) * 6, (l - 1) * 6);
  110. }
  111. else {
  112. v = positions.subarray(0, 6);
  113. }
  114. previous.set(v);
  115. previous.set(positions.subarray(0, positions.length - 6), 6);
  116. next.set(positions.subarray(6));
  117. if (GreasedLineMesh._CompareV3(l - 1, 0, positions)) {
  118. v = positions.subarray(6, 12);
  119. }
  120. else {
  121. v = positions.subarray((l - 1) * 6, l * 6);
  122. }
  123. next.set(v, next.length - 6);
  124. for (let i = 0, sidesLength = positions.length / 3; i < sidesLength; i++) {
  125. previousAndSide[previousAndSideOffset++] = previous[i * 3];
  126. previousAndSide[previousAndSideOffset++] = previous[i * 3 + 1];
  127. previousAndSide[previousAndSideOffset++] = previous[i * 3 + 2];
  128. // side[i] = i % 2 ? -1 : 1;
  129. // side[i] = 1 - ((i & 1) << 1);
  130. previousAndSide[previousAndSideOffset++] = 1 - ((i & 1) << 1);
  131. nextAndCounters[nextAndCountersOffset++] = next[i * 3];
  132. nextAndCounters[nextAndCountersOffset++] = next[i * 3 + 1];
  133. nextAndCounters[nextAndCountersOffset++] = next[i * 3 + 2];
  134. // counters[i] = lengthArray[i >> 1] / totalLength;
  135. nextAndCounters[nextAndCountersOffset++] = lengthArray[i >> 1] / totalLength;
  136. }
  137. if (this._options.uvs) {
  138. for (let i = 0; i < this._options.uvs.length; i++) {
  139. uvArr[uvOffset++] = this._options.uvs[i];
  140. }
  141. }
  142. else {
  143. for (let j = 0; j < l; j++) {
  144. // uvs
  145. const uvOffsetBase = uvOffset + j * 4;
  146. uvArr[uvOffsetBase + 0] = j / (l - 1);
  147. uvArr[uvOffsetBase + 1] = 0;
  148. uvArr[uvOffsetBase + 2] = j / (l - 1);
  149. uvArr[uvOffsetBase + 3] = 1;
  150. }
  151. uvOffset += l * 4;
  152. }
  153. });
  154. this._vertexPositions = vertexPositionsArr;
  155. this._indices = indicesArr;
  156. this._uvs = uvArr;
  157. this._previousAndSide = previousAndSide;
  158. this._nextAndCounters = nextAndCounters;
  159. if (!this._lazy) {
  160. if (!this._options.colorPointers) {
  161. this._updateColorPointers();
  162. }
  163. this._createVertexBuffers();
  164. this.refreshBoundingInfo();
  165. }
  166. }
  167. /**
  168. * Clones the GreasedLineMesh.
  169. * @param name new line name
  170. * @param newParent new parent node
  171. * @returns cloned line
  172. */
  173. clone(name = `${this.name}-cloned`, newParent) {
  174. const lineOptions = this._createLineOptions();
  175. const deepCopiedLineOptions = {};
  176. DeepCopier.DeepCopy(lineOptions, deepCopiedLineOptions, ["instance"], undefined, true);
  177. const cloned = new GreasedLineMesh(name, this._scene, deepCopiedLineOptions);
  178. if (newParent) {
  179. cloned.parent = newParent;
  180. }
  181. cloned.material = this.material;
  182. return cloned;
  183. }
  184. /**
  185. * Serializes this GreasedLineMesh
  186. * @param serializationObject object to write serialization to
  187. */
  188. serialize(serializationObject) {
  189. super.serialize(serializationObject);
  190. serializationObject.type = this.getClassName();
  191. serializationObject.lineOptions = this._createLineOptions();
  192. }
  193. /**
  194. * Parses a serialized GreasedLineMesh
  195. * @param parsedMesh the serialized GreasedLineMesh
  196. * @param scene the scene to create the GreasedLineMesh in
  197. * @returns the created GreasedLineMesh
  198. */
  199. static Parse(parsedMesh, scene) {
  200. const lineOptions = parsedMesh.lineOptions;
  201. const name = parsedMesh.name;
  202. const result = new GreasedLineMesh(name, scene, lineOptions);
  203. return result;
  204. }
  205. _initGreasedLine() {
  206. super._initGreasedLine();
  207. this._previousAndSide = [];
  208. this._nextAndCounters = [];
  209. }
  210. /**
  211. * Checks whether a ray is intersecting this GreasedLineMesh
  212. * @param ray ray to check the intersection of this mesh with
  213. * @param fastCheck not supported
  214. * @param trianglePredicate not supported
  215. * @param onlyBoundingInfo defines a boolean indicating if picking should only happen using bounding info (false by default)
  216. * @param worldToUse not supported
  217. * @param skipBoundingInfo a boolean indicating if we should skip the bounding info check
  218. * @returns the picking info
  219. */
  220. intersects(ray, fastCheck, trianglePredicate, onlyBoundingInfo = false, worldToUse, skipBoundingInfo = false) {
  221. const pickingInfo = new PickingInfo();
  222. const intersections = this.findAllIntersections(ray, fastCheck, trianglePredicate, onlyBoundingInfo, worldToUse, skipBoundingInfo, true);
  223. if (intersections?.length === 1) {
  224. const intersection = intersections[0];
  225. pickingInfo.hit = true;
  226. pickingInfo.distance = intersection.distance;
  227. pickingInfo.ray = ray;
  228. pickingInfo.pickedMesh = this;
  229. pickingInfo.pickedPoint = intersection.point;
  230. }
  231. return pickingInfo;
  232. }
  233. /**
  234. * Gets all intersections of a ray and the line
  235. * @param ray Ray to check the intersection of this mesh with
  236. * @param _fastCheck not supported
  237. * @param _trianglePredicate not supported
  238. * @param onlyBoundingInfo defines a boolean indicating if picking should only happen using bounding info (false by default)
  239. * @param _worldToUse not supported
  240. * @param skipBoundingInfo a boolean indicating if we should skip the bounding info check
  241. * @param firstOnly If true, the first and only intersection is immediatelly returned if found
  242. * @returns intersection(s)
  243. */
  244. findAllIntersections(ray, _fastCheck, _trianglePredicate, onlyBoundingInfo = false, _worldToUse, skipBoundingInfo = false, firstOnly = false) {
  245. if (onlyBoundingInfo && !skipBoundingInfo && ray.intersectsSphere(this._boundingSphere, this.intersectionThreshold) === false) {
  246. return;
  247. }
  248. const indices = this.getIndices();
  249. const positions = this.getVerticesData(VertexBuffer.PositionKind);
  250. const widths = this._widths;
  251. const lineWidth = this.greasedLineMaterial?.width ?? 1;
  252. const intersects = [];
  253. if (indices && positions && widths) {
  254. let i = 0, l = 0;
  255. for (i = 0, l = indices.length - 1; i < l; i += 3) {
  256. const a = indices[i];
  257. const b = indices[i + 1];
  258. GreasedLineMesh._V_START.fromArray(positions, a * 3);
  259. GreasedLineMesh._V_END.fromArray(positions, b * 3);
  260. if (this._offsets) {
  261. GreasedLineMesh._V_OFFSET_START.fromArray(this._offsets, a * 3);
  262. GreasedLineMesh._V_OFFSET_END.fromArray(this._offsets, b * 3);
  263. GreasedLineMesh._V_START.addInPlace(GreasedLineMesh._V_OFFSET_START);
  264. GreasedLineMesh._V_END.addInPlace(GreasedLineMesh._V_OFFSET_END);
  265. }
  266. const iFloored = Math.floor(i / 3);
  267. const width = widths[iFloored] !== undefined ? widths[iFloored] : 1;
  268. const precision = (this.intersectionThreshold * (lineWidth * width)) / 2;
  269. const distance = ray.intersectionSegment(GreasedLineMesh._V_START, GreasedLineMesh._V_END, precision);
  270. if (distance !== -1) {
  271. intersects.push({
  272. distance: distance,
  273. point: ray.direction.normalize().multiplyByFloats(distance, distance, distance).add(ray.origin),
  274. });
  275. if (firstOnly) {
  276. return intersects;
  277. }
  278. }
  279. }
  280. i = l;
  281. }
  282. return intersects;
  283. }
  284. get _boundingSphere() {
  285. return this.getBoundingInfo().boundingSphere;
  286. }
  287. static _CompareV3(positionIdx1, positionIdx2, positions) {
  288. const arrayIdx1 = positionIdx1 * 6;
  289. const arrayIdx2 = positionIdx2 * 6;
  290. return positions[arrayIdx1] === positions[arrayIdx2] && positions[arrayIdx1 + 1] === positions[arrayIdx2 + 1] && positions[arrayIdx1 + 2] === positions[arrayIdx2 + 2];
  291. }
  292. _createVertexBuffers() {
  293. const vertexData = super._createVertexBuffers();
  294. const engine = this._scene.getEngine();
  295. const previousAndSideBuffer = new Buffer(engine, this._previousAndSide, false, 4);
  296. this.setVerticesBuffer(previousAndSideBuffer.createVertexBuffer("grl_previousAndSide", 0, 4));
  297. const nextAndCountersBuffer = new Buffer(engine, this._nextAndCounters, false, 4);
  298. this.setVerticesBuffer(nextAndCountersBuffer.createVertexBuffer("grl_nextAndCounters", 0, 4));
  299. const widthBuffer = new Buffer(engine, this._widths, this._updatable, 1);
  300. this.setVerticesBuffer(widthBuffer.createVertexBuffer("grl_widths", 0, 1));
  301. this._widthsBuffer = widthBuffer;
  302. const colorPointersBuffer = new Buffer(engine, this._colorPointers, this._updatable, 1);
  303. this.setVerticesBuffer(colorPointersBuffer.createVertexBuffer("grl_colorPointers", 0, 1));
  304. this._colorPointersBuffer = colorPointersBuffer;
  305. return vertexData;
  306. }
  307. }
  308. GreasedLineMesh._V_START = new Vector3();
  309. GreasedLineMesh._V_END = new Vector3();
  310. GreasedLineMesh._V_OFFSET_START = new Vector3();
  311. GreasedLineMesh._V_OFFSET_END = new Vector3();
  312. //# sourceMappingURL=greasedLineMesh.js.map