decalBuilder.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. import { Vector3, Matrix, Vector2, TmpVectors } from "../../Maths/math.vector.js";
  2. import { Scalar } from "../../Maths/math.scalar.js";
  3. import { Mesh } from "../mesh.js";
  4. import { VertexBuffer } from "../../Buffers/buffer.js";
  5. import { VertexData } from "../mesh.vertexData.js";
  6. import { CompatibilityOptions } from "../../Compat/compatibilityOptions.js";
  7. const xpAxis = new Vector3(1, 0, 0);
  8. const xnAxis = new Vector3(-1, 0, 0);
  9. const ypAxis = new Vector3(0, 1, 0);
  10. const ynAxis = new Vector3(0, -1, 0);
  11. const zpAxis = new Vector3(0, 0, 1);
  12. const znAxis = new Vector3(0, 0, -1);
  13. /** @internal */
  14. class DecalVertex {
  15. constructor(position = Vector3.Zero(), normal = Vector3.Up(), uv = Vector2.Zero(), vertexIdx = 0, vertexIdxForBones = 0, localPositionOverride = null, localNormalOverride = null, matrixIndicesOverride = null, matrixWeightsOverride = null) {
  16. this.position = position;
  17. this.normal = normal;
  18. this.uv = uv;
  19. this.vertexIdx = vertexIdx;
  20. this.vertexIdxForBones = vertexIdxForBones;
  21. this.localPositionOverride = localPositionOverride;
  22. this.localNormalOverride = localNormalOverride;
  23. this.matrixIndicesOverride = matrixIndicesOverride;
  24. this.matrixWeightsOverride = matrixWeightsOverride;
  25. }
  26. clone() {
  27. return new DecalVertex(this.position.clone(), this.normal.clone(), this.uv.clone(), this.vertexIdx, this.vertexIdxForBones, this.localPositionOverride?.slice(), this.localNormalOverride?.slice(), this.matrixIndicesOverride?.slice(), this.matrixWeightsOverride?.slice());
  28. }
  29. }
  30. /**
  31. * Creates a decal mesh.
  32. * A decal is a mesh usually applied as a model onto the surface of another mesh. So don't forget the parameter `sourceMesh` depicting the decal
  33. * * The parameter `position` (Vector3, default `(0, 0, 0)`) sets the position of the decal in World coordinates
  34. * * The parameter `normal` (Vector3, default `Vector3.Up`) sets the normal of the mesh where the decal is applied onto in World coordinates
  35. * * The parameter `size` (Vector3, default `(1, 1, 1)`) sets the decal scaling
  36. * * The parameter `angle` (float in radian, default 0) sets the angle to rotate the decal
  37. * * The parameter `captureUVS` defines if we need to capture the uvs or compute them
  38. * * The parameter `cullBackFaces` defines if the back faces should be removed from the decal mesh
  39. * * The parameter `localMode` defines that the computations should be done with the local mesh coordinates instead of the world space coordinates.
  40. * * Use this mode if you want the decal to be parented to the sourceMesh and move/rotate with it.
  41. * Note: Meshes with morph targets are not supported!
  42. * @param name defines the name of the mesh
  43. * @param sourceMesh defines the mesh where the decal must be applied
  44. * @param options defines the options used to create the mesh
  45. * @returns the decal mesh
  46. * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/decals
  47. */
  48. export function CreateDecal(name, sourceMesh, options) {
  49. const hasSkeleton = !!sourceMesh.skeleton;
  50. const useLocalComputation = options.localMode || hasSkeleton;
  51. const meshHasOverridenMaterial = sourceMesh.overrideMaterialSideOrientation !== null && sourceMesh.overrideMaterialSideOrientation !== undefined;
  52. const indices = sourceMesh.getIndices();
  53. const positions = hasSkeleton ? sourceMesh.getPositionData(true, true) : sourceMesh.getVerticesData(VertexBuffer.PositionKind);
  54. const normals = hasSkeleton ? sourceMesh.getNormalsData(true, true) : sourceMesh.getVerticesData(VertexBuffer.NormalKind);
  55. const localPositions = useLocalComputation ? (hasSkeleton ? sourceMesh.getVerticesData(VertexBuffer.PositionKind) : positions) : null;
  56. const localNormals = useLocalComputation ? (hasSkeleton ? sourceMesh.getVerticesData(VertexBuffer.NormalKind) : normals) : null;
  57. const uvs = sourceMesh.getVerticesData(VertexBuffer.UVKind);
  58. const matIndices = hasSkeleton ? sourceMesh.getVerticesData(VertexBuffer.MatricesIndicesKind) : null;
  59. const matWeights = hasSkeleton ? sourceMesh.getVerticesData(VertexBuffer.MatricesWeightsKind) : null;
  60. const matIndicesExtra = hasSkeleton ? sourceMesh.getVerticesData(VertexBuffer.MatricesIndicesExtraKind) : null;
  61. const matWeightsExtra = hasSkeleton ? sourceMesh.getVerticesData(VertexBuffer.MatricesWeightsExtraKind) : null;
  62. const position = options.position || Vector3.Zero();
  63. let normal = options.normal || Vector3.Up();
  64. const size = options.size || Vector3.One();
  65. const angle = options.angle || 0;
  66. // Getting correct rotation
  67. if (!normal) {
  68. const target = new Vector3(0, 0, 1);
  69. const camera = sourceMesh.getScene().activeCamera;
  70. const cameraWorldTarget = Vector3.TransformCoordinates(target, camera.getWorldMatrix());
  71. normal = camera.globalPosition.subtract(cameraWorldTarget);
  72. }
  73. const yaw = -Math.atan2(normal.z, normal.x) - Math.PI / 2;
  74. const len = Math.sqrt(normal.x * normal.x + normal.z * normal.z);
  75. const pitch = Math.atan2(normal.y, len);
  76. const vertexData = new VertexData();
  77. vertexData.indices = [];
  78. vertexData.positions = [];
  79. vertexData.normals = [];
  80. vertexData.uvs = [];
  81. vertexData.matricesIndices = hasSkeleton ? [] : null;
  82. vertexData.matricesWeights = hasSkeleton ? [] : null;
  83. vertexData.matricesIndicesExtra = matIndicesExtra ? [] : null;
  84. vertexData.matricesWeightsExtra = matWeightsExtra ? [] : null;
  85. let currentVertexDataIndex = 0;
  86. const extractDecalVector3 = (indexId, transformMatrix) => {
  87. const result = new DecalVertex();
  88. if (!indices || !positions || !normals) {
  89. return result;
  90. }
  91. const vertexId = indices[indexId];
  92. result.vertexIdx = vertexId * 3;
  93. result.vertexIdxForBones = vertexId * 4;
  94. // Send vector to decal local world
  95. result.position = new Vector3(positions[vertexId * 3], positions[vertexId * 3 + 1], positions[vertexId * 3 + 2]);
  96. Vector3.TransformCoordinatesToRef(result.position, transformMatrix, result.position);
  97. // Get normal
  98. result.normal = new Vector3(normals[vertexId * 3], normals[vertexId * 3 + 1], normals[vertexId * 3 + 2]);
  99. Vector3.TransformNormalToRef(result.normal, transformMatrix, result.normal);
  100. if (options.captureUVS && uvs) {
  101. const v = uvs[vertexId * 2 + 1];
  102. result.uv = new Vector2(uvs[vertexId * 2], CompatibilityOptions.UseOpenGLOrientationForUV ? 1 - v : v);
  103. }
  104. return result;
  105. };
  106. const emptyArray = [0, 0, 0, 0];
  107. // Inspired by https://github.com/mrdoob/three.js/blob/eee231960882f6f3b6113405f524956145148146/examples/js/geometries/DecalGeometry.js
  108. const clip = (vertices, axis) => {
  109. if (vertices.length === 0) {
  110. return vertices;
  111. }
  112. const clipSize = 0.5 * Math.abs(Vector3.Dot(size, axis));
  113. const indexOf = (arr, val, start, num) => {
  114. for (let i = 0; i < num; ++i) {
  115. if (arr[start + i] === val) {
  116. return start + i;
  117. }
  118. }
  119. return -1;
  120. };
  121. const clipVertices = (v0, v1) => {
  122. const clipFactor = Vector3.GetClipFactor(v0.position, v1.position, axis, clipSize);
  123. let indices = emptyArray;
  124. let weights = emptyArray;
  125. if (matIndices && matWeights) {
  126. const mat0Index = v0.matrixIndicesOverride ? 0 : v0.vertexIdxForBones;
  127. const v0Indices = v0.matrixIndicesOverride ?? matIndices;
  128. const v0Weights = v0.matrixWeightsOverride ?? matWeights;
  129. const mat1Index = v1.matrixIndicesOverride ? 0 : v1.vertexIdxForBones;
  130. const v1Indices = v1.matrixIndicesOverride ?? matIndices;
  131. const v1Weights = v1.matrixWeightsOverride ?? matWeights;
  132. indices = [0, 0, 0, 0];
  133. weights = [0, 0, 0, 0];
  134. let index = 0;
  135. for (let i = 0; i < 4; ++i) {
  136. if (v0Weights[mat0Index + i] > 0) {
  137. const idx = indexOf(v1Indices, v0Indices[mat0Index + i], mat1Index, 4);
  138. indices[index] = v0Indices[mat0Index + i];
  139. weights[index] = Scalar.Lerp(v0Weights[mat0Index + i], idx >= 0 ? v1Weights[idx] : 0, clipFactor);
  140. index++;
  141. }
  142. }
  143. for (let i = 0; i < 4 && index < 4; ++i) {
  144. const ind = v1Indices[mat1Index + i];
  145. if (indexOf(v0Indices, ind, mat0Index, 4) !== -1)
  146. continue;
  147. indices[index] = ind;
  148. weights[index] = Scalar.Lerp(0, v1Weights[mat1Index + i], clipFactor);
  149. index++;
  150. }
  151. const sumw = weights[0] + weights[1] + weights[2] + weights[3];
  152. weights[0] /= sumw;
  153. weights[1] /= sumw;
  154. weights[2] /= sumw;
  155. weights[3] /= sumw;
  156. }
  157. const v0LocalPositionX = v0.localPositionOverride ? v0.localPositionOverride[0] : localPositions?.[v0.vertexIdx] ?? 0;
  158. const v0LocalPositionY = v0.localPositionOverride ? v0.localPositionOverride[1] : localPositions?.[v0.vertexIdx + 1] ?? 0;
  159. const v0LocalPositionZ = v0.localPositionOverride ? v0.localPositionOverride[2] : localPositions?.[v0.vertexIdx + 2] ?? 0;
  160. const v1LocalPositionX = v1.localPositionOverride ? v1.localPositionOverride[0] : localPositions?.[v1.vertexIdx] ?? 0;
  161. const v1LocalPositionY = v1.localPositionOverride ? v1.localPositionOverride[1] : localPositions?.[v1.vertexIdx + 1] ?? 0;
  162. const v1LocalPositionZ = v1.localPositionOverride ? v1.localPositionOverride[2] : localPositions?.[v1.vertexIdx + 2] ?? 0;
  163. const v0LocalNormalX = v0.localNormalOverride ? v0.localNormalOverride[0] : localNormals?.[v0.vertexIdx] ?? 0;
  164. const v0LocalNormalY = v0.localNormalOverride ? v0.localNormalOverride[1] : localNormals?.[v0.vertexIdx + 1] ?? 0;
  165. const v0LocalNormalZ = v0.localNormalOverride ? v0.localNormalOverride[2] : localNormals?.[v0.vertexIdx + 2] ?? 0;
  166. const v1LocalNormalX = v1.localNormalOverride ? v1.localNormalOverride[0] : localNormals?.[v1.vertexIdx] ?? 0;
  167. const v1LocalNormalY = v1.localNormalOverride ? v1.localNormalOverride[1] : localNormals?.[v1.vertexIdx + 1] ?? 0;
  168. const v1LocalNormalZ = v1.localNormalOverride ? v1.localNormalOverride[2] : localNormals?.[v1.vertexIdx + 2] ?? 0;
  169. const interpNormalX = v0LocalNormalX + (v1LocalNormalX - v0LocalNormalX) * clipFactor;
  170. const interpNormalY = v0LocalNormalY + (v1LocalNormalY - v0LocalNormalY) * clipFactor;
  171. const interpNormalZ = v0LocalNormalZ + (v1LocalNormalZ - v0LocalNormalZ) * clipFactor;
  172. const norm = Math.sqrt(interpNormalX * interpNormalX + interpNormalY * interpNormalY + interpNormalZ * interpNormalZ);
  173. return new DecalVertex(Vector3.Lerp(v0.position, v1.position, clipFactor), Vector3.Lerp(v0.normal, v1.normal, clipFactor).normalize(), Vector2.Lerp(v0.uv, v1.uv, clipFactor), -1, -1, localPositions
  174. ? [
  175. v0LocalPositionX + (v1LocalPositionX - v0LocalPositionX) * clipFactor,
  176. v0LocalPositionY + (v1LocalPositionY - v0LocalPositionY) * clipFactor,
  177. v0LocalPositionZ + (v1LocalPositionZ - v0LocalPositionZ) * clipFactor,
  178. ]
  179. : null, localNormals ? [interpNormalX / norm, interpNormalY / norm, interpNormalZ / norm] : null, indices, weights);
  180. };
  181. let clipResult = null;
  182. if (vertices.length > 3) {
  183. clipResult = [];
  184. }
  185. for (let index = 0; index < vertices.length; index += 3) {
  186. let total = 0;
  187. let nV1 = null;
  188. let nV2 = null;
  189. let nV3 = null;
  190. let nV4 = null;
  191. const d1 = Vector3.Dot(vertices[index].position, axis) - clipSize;
  192. const d2 = Vector3.Dot(vertices[index + 1].position, axis) - clipSize;
  193. const d3 = Vector3.Dot(vertices[index + 2].position, axis) - clipSize;
  194. const v1Out = d1 > 0;
  195. const v2Out = d2 > 0;
  196. const v3Out = d3 > 0;
  197. total = (v1Out ? 1 : 0) + (v2Out ? 1 : 0) + (v3Out ? 1 : 0);
  198. switch (total) {
  199. case 0:
  200. if (vertices.length > 3) {
  201. clipResult.push(vertices[index]);
  202. clipResult.push(vertices[index + 1]);
  203. clipResult.push(vertices[index + 2]);
  204. }
  205. else {
  206. clipResult = vertices;
  207. }
  208. break;
  209. case 1:
  210. clipResult = clipResult ?? new Array();
  211. if (v1Out) {
  212. nV1 = vertices[index + 1];
  213. nV2 = vertices[index + 2];
  214. nV3 = clipVertices(vertices[index], nV1);
  215. nV4 = clipVertices(vertices[index], nV2);
  216. }
  217. if (v2Out) {
  218. nV1 = vertices[index];
  219. nV2 = vertices[index + 2];
  220. nV3 = clipVertices(vertices[index + 1], nV1);
  221. nV4 = clipVertices(vertices[index + 1], nV2);
  222. clipResult.push(nV3);
  223. clipResult.push(nV2.clone());
  224. clipResult.push(nV1.clone());
  225. clipResult.push(nV2.clone());
  226. clipResult.push(nV3.clone());
  227. clipResult.push(nV4);
  228. break;
  229. }
  230. if (v3Out) {
  231. nV1 = vertices[index];
  232. nV2 = vertices[index + 1];
  233. nV3 = clipVertices(vertices[index + 2], nV1);
  234. nV4 = clipVertices(vertices[index + 2], nV2);
  235. }
  236. if (nV1 && nV2 && nV3 && nV4) {
  237. clipResult.push(nV1.clone());
  238. clipResult.push(nV2.clone());
  239. clipResult.push(nV3);
  240. clipResult.push(nV4);
  241. clipResult.push(nV3.clone());
  242. clipResult.push(nV2.clone());
  243. }
  244. break;
  245. case 2:
  246. clipResult = clipResult ?? new Array();
  247. if (!v1Out) {
  248. nV1 = vertices[index].clone();
  249. nV2 = clipVertices(nV1, vertices[index + 1]);
  250. nV3 = clipVertices(nV1, vertices[index + 2]);
  251. clipResult.push(nV1);
  252. clipResult.push(nV2);
  253. clipResult.push(nV3);
  254. }
  255. if (!v2Out) {
  256. nV1 = vertices[index + 1].clone();
  257. nV2 = clipVertices(nV1, vertices[index + 2]);
  258. nV3 = clipVertices(nV1, vertices[index]);
  259. clipResult.push(nV1);
  260. clipResult.push(nV2);
  261. clipResult.push(nV3);
  262. }
  263. if (!v3Out) {
  264. nV1 = vertices[index + 2].clone();
  265. nV2 = clipVertices(nV1, vertices[index]);
  266. nV3 = clipVertices(nV1, vertices[index + 1]);
  267. clipResult.push(nV1);
  268. clipResult.push(nV2);
  269. clipResult.push(nV3);
  270. }
  271. break;
  272. case 3:
  273. break;
  274. }
  275. }
  276. return clipResult;
  277. };
  278. const sourceMeshAsMesh = sourceMesh instanceof Mesh ? sourceMesh : null;
  279. const matrixData = sourceMeshAsMesh?._thinInstanceDataStorage.matrixData;
  280. const numMatrices = sourceMeshAsMesh?.thinInstanceCount || 1;
  281. const thinInstanceMatrix = TmpVectors.Matrix[0];
  282. thinInstanceMatrix.copyFrom(Matrix.IdentityReadOnly);
  283. for (let m = 0; m < numMatrices; ++m) {
  284. if (sourceMeshAsMesh?.hasThinInstances && matrixData) {
  285. const ofst = m * 16;
  286. thinInstanceMatrix.setRowFromFloats(0, matrixData[ofst + 0], matrixData[ofst + 1], matrixData[ofst + 2], matrixData[ofst + 3]);
  287. thinInstanceMatrix.setRowFromFloats(1, matrixData[ofst + 4], matrixData[ofst + 5], matrixData[ofst + 6], matrixData[ofst + 7]);
  288. thinInstanceMatrix.setRowFromFloats(2, matrixData[ofst + 8], matrixData[ofst + 9], matrixData[ofst + 10], matrixData[ofst + 11]);
  289. thinInstanceMatrix.setRowFromFloats(3, matrixData[ofst + 12], matrixData[ofst + 13], matrixData[ofst + 14], matrixData[ofst + 15]);
  290. }
  291. // Matrix
  292. const decalWorldMatrix = Matrix.RotationYawPitchRoll(yaw, pitch, angle).multiply(Matrix.Translation(position.x, position.y, position.z));
  293. const inverseDecalWorldMatrix = Matrix.Invert(decalWorldMatrix);
  294. const meshWorldMatrix = sourceMesh.getWorldMatrix();
  295. const transformMatrix = thinInstanceMatrix.multiply(meshWorldMatrix).multiply(inverseDecalWorldMatrix);
  296. const oneFaceVertices = new Array(3);
  297. for (let index = 0; index < indices.length; index += 3) {
  298. let faceVertices = oneFaceVertices;
  299. faceVertices[0] = extractDecalVector3(index, transformMatrix);
  300. if (meshHasOverridenMaterial && useLocalComputation) {
  301. faceVertices[1] = extractDecalVector3(index + 2, transformMatrix);
  302. faceVertices[2] = extractDecalVector3(index + 1, transformMatrix);
  303. }
  304. else {
  305. faceVertices[1] = extractDecalVector3(index + 1, transformMatrix);
  306. faceVertices[2] = extractDecalVector3(index + 2, transformMatrix);
  307. }
  308. if (options.cullBackFaces) {
  309. // If all the normals of the vertices of the face are pointing away from the view direction we discard the face.
  310. // As computations are done in the decal coordinate space, the viewDirection is (0,0,1), so when dot(vertexNormal, -viewDirection) <= 0 the vertex is culled
  311. if (-faceVertices[0].normal.z <= 0 && -faceVertices[1].normal.z <= 0 && -faceVertices[2].normal.z <= 0) {
  312. continue;
  313. }
  314. }
  315. // Clip
  316. faceVertices = clip(faceVertices, xpAxis);
  317. if (!faceVertices)
  318. continue;
  319. faceVertices = clip(faceVertices, xnAxis);
  320. if (!faceVertices)
  321. continue;
  322. faceVertices = clip(faceVertices, ypAxis);
  323. if (!faceVertices)
  324. continue;
  325. faceVertices = clip(faceVertices, ynAxis);
  326. if (!faceVertices)
  327. continue;
  328. faceVertices = clip(faceVertices, zpAxis);
  329. if (!faceVertices)
  330. continue;
  331. faceVertices = clip(faceVertices, znAxis);
  332. if (!faceVertices)
  333. continue;
  334. // Add UVs and get back to world
  335. for (let vIndex = 0; vIndex < faceVertices.length; vIndex++) {
  336. const vertex = faceVertices[vIndex];
  337. //TODO check for Int32Array | Uint32Array | Uint16Array
  338. vertexData.indices.push(currentVertexDataIndex);
  339. if (useLocalComputation) {
  340. if (vertex.localPositionOverride) {
  341. vertexData.positions[currentVertexDataIndex * 3] = vertex.localPositionOverride[0];
  342. vertexData.positions[currentVertexDataIndex * 3 + 1] = vertex.localPositionOverride[1];
  343. vertexData.positions[currentVertexDataIndex * 3 + 2] = vertex.localPositionOverride[2];
  344. }
  345. else if (localPositions) {
  346. vertexData.positions[currentVertexDataIndex * 3] = localPositions[vertex.vertexIdx];
  347. vertexData.positions[currentVertexDataIndex * 3 + 1] = localPositions[vertex.vertexIdx + 1];
  348. vertexData.positions[currentVertexDataIndex * 3 + 2] = localPositions[vertex.vertexIdx + 2];
  349. }
  350. if (vertex.localNormalOverride) {
  351. vertexData.normals[currentVertexDataIndex * 3] = vertex.localNormalOverride[0];
  352. vertexData.normals[currentVertexDataIndex * 3 + 1] = vertex.localNormalOverride[1];
  353. vertexData.normals[currentVertexDataIndex * 3 + 2] = vertex.localNormalOverride[2];
  354. }
  355. else if (localNormals) {
  356. vertexData.normals[currentVertexDataIndex * 3] = localNormals[vertex.vertexIdx];
  357. vertexData.normals[currentVertexDataIndex * 3 + 1] = localNormals[vertex.vertexIdx + 1];
  358. vertexData.normals[currentVertexDataIndex * 3 + 2] = localNormals[vertex.vertexIdx + 2];
  359. }
  360. }
  361. else {
  362. vertex.position.toArray(vertexData.positions, currentVertexDataIndex * 3);
  363. vertex.normal.toArray(vertexData.normals, currentVertexDataIndex * 3);
  364. }
  365. if (vertexData.matricesIndices && vertexData.matricesWeights) {
  366. if (vertex.matrixIndicesOverride) {
  367. vertexData.matricesIndices[currentVertexDataIndex * 4] = vertex.matrixIndicesOverride[0];
  368. vertexData.matricesIndices[currentVertexDataIndex * 4 + 1] = vertex.matrixIndicesOverride[1];
  369. vertexData.matricesIndices[currentVertexDataIndex * 4 + 2] = vertex.matrixIndicesOverride[2];
  370. vertexData.matricesIndices[currentVertexDataIndex * 4 + 3] = vertex.matrixIndicesOverride[3];
  371. }
  372. else {
  373. if (matIndices) {
  374. vertexData.matricesIndices[currentVertexDataIndex * 4] = matIndices[vertex.vertexIdxForBones];
  375. vertexData.matricesIndices[currentVertexDataIndex * 4 + 1] = matIndices[vertex.vertexIdxForBones + 1];
  376. vertexData.matricesIndices[currentVertexDataIndex * 4 + 2] = matIndices[vertex.vertexIdxForBones + 2];
  377. vertexData.matricesIndices[currentVertexDataIndex * 4 + 3] = matIndices[vertex.vertexIdxForBones + 3];
  378. }
  379. if (matIndicesExtra && vertexData.matricesIndicesExtra) {
  380. vertexData.matricesIndicesExtra[currentVertexDataIndex * 4] = matIndicesExtra[vertex.vertexIdxForBones];
  381. vertexData.matricesIndicesExtra[currentVertexDataIndex * 4 + 1] = matIndicesExtra[vertex.vertexIdxForBones + 1];
  382. vertexData.matricesIndicesExtra[currentVertexDataIndex * 4 + 2] = matIndicesExtra[vertex.vertexIdxForBones + 2];
  383. vertexData.matricesIndicesExtra[currentVertexDataIndex * 4 + 3] = matIndicesExtra[vertex.vertexIdxForBones + 3];
  384. }
  385. }
  386. if (vertex.matrixWeightsOverride) {
  387. vertexData.matricesWeights[currentVertexDataIndex * 4] = vertex.matrixWeightsOverride[0];
  388. vertexData.matricesWeights[currentVertexDataIndex * 4 + 1] = vertex.matrixWeightsOverride[1];
  389. vertexData.matricesWeights[currentVertexDataIndex * 4 + 2] = vertex.matrixWeightsOverride[2];
  390. vertexData.matricesWeights[currentVertexDataIndex * 4 + 3] = vertex.matrixWeightsOverride[3];
  391. }
  392. else {
  393. if (matWeights) {
  394. vertexData.matricesWeights[currentVertexDataIndex * 4] = matWeights[vertex.vertexIdxForBones];
  395. vertexData.matricesWeights[currentVertexDataIndex * 4 + 1] = matWeights[vertex.vertexIdxForBones + 1];
  396. vertexData.matricesWeights[currentVertexDataIndex * 4 + 2] = matWeights[vertex.vertexIdxForBones + 2];
  397. vertexData.matricesWeights[currentVertexDataIndex * 4 + 3] = matWeights[vertex.vertexIdxForBones + 3];
  398. }
  399. if (matWeightsExtra && vertexData.matricesWeightsExtra) {
  400. vertexData.matricesWeightsExtra[currentVertexDataIndex * 4] = matWeightsExtra[vertex.vertexIdxForBones];
  401. vertexData.matricesWeightsExtra[currentVertexDataIndex * 4 + 1] = matWeightsExtra[vertex.vertexIdxForBones + 1];
  402. vertexData.matricesWeightsExtra[currentVertexDataIndex * 4 + 2] = matWeightsExtra[vertex.vertexIdxForBones + 2];
  403. vertexData.matricesWeightsExtra[currentVertexDataIndex * 4 + 3] = matWeightsExtra[vertex.vertexIdxForBones + 3];
  404. }
  405. }
  406. }
  407. if (!options.captureUVS) {
  408. vertexData.uvs.push(0.5 + vertex.position.x / size.x);
  409. const v = 0.5 + vertex.position.y / size.y;
  410. vertexData.uvs.push(CompatibilityOptions.UseOpenGLOrientationForUV ? 1 - v : v);
  411. }
  412. else {
  413. vertex.uv.toArray(vertexData.uvs, currentVertexDataIndex * 2);
  414. }
  415. currentVertexDataIndex++;
  416. }
  417. }
  418. }
  419. // Avoid the "Setting vertex data kind 'XXX' with an empty array" warning when calling vertexData.applyToMesh
  420. if (vertexData.indices.length === 0)
  421. vertexData.indices = null;
  422. if (vertexData.positions.length === 0)
  423. vertexData.positions = null;
  424. if (vertexData.normals.length === 0)
  425. vertexData.normals = null;
  426. if (vertexData.uvs.length === 0)
  427. vertexData.uvs = null;
  428. if (vertexData.matricesIndices?.length === 0)
  429. vertexData.matricesIndices = null;
  430. if (vertexData.matricesWeights?.length === 0)
  431. vertexData.matricesWeights = null;
  432. if (vertexData.matricesIndicesExtra?.length === 0)
  433. vertexData.matricesIndicesExtra = null;
  434. if (vertexData.matricesWeightsExtra?.length === 0)
  435. vertexData.matricesWeightsExtra = null;
  436. // Return mesh
  437. const decal = new Mesh(name, sourceMesh.getScene());
  438. vertexData.applyToMesh(decal);
  439. if (useLocalComputation) {
  440. decal.skeleton = sourceMesh.skeleton;
  441. decal.parent = sourceMesh;
  442. }
  443. else {
  444. decal.position = position.clone();
  445. decal.rotation = new Vector3(pitch, yaw, angle);
  446. }
  447. decal.computeWorldMatrix(true);
  448. decal.refreshBoundingInfo(true, true);
  449. return decal;
  450. }
  451. /**
  452. * Class containing static functions to help procedurally build meshes
  453. * @deprecated use the function directly from the module
  454. */
  455. export const DecalBuilder = {
  456. // eslint-disable-next-line @typescript-eslint/naming-convention
  457. CreateDecal,
  458. };
  459. Mesh.CreateDecal = (name, sourceMesh, position, normal, size, angle) => {
  460. const options = {
  461. position,
  462. normal,
  463. size,
  464. angle,
  465. };
  466. return CreateDecal(name, sourceMesh, options);
  467. };
  468. //# sourceMappingURL=decalBuilder.js.map