trailMesh.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { AbstractMesh } from "../Meshes/abstractMesh.js";
  2. import { Mesh } from "../Meshes/mesh.js";
  3. import { Vector3 } from "../Maths/math.vector.js";
  4. import { VertexBuffer } from "../Buffers/buffer.js";
  5. import { VertexData } from "../Meshes/mesh.vertexData.js";
  6. Mesh._TrailMeshParser = (parsedMesh, scene) => {
  7. return TrailMesh.Parse(parsedMesh, scene);
  8. };
  9. /**
  10. * Class used to create a trail following a mesh
  11. */
  12. export class TrailMesh extends Mesh {
  13. /**
  14. * Creates a new TrailMesh.
  15. * @param name The value used by scene.getMeshByName() to do a lookup.
  16. * @param generator The mesh or transform node to generate a trail.
  17. * @param scene The scene to add this mesh to.
  18. * @param diameter Diameter of trailing mesh. Default is 1.
  19. * @param length Length of trailing mesh. Default is 60.
  20. * @param autoStart Automatically start trailing mesh. Default true.
  21. */
  22. constructor(name, generator, scene, diameter = 1, length = 60, autoStart = true) {
  23. super(name, scene);
  24. this._sectionPolygonPointsCount = 4;
  25. this._running = false;
  26. this._autoStart = autoStart;
  27. this._generator = generator;
  28. this.diameter = diameter;
  29. this._length = length;
  30. this._sectionVectors = [];
  31. this._sectionNormalVectors = [];
  32. for (let i = 0; i <= this._sectionPolygonPointsCount; i++) {
  33. this._sectionVectors[i] = Vector3.Zero();
  34. this._sectionNormalVectors[i] = Vector3.Zero();
  35. }
  36. this._createMesh();
  37. }
  38. /**
  39. * "TrailMesh"
  40. * @returns "TrailMesh"
  41. */
  42. getClassName() {
  43. return "TrailMesh";
  44. }
  45. _createMesh() {
  46. const data = new VertexData();
  47. const positions = [];
  48. const normals = [];
  49. const indices = [];
  50. const uvs = [];
  51. let meshCenter = Vector3.Zero();
  52. if (this._generator instanceof AbstractMesh && this._generator.hasBoundingInfo) {
  53. meshCenter = this._generator.getBoundingInfo().boundingBox.centerWorld;
  54. }
  55. else {
  56. meshCenter = this._generator.absolutePosition;
  57. }
  58. const alpha = (2 * Math.PI) / this._sectionPolygonPointsCount;
  59. for (let i = 0; i <= this._sectionPolygonPointsCount; i++) {
  60. const angle = i !== this._sectionPolygonPointsCount ? i * alpha : 0;
  61. positions.push(meshCenter.x + Math.cos(angle) * this.diameter, meshCenter.y + Math.sin(angle) * this.diameter, meshCenter.z);
  62. uvs.push(i / this._sectionPolygonPointsCount, 0);
  63. }
  64. for (let i = 1; i <= this._length; i++) {
  65. for (let j = 0; j <= this._sectionPolygonPointsCount; j++) {
  66. const angle = j !== this._sectionPolygonPointsCount ? j * alpha : 0;
  67. positions.push(meshCenter.x + Math.cos(angle) * this.diameter, meshCenter.y + Math.sin(angle) * this.diameter, meshCenter.z);
  68. uvs.push(j / this._sectionPolygonPointsCount, i / this._length);
  69. }
  70. const l = positions.length / 3 - 2 * (this._sectionPolygonPointsCount + 1);
  71. for (let j = 0; j <= this._sectionPolygonPointsCount; j++) {
  72. indices.push(l + j, l + j + this._sectionPolygonPointsCount, l + j + this._sectionPolygonPointsCount + 1);
  73. indices.push(l + j, l + j + this._sectionPolygonPointsCount + 1, l + j + 1);
  74. }
  75. }
  76. VertexData.ComputeNormals(positions, indices, normals);
  77. data.positions = positions;
  78. data.normals = normals;
  79. data.indices = indices;
  80. data.uvs = uvs;
  81. data.applyToMesh(this, true);
  82. if (this._autoStart) {
  83. this.start();
  84. }
  85. }
  86. /**
  87. * Start trailing mesh.
  88. */
  89. start() {
  90. if (!this._running) {
  91. this._running = true;
  92. this._beforeRenderObserver = this.getScene().onBeforeRenderObservable.add(() => {
  93. this.update();
  94. });
  95. }
  96. }
  97. /**
  98. * Stop trailing mesh.
  99. */
  100. stop() {
  101. if (this._beforeRenderObserver && this._running) {
  102. this._running = false;
  103. this.getScene().onBeforeRenderObservable.remove(this._beforeRenderObserver);
  104. }
  105. }
  106. /**
  107. * Update trailing mesh geometry.
  108. */
  109. update() {
  110. const positions = this.getVerticesData(VertexBuffer.PositionKind);
  111. const normals = this.getVerticesData(VertexBuffer.NormalKind);
  112. const wm = this._generator.getWorldMatrix();
  113. if (positions && normals) {
  114. for (let i = 3 * (this._sectionPolygonPointsCount + 1); i < positions.length; i++) {
  115. positions[i - 3 * (this._sectionPolygonPointsCount + 1)] = positions[i] - (normals[i] / this._length) * this.diameter;
  116. }
  117. for (let i = 3 * (this._sectionPolygonPointsCount + 1); i < normals.length; i++) {
  118. normals[i - 3 * (this._sectionPolygonPointsCount + 1)] = normals[i];
  119. }
  120. const l = positions.length - 3 * (this._sectionPolygonPointsCount + 1);
  121. const alpha = (2 * Math.PI) / this._sectionPolygonPointsCount;
  122. for (let i = 0; i <= this._sectionPolygonPointsCount; i++) {
  123. const angle = i !== this._sectionPolygonPointsCount ? i * alpha : 0;
  124. this._sectionVectors[i].copyFromFloats(Math.cos(angle) * this.diameter, Math.sin(angle) * this.diameter, 0);
  125. this._sectionNormalVectors[i].copyFromFloats(Math.cos(angle), Math.sin(angle), 0);
  126. Vector3.TransformCoordinatesToRef(this._sectionVectors[i], wm, this._sectionVectors[i]);
  127. Vector3.TransformNormalToRef(this._sectionNormalVectors[i], wm, this._sectionNormalVectors[i]);
  128. }
  129. for (let i = 0; i <= this._sectionPolygonPointsCount; i++) {
  130. positions[l + 3 * i] = this._sectionVectors[i].x;
  131. positions[l + 3 * i + 1] = this._sectionVectors[i].y;
  132. positions[l + 3 * i + 2] = this._sectionVectors[i].z;
  133. normals[l + 3 * i] = this._sectionNormalVectors[i].x;
  134. normals[l + 3 * i + 1] = this._sectionNormalVectors[i].y;
  135. normals[l + 3 * i + 2] = this._sectionNormalVectors[i].z;
  136. }
  137. this.updateVerticesData(VertexBuffer.PositionKind, positions, true, false);
  138. this.updateVerticesData(VertexBuffer.NormalKind, normals, true, false);
  139. }
  140. }
  141. /**
  142. * Returns a new TrailMesh object.
  143. * @param name is a string, the name given to the new mesh
  144. * @param newGenerator use new generator object for cloned trail mesh
  145. * @returns a new mesh
  146. */
  147. clone(name = "", newGenerator) {
  148. return new TrailMesh(name, newGenerator ?? this._generator, this.getScene(), this.diameter, this._length, this._autoStart);
  149. }
  150. /**
  151. * Serializes this trail mesh
  152. * @param serializationObject object to write serialization to
  153. */
  154. serialize(serializationObject) {
  155. super.serialize(serializationObject);
  156. serializationObject.generatorId = this._generator.id;
  157. }
  158. /**
  159. * Parses a serialized trail mesh
  160. * @param parsedMesh the serialized mesh
  161. * @param scene the scene to create the trail mesh in
  162. * @returns the created trail mesh
  163. */
  164. static Parse(parsedMesh, scene) {
  165. const generator = scene.getLastMeshById(parsedMesh.generatorId) ?? scene.getLastTransformNodeById(parsedMesh.generatorId);
  166. if (!generator) {
  167. throw new Error("TrailMesh: generator not found with ID " + parsedMesh.generatorId);
  168. }
  169. return new TrailMesh(parsedMesh.name, generator, scene, parsedMesh.diameter ?? parsedMesh._diameter, parsedMesh._length, parsedMesh._autoStart);
  170. }
  171. }
  172. //# sourceMappingURL=trailMesh.js.map