Home Reference Source

cables_dev/cables/src/core/cg/cg_geom.js

  1. // import { vec2, vec3 } from "gl-matrix";
  2. import { Logger } from "cables-shared-client";
  3. import { UTILS } from "../utils.js";
  4. import { BoundingBox } from "./cg_boundingbox.js";
  5.  
  6. /**
  7. * a geometry contains all information about a mesh, vertices, texturecoordinates etc. etc.
  8. * @namespace external:CGL#Geometry
  9. * @param {String} name
  10. * @class
  11. * @example
  12. * // create a triangle with all attributes
  13. * const geom=new Geometry("triangle"),
  14. *
  15. * geom.vertices = [
  16. * 0.0, sizeH.get(), 0.0,
  17. * -sizeW.get(), -sizeH.get(), 0.0,
  18. * sizeW.get(), -sizeH.get(), 0.0 ];
  19. *
  20. * geom.vertexNormals = [
  21. * 0.0, 0.0, 1.0,
  22. * 0.0, 0.0, 1.0,
  23. * 0.0, 0.0, 1.0 ];
  24. *
  25. * geom.tangents = [
  26. * 1,0,0,
  27. * 1,0,0,
  28. * 1,0,0 ];
  29. *
  30. * geom.biTangents = [
  31. * 0,1,0,
  32. * 0,1,0,
  33. * 0,1,0 ];
  34. *
  35. * geom.texCoords = [
  36. * 0.5, 0.0,
  37. * 1.0, 1.0,
  38. * 0.0, 1.0, ];
  39. *
  40. * geom.verticesIndices = [
  41. * 0, 1, 2 ];
  42. *
  43. */
  44. const Geometry = function (name)
  45. {
  46. this.name = name || "unknown";
  47. this._log = new Logger("cgl_geometry");
  48.  
  49. this.faceVertCount = 3;
  50. this.glPrimitive = null;
  51. this._attributes = {};
  52.  
  53. this._vertices = [];
  54. this.verticesIndices = [];
  55.  
  56. this.isGeometry = true;
  57.  
  58. this.morphTargets = [];
  59.  
  60. Object.defineProperty(this, "vertices", {
  61. get()
  62. {
  63. return this._vertices;
  64. },
  65. set(v)
  66. {
  67. this.setVertices(v);
  68. },
  69. });
  70.  
  71. Object.defineProperty(this, "texCoords", {
  72. get()
  73. {
  74. const att = this.getAttribute("texCoords");
  75. if (!att) return [];
  76. return att.data;
  77. },
  78. set(v)
  79. {
  80. this.setAttribute("texCoords", v, 2);
  81. },
  82. });
  83.  
  84. Object.defineProperty(this, "vertexNormals", {
  85. get()
  86. {
  87. const att = this.getAttribute("vertexNormals");
  88. if (!att) return [];
  89. return att.data;
  90. },
  91. set(v)
  92. {
  93. this.setAttribute("vertexNormals", v, 3);
  94. },
  95. });
  96.  
  97. Object.defineProperty(this, "tangents", {
  98. get()
  99. {
  100. const att = this.getAttribute("tangents");
  101. if (!att) return [];
  102. return att.data;
  103. },
  104. set(v)
  105. {
  106. this.setAttribute("tangents", v, 3);
  107. },
  108. });
  109.  
  110. Object.defineProperty(this, "biTangents", {
  111. get()
  112. {
  113. const att = this.getAttribute("biTangents");
  114. if (!att) return [];
  115. return att.data;
  116. },
  117. set(v)
  118. {
  119. this.setAttribute("biTangents", v, 3);
  120. },
  121. });
  122.  
  123. Object.defineProperty(this, "vertexColors", {
  124. get()
  125. {
  126. const att = this.getAttribute("vertexColors");
  127. if (!att) return [];
  128. return att.data;
  129. },
  130. set(v)
  131. {
  132. this.setAttribute("vertexColors", v, 4);
  133. },
  134. });
  135. };
  136.  
  137. /**
  138. * @function clear
  139. * @memberof Geometry
  140. * @instance
  141. * @description clear all buffers/set them to length 0
  142. */
  143. Geometry.prototype.clear = function ()
  144. {
  145. this._vertices = new Float32Array([]);
  146. this.verticesIndices = [];
  147. this.texCoords = new Float32Array([]);
  148. this.vertexNormals = new Float32Array([]);
  149. this.tangents = [];
  150. this.biTangents = [];
  151. this._attributes = {};
  152. };
  153.  
  154.  
  155.  
  156. /**
  157. * @function getAttributes
  158. @memberof Geometry
  159. * @instance
  160. * @return {Array<Object>} returns array of attribute objects
  161. */
  162. Geometry.prototype.getAttributes = function ()
  163. {
  164. return this._attributes;
  165. };
  166.  
  167. /**
  168. * @function getAttribute
  169. * @memberof Geometry
  170. * @instance
  171. * @param {String} name
  172. * @return {Object}
  173. */
  174. Geometry.prototype.getAttribute = function (name)
  175. {
  176. for (const i in this._attributes)
  177. {
  178. if (this._attributes[i].name == name) return this._attributes[i];
  179. }
  180. return null;
  181. };
  182.  
  183. /**
  184. * @function setAttribute
  185. * @description create an attribute
  186. * @memberof Geometry
  187. * @instance
  188. * @param {String} name
  189. * @param {Array} arr
  190. * @param {Number} itemSize
  191. */
  192. Geometry.prototype.setAttribute = function (name, arr, itemSize)
  193. {
  194. let attrType = "";
  195. if (!itemSize || itemSize > 4)
  196. {
  197. console.log("itemsize wrong?", itemSize, name);
  198. this._log.stack("itemsize");
  199.  
  200. itemSize = 3;
  201. }
  202.  
  203. if (itemSize == 1) attrType = "float";
  204. else if (itemSize == 2) attrType = "vec2";
  205. else if (itemSize == 3) attrType = "vec3";
  206. else if (itemSize == 4) attrType = "vec4";
  207.  
  208.  
  209. const attr = {
  210. "name": name,
  211. "data": arr,
  212. "itemSize": itemSize,
  213. "type": attrType,
  214. };
  215.  
  216. this._attributes[name] = attr;
  217. };
  218.  
  219. Geometry.prototype.copyAttribute = function (name, newgeom)
  220. {
  221. const attr = this.getAttribute(name);
  222. newgeom.setAttribute(name, new Float32Array(attr.data), attr.itemSize);
  223. };
  224.  
  225.  
  226. /**
  227. * @function setVertices
  228. * @memberof Geometry
  229. * @instance
  230. * @description set vertices
  231. * @param {Array|Float32Array} arr [x,y,z,x,y,z,...]
  232. */
  233. Geometry.prototype.setVertices = function (arr)
  234. {
  235. if (arr instanceof Float32Array) this._vertices = arr;
  236. else this._vertices = new Float32Array(arr);
  237. };
  238.  
  239. /**
  240. * @function setTexCoords
  241. * @memberof Geometry
  242. * @instance
  243. * @description set texcoords
  244. * @param {Array|Float32Array} arr [u,v,u,v,...]
  245. */
  246. Geometry.prototype.setTexCoords = function (arr)
  247. {
  248. if (arr instanceof Float32Array) this.texCoords = arr;
  249. else this.texCoords = new Float32Array(arr);
  250. };
  251.  
  252. // Geometry.prototype.testIndices = function ()
  253. // {
  254. // var foundError = false;
  255. // for (var i = 0; i < this.verticesIndices.length; i++)
  256. // {
  257. // if (this.verticesIndices[i * 3 + 0] >= this._vertices.length / 3 || this.verticesIndices[i * 3 + 1] >= this._vertices.length / 3 || this.verticesIndices[i * 3 + 2] >= this._vertices.length / 3)
  258. // {
  259. // foundError = true;
  260. // console.log("index error!");
  261. // }
  262. // }
  263. // };
  264.  
  265. // deprecated
  266. Geometry.prototype.calcNormals = function (smooth)
  267. {
  268. const options = { "smooth": smooth };
  269. this.calculateNormals(options);
  270. };
  271.  
  272. /**
  273. * @function flipNormals
  274. * @memberof Geometry
  275. * @param x
  276. * @param y
  277. * @param z
  278. * @description flip normals
  279. */
  280. Geometry.prototype.flipNormals = function (x, y, z)
  281. {
  282. let vec = vec3.create();
  283.  
  284. if (x == undefined)x = 1;
  285. if (y == undefined)y = 1;
  286. if (z == undefined)z = 1;
  287.  
  288.  
  289. for (let i = 0; i < this.vertexNormals.length; i += 3)
  290. {
  291. vec3.set(vec,
  292. this.vertexNormals[i + 0],
  293. this.vertexNormals[i + 1],
  294. this.vertexNormals[i + 2]);
  295.  
  296. vec[0] *= -x;
  297. vec[1] *= -y;
  298. vec[2] *= -z;
  299.  
  300. vec3.normalize(vec, vec);
  301.  
  302. this.vertexNormals[i + 0] = vec[0];
  303. this.vertexNormals[i + 1] = vec[1];
  304. this.vertexNormals[i + 2] = vec[2];
  305. }
  306. };
  307.  
  308. Geometry.prototype.getNumTriangles = function ()
  309. {
  310. if (this.verticesIndices && this.verticesIndices.length) return this.verticesIndices.length / 3;
  311. return this.vertices.length / 3;
  312. };
  313.  
  314.  
  315. /**
  316. * @function flipVertDir
  317. * @memberof Geometry
  318. * @description flip order of vertices in geom faces
  319. */
  320. Geometry.prototype.flipVertDir = function ()
  321. {
  322. const newInd = [];
  323. newInd.length = this.verticesIndices.length;
  324. for (let i = 0; i < this.verticesIndices.length; i += 3)
  325. {
  326. newInd[i] = this.verticesIndices[i + 2];
  327. newInd[i + 1] = this.verticesIndices[i + 1];
  328. newInd[i + 2] = this.verticesIndices[i];
  329. }
  330. this.verticesIndices = newInd;
  331. };
  332.  
  333.  
  334. Geometry.prototype.setPointVertices = function (verts)
  335. {
  336. if (verts.length % 3 !== 0)
  337. {
  338. this._log.error("SetPointVertices: Array must be multiple of three.");
  339. return;
  340. }
  341.  
  342. if (!(verts instanceof Float32Array)) this.vertices = new Float32Array(verts);
  343. else this.vertices = verts;
  344.  
  345. if (!(this.texCoords instanceof Float32Array)) this.texCoords = new Float32Array((verts.length / 3) * 2);
  346.  
  347. // this.texCoords.length=verts.length/3*2;
  348. this.verticesIndices.length = verts.length / 3;
  349. // this.verticesIndices=[];
  350.  
  351. for (let i = 0; i < verts.length / 3; i++)
  352. {
  353. this.verticesIndices[i] = i;
  354. this.texCoords[i * 2] = 0;
  355. this.texCoords[i * 2 + 1] = 0;
  356. }
  357. };
  358.  
  359. /**
  360. * merge a different geometry into the this geometry
  361. * @function merge
  362. * @param {Geometry} geom
  363. * @memberof Geometry
  364. * @instance
  365. */
  366. Geometry.prototype.merge = function (geom)
  367. {
  368. if (!geom) return;
  369.  
  370. if (this.isIndexed() != geom.isIndexed())
  371. {
  372. if (this.isIndexed())
  373. {
  374. this.unIndex(false, true);
  375. }
  376. if (geom.isIndexed())
  377. {
  378. const g = geom.copy();
  379. g.unIndex(false, true);
  380. geom = g;
  381. }
  382. }
  383.  
  384. const oldIndizesLength = this.verticesIndices.length;
  385. const vertLength = this._vertices.length / 3;
  386.  
  387. this.verticesIndices.length += geom.verticesIndices.length;
  388. for (let i = 0; i < geom.verticesIndices.length; i++)
  389. this.verticesIndices[oldIndizesLength + i] = geom.verticesIndices[i] + vertLength;
  390.  
  391. this.vertices = UTILS.float32Concat(this._vertices, geom.vertices);
  392. this.texCoords = UTILS.float32Concat(this.texCoords, geom.texCoords);
  393. this.vertexNormals = UTILS.float32Concat(this.vertexNormals, geom.vertexNormals);
  394. this.tangents = UTILS.float32Concat(this.tangents, geom.tangents);
  395. this.biTangents = UTILS.float32Concat(this.biTangents, geom.biTangents);
  396. };
  397.  
  398. /**
  399. * a copy of the geometry
  400. * @function copy
  401. * @memberof Geometry
  402. * @instance
  403. */
  404. Geometry.prototype.copy = function ()
  405. {
  406. const geom = new Geometry(this.name + " copy");
  407. geom.faceVertCount = this.faceVertCount;
  408. geom.glPrimitive = this.glPrimitive;
  409.  
  410. geom.setVertices(this._vertices.slice(0));
  411.  
  412. if (this.verticesIndices)
  413. {
  414. geom.verticesIndices.length = this.verticesIndices.length;
  415. for (let i = 0; i < this.verticesIndices.length; i++) geom.verticesIndices[i] = this.verticesIndices[i];
  416. }
  417.  
  418. for (let i in this._attributes) this.copyAttribute(i, geom);
  419.  
  420. geom.morphTargets.length = this.morphTargets.length;
  421. for (let i = 0; i < this.morphTargets.length; i++) geom.morphTargets[i] = this.morphTargets[i];
  422.  
  423. return geom;
  424. };
  425.  
  426. /**
  427. * Calculaten normals
  428. * @function calculateNormals
  429. * @memberof Geometry
  430. * @param options
  431. * @instance
  432. */
  433. Geometry.prototype.calculateNormals = function (options)
  434. {
  435. // todo: should check angle of normals to get edges https://community.khronos.org/t/calculating-accurate-vertex-normals/28152
  436. options = options || {};
  437. if (options.smooth === false) this.unIndex();
  438.  
  439. const u = vec3.create();
  440. const v = vec3.create();
  441. const n = vec3.create();
  442.  
  443. function calcNormal(triangle)
  444. {
  445. vec3.subtract(u, triangle[0], triangle[1]);
  446. vec3.subtract(v, triangle[0], triangle[2]);
  447. vec3.cross(n, u, v);
  448. vec3.normalize(n, n);
  449.  
  450. if (options && options.forceZUp)
  451. {
  452. if (n[2] < 0)
  453. {
  454. n[0] *= -1;
  455. n[1] *= -1;
  456. n[2] *= -1;
  457. }
  458. }
  459. return n;
  460. }
  461.  
  462. this.getVertexVec = function (which)
  463. {
  464. const vec = [0, 0, 0];
  465. vec[0] = this.vertices[which * 3 + 0];
  466. vec[1] = this.vertices[which * 3 + 1];
  467. vec[2] = this.vertices[which * 3 + 2];
  468. return vec;
  469. };
  470.  
  471. if (!(this.vertexNormals instanceof Float32Array) || this.vertexNormals.length != this.vertices.length) this.vertexNormals = new Float32Array(this.vertices.length);
  472.  
  473. for (let i = 0; i < this.vertices.length; i++)
  474. {
  475. this.vertexNormals[i] = 0;
  476. }
  477.  
  478. if (!this.isIndexed())
  479. {
  480. const norms = [];
  481. for (let i = 0; i < this.vertices.length; i += 9)
  482. {
  483. const triangle = [[this.vertices[i + 0], this.vertices[i + 1], this.vertices[i + 2]], [this.vertices[i + 3], this.vertices[i + 4], this.vertices[i + 5]], [this.vertices[i + 6], this.vertices[i + 7], this.vertices[i + 8]]];
  484. const nn = calcNormal(triangle);
  485. norms.push(nn[0], nn[1], nn[2], nn[0], nn[1], nn[2], nn[0], nn[1], nn[2]);
  486. }
  487. this.vertexNormals = norms;
  488. }
  489. else
  490. {
  491. const faceNormals = [];
  492.  
  493. faceNormals.length = Math.floor(this.verticesIndices.length / 3);
  494.  
  495. for (let i = 0; i < this.verticesIndices.length; i += 3)
  496. {
  497. const triangle = [this.getVertexVec(this.verticesIndices[i + 0]), this.getVertexVec(this.verticesIndices[i + 1]), this.getVertexVec(this.verticesIndices[i + 2])];
  498.  
  499. faceNormals[i / 3] = calcNormal(triangle);
  500.  
  501. this.vertexNormals[this.verticesIndices[i + 0] * 3 + 0] += faceNormals[i / 3][0];
  502. this.vertexNormals[this.verticesIndices[i + 0] * 3 + 1] += faceNormals[i / 3][1];
  503. this.vertexNormals[this.verticesIndices[i + 0] * 3 + 2] += faceNormals[i / 3][2];
  504.  
  505. this.vertexNormals[this.verticesIndices[i + 1] * 3 + 0] += faceNormals[i / 3][0];
  506. this.vertexNormals[this.verticesIndices[i + 1] * 3 + 1] += faceNormals[i / 3][1];
  507. this.vertexNormals[this.verticesIndices[i + 1] * 3 + 2] += faceNormals[i / 3][2];
  508.  
  509. this.vertexNormals[this.verticesIndices[i + 2] * 3 + 0] += faceNormals[i / 3][0];
  510. this.vertexNormals[this.verticesIndices[i + 2] * 3 + 1] += faceNormals[i / 3][1];
  511. this.vertexNormals[this.verticesIndices[i + 2] * 3 + 2] += faceNormals[i / 3][2];
  512. }
  513.  
  514.  
  515. for (let i = 0; i < this.verticesIndices.length; i += 3) // faces
  516. {
  517. for (let k = 0; k < 3; k++) // triangles
  518. {
  519. const vv = [this.vertexNormals[this.verticesIndices[i + k] * 3 + 0], this.vertexNormals[this.verticesIndices[i + k] * 3 + 1], this.vertexNormals[this.verticesIndices[i + k] * 3 + 2]];
  520. vec3.normalize(vv, vv);
  521. this.vertexNormals[this.verticesIndices[i + k] * 3 + 0] = vv[0];
  522. this.vertexNormals[this.verticesIndices[i + k] * 3 + 1] = vv[1];
  523. this.vertexNormals[this.verticesIndices[i + k] * 3 + 2] = vv[2];
  524. }
  525. }
  526. }
  527. };
  528.  
  529. /**
  530. * Calculates tangents & bitangents with the help of uv-coordinates. Adapted from
  531. * Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”.
  532. * Terathon Software 3D Graphics Library.
  533. * https://fenix.tecnico.ulisboa.pt/downloadFile/845043405449073/Tangent%20Space%20Calculation.pdf
  534. *
  535. * @function calcTangentsBitangents
  536. * @memberof Geometry
  537. * @instance
  538. */
  539. Geometry.prototype.calcTangentsBitangents = function ()
  540. {
  541. if (!this.vertices.length)
  542. {
  543. // this._log.error("Cannot calculate tangents/bitangents without vertices.");
  544. return;
  545. }
  546. if (!this.vertexNormals.length)
  547. {
  548. // this._log.error("Cannot calculate tangents/bitangents without normals.");
  549. return;
  550. }
  551. if (!this.texCoords.length)
  552. {
  553. // console.warn("No texcoords. Replacing with default values [0, 0].");
  554. const texCoordLength = (this.vertices.length / 3) * 2;
  555. this.texCoords = new Float32Array(texCoordLength);
  556. for (let i = 0; i < texCoordLength; i += 1) this.texCoords[i] = 0;
  557. }
  558. if (!this.verticesIndices || !this.verticesIndices.length)
  559. {
  560. // this._log.error("Cannot calculate tangents/bitangents without vertex indices.");
  561. return;
  562. }
  563. // this code assumes that we have three indices per triangle
  564. if (this.verticesIndices.length % 3 !== 0)
  565. {
  566. this._log.error("Vertex indices mismatch!");
  567. return;
  568. }
  569.  
  570. const triangleCount = this.verticesIndices.length / 3;
  571. const vertexCount = this.vertices.length / 3;
  572.  
  573. this.tangents = new Float32Array(this.vertexNormals.length);
  574. this.biTangents = new Float32Array(this.vertexNormals.length);
  575.  
  576. // temporary buffers
  577. const tempVertices = [];
  578. tempVertices.length = vertexCount * 2;
  579. const v1 = vec3.create();
  580. const v2 = vec3.create();
  581. const v3 = vec3.create();
  582.  
  583. const w1 = vec2.create();
  584. const w2 = vec2.create();
  585. const w3 = vec2.create();
  586.  
  587. const sdir = vec3.create();
  588. const tdir = vec3.create();
  589.  
  590. // for details on calculation, see article referenced above
  591. for (let tri = 0; tri < triangleCount; tri += 1)
  592. {
  593. // indices of the three vertices for a triangle
  594. const i1 = this.verticesIndices[tri * 3];
  595. const i2 = this.verticesIndices[tri * 3 + 1];
  596. const i3 = this.verticesIndices[tri * 3 + 2];
  597.  
  598. // vertex position as vec3
  599. vec3.set(v1, this.vertices[i1 * 3], this.vertices[i1 * 3 + 1], this.vertices[i1 * 3 + 2]);
  600. vec3.set(v2, this.vertices[i2 * 3], this.vertices[i2 * 3 + 1], this.vertices[i2 * 3 + 2]);
  601. vec3.set(v3, this.vertices[i3 * 3], this.vertices[i3 * 3 + 1], this.vertices[i3 * 3 + 2]);
  602.  
  603. // texture coordinate as vec2
  604. vec2.set(w1, this.texCoords[i1 * 2], this.texCoords[i1 * 2 + 1]);
  605. vec2.set(w2, this.texCoords[i2 * 2], this.texCoords[i2 * 2 + 1]);
  606. vec2.set(w3, this.texCoords[i3 * 2], this.texCoords[i3 * 2 + 1]);
  607.  
  608. const x1 = v2[0] - v1[0];
  609. const x2 = v3[0] - v1[0];
  610. const y1 = v2[1] - v1[1];
  611. const y2 = v3[1] - v1[1];
  612. const z1 = v2[2] - v1[2];
  613. const z2 = v3[2] - v1[2];
  614.  
  615. const s1 = w2[0] - w1[0];
  616. const s2 = w3[0] - w1[0];
  617. const t1 = w2[1] - w1[1];
  618. const t2 = w3[1] - w1[1];
  619.  
  620. const r = 1.0 / (s1 * t2 - s2 * t1);
  621.  
  622. vec3.set(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
  623. vec3.set(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
  624.  
  625. tempVertices[i1] = sdir;
  626. tempVertices[i2] = sdir;
  627. tempVertices[i3] = sdir;
  628.  
  629. tempVertices[i1 + vertexCount] = tdir;
  630. tempVertices[i2 + vertexCount] = tdir;
  631. tempVertices[i3 + vertexCount] = tdir;
  632. }
  633.  
  634. const normal = vec3.create();
  635. const tempVert = vec3.create();
  636. const tan = vec3.create();
  637. const bitan = vec3.create();
  638. const temp1 = vec3.create();
  639. const temp2 = vec3.create();
  640. const crossPd = vec3.create();
  641. const normalized = vec3.create();
  642.  
  643. for (let vert = 0; vert < vertexCount; vert += 1)
  644. {
  645. // NOTE: some meshes don't have index 0 - n in their indexbuffer, if this is the case, skip calculation of this vertex
  646. if (!tempVertices[vert]) continue;
  647.  
  648. vec3.set(normal, this.vertexNormals[vert * 3], this.vertexNormals[vert * 3 + 1], this.vertexNormals[vert * 3 + 2]);
  649. vec3.set(tempVert, tempVertices[vert][0], tempVertices[vert][1], tempVertices[vert][2]);
  650.  
  651. // Gram-Schmidt orthagonalize
  652. const _dp = vec3.dot(normal, tempVert);
  653. vec3.scale(temp1, normal, _dp);
  654. vec3.subtract(temp2, tempVert, temp1);
  655.  
  656. vec3.normalize(normalized, temp2);
  657. vec3.cross(crossPd, normal, tempVert);
  658.  
  659. // const intermDot = vec3.dot(crossPd, tempVertices[vert + vertexCount]);
  660. const w = 1.0;// intermDot < 0.0 ? -1.0 : 1.0;
  661.  
  662. vec3.scale(tan, normalized, 1 / w);
  663. vec3.cross(bitan, normal, tan);
  664.  
  665. this.tangents[vert * 3 + 0] = tan[0];
  666. this.tangents[vert * 3 + 1] = tan[1];
  667. this.tangents[vert * 3 + 2] = tan[2];
  668. this.biTangents[vert * 3 + 0] = bitan[0];
  669. this.biTangents[vert * 3 + 1] = bitan[1];
  670. this.biTangents[vert * 3 + 2] = bitan[2];
  671. }
  672. };
  673.  
  674. Geometry.prototype.isIndexed = function ()
  675. {
  676. if (this._vertices.length == 0) return true;
  677. return this.verticesIndices.length != 0;
  678. };
  679.  
  680. /**
  681. * @function unIndex
  682. * @memberof Geometry
  683. * @instance
  684. * @description remove all vertex indizes, vertices array will contain 3*XYZ for every triangle
  685. * @param {boolean} reIndex
  686. * @param {boolean} dontCalcNormals
  687. */
  688. Geometry.prototype.unIndex = function (reIndex, dontCalcNormals)
  689. {
  690. const newVerts = [];
  691. const newIndizes = [];
  692. let count = 0;
  693.  
  694. for (let j in this._attributes)
  695. {
  696. const attr = this._attributes[j];
  697. let na = [];
  698.  
  699. for (let i = 0; i < this.verticesIndices.length; i += 3)
  700. {
  701. for (let s = 0; s < 3; s++)
  702. {
  703. if (attr.itemSize == 3)
  704. na.push(
  705. attr.data[this.verticesIndices[i + s] * 3 + 0],
  706. attr.data[this.verticesIndices[i + s] * 3 + 1],
  707. attr.data[this.verticesIndices[i + s] * 3 + 2]);
  708. else if (attr.itemSize == 4)
  709. na.push(
  710. attr.data[this.verticesIndices[i + s] * 4 + 0],
  711. attr.data[this.verticesIndices[i + s] * 4 + 1],
  712. attr.data[this.verticesIndices[i + s] * 4 + 2],
  713. attr.data[this.verticesIndices[i + s] * 4 + 3]);
  714. else if (attr.itemSize == 2)
  715. na.push(
  716. attr.data[this.verticesIndices[i + s] * 2 + 0],
  717. attr.data[this.verticesIndices[i + s] * 2 + 1]);
  718. else if (attr.itemSize == 1)
  719. na.push(
  720. attr.data[this.verticesIndices[i + s]]);
  721. else console.log("unknown attr", attr);
  722. }
  723. }
  724. this.setAttribute(attr.name, na, attr.itemSize);
  725. }
  726.  
  727. for (let i = 0; i < this.verticesIndices.length; i += 3)
  728. {
  729. newVerts.push(
  730. this.vertices[this.verticesIndices[i + 0] * 3 + 0],
  731. this.vertices[this.verticesIndices[i + 0] * 3 + 1],
  732. this.vertices[this.verticesIndices[i + 0] * 3 + 2]);
  733.  
  734. newIndizes.push(count);
  735. count++;
  736.  
  737. newVerts.push(
  738. this.vertices[this.verticesIndices[i + 1] * 3 + 0],
  739. this.vertices[this.verticesIndices[i + 1] * 3 + 1],
  740. this.vertices[this.verticesIndices[i + 1] * 3 + 2]);
  741.  
  742. newIndizes.push(count);
  743. count++;
  744.  
  745. newVerts.push(
  746. this.vertices[this.verticesIndices[i + 2] * 3 + 0],
  747. this.vertices[this.verticesIndices[i + 2] * 3 + 1],
  748. this.vertices[this.verticesIndices[i + 2] * 3 + 2]);
  749.  
  750. newIndizes.push(count);
  751. count++;
  752. }
  753.  
  754. this.vertices = newVerts;
  755.  
  756. this.verticesIndices = [];
  757. if (reIndex) this.verticesIndices = newIndizes;
  758.  
  759. if (!dontCalcNormals) this.calculateNormals();
  760. };
  761.  
  762. Geometry.prototype.calcBarycentric = function ()
  763. {
  764. let barycentrics = [];
  765. barycentrics.length = this.vertices.length;
  766. for (let i = 0; i < this.vertices.length; i++) barycentrics[i] = 0;
  767.  
  768. let count = 0;
  769. for (let i = 0; i < this.vertices.length; i += 3)
  770. {
  771. barycentrics[i + count] = 1;
  772. count++;
  773. if (count == 3) count = 0;
  774. }
  775.  
  776. this.setAttribute("attrBarycentric", barycentrics, 3);
  777. };
  778.  
  779. Geometry.prototype.getBounds = function ()
  780. {
  781. return new BoundingBox(this);
  782. };
  783.  
  784. Geometry.prototype.center = function (x, y, z)
  785. {
  786. if (x === undefined)
  787. {
  788. x = true;
  789. y = true;
  790. z = true;
  791. }
  792.  
  793. let i = 0;
  794. const bounds = this.getBounds();
  795. const offset = [bounds.minX + (bounds.maxX - bounds.minX) / 2, bounds.minY + (bounds.maxY - bounds.minY) / 2, bounds.minZ + (bounds.maxZ - bounds.minZ) / 2];
  796.  
  797. for (i = 0; i < this.vertices.length; i += 3)
  798. {
  799. if (this.vertices[i + 0] == this.vertices[i + 0])
  800. {
  801. if (x) this.vertices[i + 0] -= offset[0];
  802. if (y) this.vertices[i + 1] -= offset[1];
  803. if (z) this.vertices[i + 2] -= offset[2];
  804. }
  805. }
  806.  
  807. return offset;
  808. };
  809.  
  810. Geometry.prototype.mapTexCoords2d = function ()
  811. {
  812. const bounds = this.getBounds();
  813. const num = this.vertices.length / 3;
  814.  
  815. this.texCoords = new Float32Array(num * 2);
  816.  
  817. for (let i = 0; i < num; i++)
  818. {
  819. const vertX = this.vertices[i * 3 + 0];
  820. const vertY = this.vertices[i * 3 + 1];
  821. this.texCoords[i * 2 + 0] = vertX / (bounds.maxX - bounds.minX) + 0.5;
  822. this.texCoords[i * 2 + 1] = 1.0 - vertY / (bounds.maxY - bounds.minY) + 0.5;
  823. }
  824. };
  825.  
  826.  
  827. Geometry.prototype.getInfoOneLine = function ()
  828. {
  829. let txt = "";
  830. if (this.faceVertCount == 3 && this.verticesIndices)txt += this.verticesIndices.length / 3;
  831. else txt += 0;
  832.  
  833. txt += " tris ";
  834.  
  835. if (this.vertices)txt += this.vertices.length / 3;
  836. else txt += 0;
  837.  
  838. txt += " verts";
  839.  
  840. return txt;
  841. };
  842.  
  843. Geometry.prototype.getInfo = function ()
  844. {
  845. const info = {};
  846.  
  847. if (this.faceVertCount == 3 && this.verticesIndices)info.numFaces = this.verticesIndices.length / 3;
  848. else info.numFaces = 0;
  849.  
  850. if (this.verticesIndices && this.verticesIndices.length)info.indices = this.verticesIndices.length;
  851.  
  852. if (this.vertices)info.numVerts = this.vertices.length / 3;
  853. else info.numVerts = 0;
  854.  
  855. if (this.vertexNormals) info.numNormals = this.vertexNormals.length / 3;
  856. else info.numNormals = 0;
  857.  
  858. if (this.texCoords) info.numTexCoords = this.texCoords.length / 2;
  859. else info.numTexCoords = 0;
  860.  
  861. if (this.tangents) info.numTangents = this.tangents.length / 3;
  862. else info.numTangents = 0;
  863.  
  864. if (this.biTangents) info.numBiTangents = this.biTangents.length / 3;
  865. else info.numBiTangents = 0;
  866.  
  867. if (this.biTangents) info.numBiTangents = this.biTangents.length / 3;
  868. else info.numBiTangents = 0;
  869.  
  870. if (this.vertexColors) info.numVertexColors = this.vertexColors.length / 4;
  871. else info.numVertexColors = 0;
  872.  
  873. if (this.getAttributes()) info.numAttribs = Object.keys(this.getAttributes()).length;
  874. else info.numAttribs = 0;
  875.  
  876. info.isIndexed = this.isIndexed();
  877.  
  878. return info;
  879. };
  880.  
  881. // -----------------
  882.  
  883. // TODO : rewritwe circle op
  884. Geometry.buildFromFaces = function (arr, name, optimize)
  885. {
  886. const vertices = [];
  887. const verticesIndices = [];
  888.  
  889. for (let i = 0; i < arr.length; i += 3)
  890. {
  891. const a = arr[i + 0];
  892. const b = arr[i + 1];
  893. const c = arr[i + 2];
  894. const face = [-1, -1, -1];
  895.  
  896. if (optimize)
  897. for (let iv = 0; iv < vertices.length; iv += 3)
  898. {
  899. if (vertices[iv + 0] == a[0] && vertices[iv + 1] == a[1] && vertices[iv + 2] == a[2]) face[0] = iv / 3;
  900. if (vertices[iv + 0] == b[0] && vertices[iv + 1] == b[1] && vertices[iv + 2] == b[2]) face[1] = iv / 3;
  901. if (vertices[iv + 0] == c[0] && vertices[iv + 1] == c[1] && vertices[iv + 2] == c[2]) face[2] = iv / 3;
  902. }
  903.  
  904. if (face[0] == -1)
  905. {
  906. vertices.push(a[0], a[1], a[2]);
  907. face[0] = (vertices.length - 1) / 3;
  908. }
  909.  
  910. if (face[1] == -1)
  911. {
  912. vertices.push(b[0], b[1], b[2]);
  913. face[1] = (vertices.length - 1) / 3;
  914. }
  915.  
  916. if (face[2] == -1)
  917. {
  918. vertices.push(c[0], c[1], c[2]);
  919. face[2] = (vertices.length - 1) / 3;
  920. }
  921.  
  922. verticesIndices.push(parseInt(face[0], 10));
  923. verticesIndices.push(parseInt(face[1], 10));
  924. verticesIndices.push(parseInt(face[2], 10));
  925. }
  926.  
  927. const geom = new Geometry(name);
  928. geom.name = name;
  929. geom.vertices = vertices;
  930. geom.verticesIndices = verticesIndices;
  931.  
  932. return geom;
  933. };
  934.  
  935.  
  936. export { Geometry };