babylon.mesh.vertexData.ts 150 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897
  1. module BABYLON {
  2. /**
  3. * Define an interface for all classes that will get and set the data on vertices
  4. */
  5. export interface IGetSetVerticesData {
  6. isVerticesDataPresent(kind: string): boolean;
  7. getVerticesData(kind: string, copyWhenShared?: boolean, forceCopy?: boolean): Nullable<FloatArray>;
  8. getIndices(copyWhenShared?: boolean): Nullable<IndicesArray>;
  9. setVerticesData(kind: string, data: FloatArray, updatable: boolean): void;
  10. updateVerticesData(kind: string, data: FloatArray, updateExtends?: boolean, makeItUnique?: boolean): void;
  11. setIndices(indices: IndicesArray, totalVertices: Nullable<number>, updatable?: boolean): void;
  12. }
  13. /**
  14. * This class contains the various kinds of data on every vertex of a mesh used in determining its shape and appearance
  15. */
  16. export class VertexData {
  17. /**
  18. * An array of the x, y, z position of each vertex [...., x, y, z, .....]
  19. */
  20. public positions: Nullable<FloatArray>;
  21. /**
  22. * An array of the x, y, z normal vector of each vertex [...., x, y, z, .....]
  23. */
  24. public normals: Nullable<FloatArray>;
  25. /**
  26. * An array of the x, y, z tangent vector of each vertex [...., x, y, z, .....]
  27. */
  28. public tangents: Nullable<FloatArray>;
  29. /**
  30. * An array of u,v which maps a texture image onto each vertex [...., u, v, .....]
  31. */
  32. public uvs: Nullable<FloatArray>;
  33. /**
  34. * A second array of u,v which maps a texture image onto each vertex [...., u, v, .....]
  35. */
  36. public uvs2: Nullable<FloatArray>;
  37. /**
  38. * A third array of u,v which maps a texture image onto each vertex [...., u, v, .....]
  39. */
  40. public uvs3: Nullable<FloatArray>;
  41. /**
  42. * A fourth array of u,v which maps a texture image onto each vertex [...., u, v, .....]
  43. */
  44. public uvs4: Nullable<FloatArray>;
  45. /**
  46. * A fifth array of u,v which maps a texture image onto each vertex [...., u, v, .....]
  47. */
  48. public uvs5: Nullable<FloatArray>;
  49. /**
  50. * A sixth array of u,v which maps a texture image onto each vertex [...., u, v, .....]
  51. */
  52. public uvs6: Nullable<FloatArray>;
  53. /**
  54. * An array of the r, g, b, a, color of each vertex [...., r, g, b, a, .....]
  55. */
  56. public colors: Nullable<FloatArray>;
  57. /**
  58. * An array containing the list of indices to the array of matrices produced by bones, each vertex have up to 4 indices (8 if the matricesIndicesExtra is set).
  59. */
  60. public matricesIndices: Nullable<FloatArray>;
  61. /**
  62. * An array containing the list of weights defining the weight of each indexed matrix in the final computation
  63. */
  64. public matricesWeights: Nullable<FloatArray>;
  65. /**
  66. * An array extending the number of possible indices
  67. */
  68. public matricesIndicesExtra: Nullable<FloatArray>;
  69. /**
  70. * An array extending the number of possible weights when the number of indices is extended
  71. */
  72. public matricesWeightsExtra: Nullable<FloatArray>;
  73. /**
  74. * An array of i, j, k the three vertex indices required for each triangular facet [...., i, j, k .....]
  75. */
  76. public indices: Nullable<IndicesArray>;
  77. /**
  78. * Uses the passed data array to set the set the values for the specified kind of data
  79. * @param data a linear array of floating numbers
  80. * @param kind the type of data that is being set, eg positions, colors etc
  81. */
  82. public set(data: FloatArray, kind: string) {
  83. switch (kind) {
  84. case VertexBuffer.PositionKind:
  85. this.positions = data;
  86. break;
  87. case VertexBuffer.NormalKind:
  88. this.normals = data;
  89. break;
  90. case VertexBuffer.TangentKind:
  91. this.tangents = data;
  92. break;
  93. case VertexBuffer.UVKind:
  94. this.uvs = data;
  95. break;
  96. case VertexBuffer.UV2Kind:
  97. this.uvs2 = data;
  98. break;
  99. case VertexBuffer.UV3Kind:
  100. this.uvs3 = data;
  101. break;
  102. case VertexBuffer.UV4Kind:
  103. this.uvs4 = data;
  104. break;
  105. case VertexBuffer.UV5Kind:
  106. this.uvs5 = data;
  107. break;
  108. case VertexBuffer.UV6Kind:
  109. this.uvs6 = data;
  110. break;
  111. case VertexBuffer.ColorKind:
  112. this.colors = data;
  113. break;
  114. case VertexBuffer.MatricesIndicesKind:
  115. this.matricesIndices = data;
  116. break;
  117. case VertexBuffer.MatricesWeightsKind:
  118. this.matricesWeights = data;
  119. break;
  120. case VertexBuffer.MatricesIndicesExtraKind:
  121. this.matricesIndicesExtra = data;
  122. break;
  123. case VertexBuffer.MatricesWeightsExtraKind:
  124. this.matricesWeightsExtra = data;
  125. break;
  126. }
  127. }
  128. /**
  129. * Associates the vertexData to the passed Mesh.
  130. * Sets it as updatable or not (default `false`)
  131. * @param mesh the mesh the vertexData is applied to
  132. * @param updatable when used and having the value true allows new data to update the vertexData
  133. * @returns the VertexData
  134. */
  135. public applyToMesh(mesh: Mesh, updatable?: boolean): VertexData {
  136. this._applyTo(mesh, updatable);
  137. return this;
  138. }
  139. /**
  140. * Associates the vertexData to the passed Geometry.
  141. * Sets it as updatable or not (default `false`)
  142. * @param geometry the geometry the vertexData is applied to
  143. * @param updatable when used and having the value true allows new data to update the vertexData
  144. * @returns VertexData
  145. */
  146. public applyToGeometry(geometry: Geometry, updatable?: boolean): VertexData {
  147. this._applyTo(geometry, updatable);
  148. return this;
  149. }
  150. /**
  151. * Updates the associated mesh
  152. * @param mesh the mesh to be updated
  153. * @param updateExtends when true the mesh BoundingInfo will be renewed when and if position kind is updated, optional with default false
  154. * @param makeItUnique when true, and when and if position kind is updated, a new global geometry will be created from these positions and set to the mesh, optional with default false
  155. * @returns VertexData
  156. */
  157. public updateMesh(mesh: Mesh, updateExtends?: boolean, makeItUnique?: boolean): VertexData {
  158. this._update(mesh);
  159. return this;
  160. }
  161. /**
  162. * Updates the associated geometry
  163. * @param geometry the geometry to be updated
  164. * @param updateExtends when true BoundingInfo will be renewed when and if position kind is updated, optional with default false
  165. * @param makeItUnique when true, and when and if position kind is updated, a new global geometry will be created from these positions and set to the mesh, optional with default false
  166. * @returns VertexData.
  167. */
  168. public updateGeometry(geometry: Geometry, updateExtends?: boolean, makeItUnique?: boolean): VertexData {
  169. this._update(geometry);
  170. return this;
  171. }
  172. private _applyTo(meshOrGeometry: IGetSetVerticesData, updatable: boolean = false): VertexData {
  173. if (this.positions) {
  174. meshOrGeometry.setVerticesData(VertexBuffer.PositionKind, this.positions, updatable);
  175. }
  176. if (this.normals) {
  177. meshOrGeometry.setVerticesData(VertexBuffer.NormalKind, this.normals, updatable);
  178. }
  179. if (this.tangents) {
  180. meshOrGeometry.setVerticesData(VertexBuffer.TangentKind, this.tangents, updatable);
  181. }
  182. if (this.uvs) {
  183. meshOrGeometry.setVerticesData(VertexBuffer.UVKind, this.uvs, updatable);
  184. }
  185. if (this.uvs2) {
  186. meshOrGeometry.setVerticesData(VertexBuffer.UV2Kind, this.uvs2, updatable);
  187. }
  188. if (this.uvs3) {
  189. meshOrGeometry.setVerticesData(VertexBuffer.UV3Kind, this.uvs3, updatable);
  190. }
  191. if (this.uvs4) {
  192. meshOrGeometry.setVerticesData(VertexBuffer.UV4Kind, this.uvs4, updatable);
  193. }
  194. if (this.uvs5) {
  195. meshOrGeometry.setVerticesData(VertexBuffer.UV5Kind, this.uvs5, updatable);
  196. }
  197. if (this.uvs6) {
  198. meshOrGeometry.setVerticesData(VertexBuffer.UV6Kind, this.uvs6, updatable);
  199. }
  200. if (this.colors) {
  201. meshOrGeometry.setVerticesData(VertexBuffer.ColorKind, this.colors, updatable);
  202. }
  203. if (this.matricesIndices) {
  204. meshOrGeometry.setVerticesData(VertexBuffer.MatricesIndicesKind, this.matricesIndices, updatable);
  205. }
  206. if (this.matricesWeights) {
  207. meshOrGeometry.setVerticesData(VertexBuffer.MatricesWeightsKind, this.matricesWeights, updatable);
  208. }
  209. if (this.matricesIndicesExtra) {
  210. meshOrGeometry.setVerticesData(VertexBuffer.MatricesIndicesExtraKind, this.matricesIndicesExtra, updatable);
  211. }
  212. if (this.matricesWeightsExtra) {
  213. meshOrGeometry.setVerticesData(VertexBuffer.MatricesWeightsExtraKind, this.matricesWeightsExtra, updatable);
  214. }
  215. if (this.indices) {
  216. meshOrGeometry.setIndices(this.indices, null, updatable);
  217. } else {
  218. meshOrGeometry.setIndices([], null);
  219. }
  220. return this;
  221. }
  222. private _update(meshOrGeometry: IGetSetVerticesData, updateExtends?: boolean, makeItUnique?: boolean): VertexData {
  223. if (this.positions) {
  224. meshOrGeometry.updateVerticesData(VertexBuffer.PositionKind, this.positions, updateExtends, makeItUnique);
  225. }
  226. if (this.normals) {
  227. meshOrGeometry.updateVerticesData(VertexBuffer.NormalKind, this.normals, updateExtends, makeItUnique);
  228. }
  229. if (this.tangents) {
  230. meshOrGeometry.updateVerticesData(VertexBuffer.TangentKind, this.tangents, updateExtends, makeItUnique);
  231. }
  232. if (this.uvs) {
  233. meshOrGeometry.updateVerticesData(VertexBuffer.UVKind, this.uvs, updateExtends, makeItUnique);
  234. }
  235. if (this.uvs2) {
  236. meshOrGeometry.updateVerticesData(VertexBuffer.UV2Kind, this.uvs2, updateExtends, makeItUnique);
  237. }
  238. if (this.uvs3) {
  239. meshOrGeometry.updateVerticesData(VertexBuffer.UV3Kind, this.uvs3, updateExtends, makeItUnique);
  240. }
  241. if (this.uvs4) {
  242. meshOrGeometry.updateVerticesData(VertexBuffer.UV4Kind, this.uvs4, updateExtends, makeItUnique);
  243. }
  244. if (this.uvs5) {
  245. meshOrGeometry.updateVerticesData(VertexBuffer.UV5Kind, this.uvs5, updateExtends, makeItUnique);
  246. }
  247. if (this.uvs6) {
  248. meshOrGeometry.updateVerticesData(VertexBuffer.UV6Kind, this.uvs6, updateExtends, makeItUnique);
  249. }
  250. if (this.colors) {
  251. meshOrGeometry.updateVerticesData(VertexBuffer.ColorKind, this.colors, updateExtends, makeItUnique);
  252. }
  253. if (this.matricesIndices) {
  254. meshOrGeometry.updateVerticesData(VertexBuffer.MatricesIndicesKind, this.matricesIndices, updateExtends, makeItUnique);
  255. }
  256. if (this.matricesWeights) {
  257. meshOrGeometry.updateVerticesData(VertexBuffer.MatricesWeightsKind, this.matricesWeights, updateExtends, makeItUnique);
  258. }
  259. if (this.matricesIndicesExtra) {
  260. meshOrGeometry.updateVerticesData(VertexBuffer.MatricesIndicesExtraKind, this.matricesIndicesExtra, updateExtends, makeItUnique);
  261. }
  262. if (this.matricesWeightsExtra) {
  263. meshOrGeometry.updateVerticesData(VertexBuffer.MatricesWeightsExtraKind, this.matricesWeightsExtra, updateExtends, makeItUnique);
  264. }
  265. if (this.indices) {
  266. meshOrGeometry.setIndices(this.indices, null);
  267. }
  268. return this;
  269. }
  270. /**
  271. * Transforms each position and each normal of the vertexData according to the passed Matrix
  272. * @param matrix the transforming matrix
  273. * @returns the VertexData
  274. */
  275. public transform(matrix: Matrix): VertexData {
  276. var scaling = Vector3.One();
  277. matrix.decompose(scaling, BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[0]);
  278. var flip = scaling.x * scaling.y * scaling.z < 0;
  279. var transformed = Vector3.Zero();
  280. var index: number;
  281. if (this.positions) {
  282. var position = Vector3.Zero();
  283. for (index = 0; index < this.positions.length; index += 3) {
  284. Vector3.FromArrayToRef(this.positions, index, position);
  285. Vector3.TransformCoordinatesToRef(position, matrix, transformed);
  286. this.positions[index] = transformed.x;
  287. this.positions[index + 1] = transformed.y;
  288. this.positions[index + 2] = transformed.z;
  289. }
  290. }
  291. if (this.normals) {
  292. var normal = Vector3.Zero();
  293. for (index = 0; index < this.normals.length; index += 3) {
  294. Vector3.FromArrayToRef(this.normals, index, normal);
  295. Vector3.TransformNormalToRef(normal, matrix, transformed);
  296. this.normals[index] = transformed.x;
  297. this.normals[index + 1] = transformed.y;
  298. this.normals[index + 2] = transformed.z;
  299. }
  300. }
  301. if (this.tangents) {
  302. var tangent = Vector4.Zero();
  303. var tangentTransformed = Vector4.Zero();
  304. for (index = 0; index < this.tangents.length; index += 4) {
  305. Vector4.FromArrayToRef(this.tangents, index, tangent);
  306. Vector4.TransformNormalToRef(tangent, matrix, tangentTransformed);
  307. this.tangents[index] = tangentTransformed.x;
  308. this.tangents[index + 1] = tangentTransformed.y;
  309. this.tangents[index + 2] = tangentTransformed.z;
  310. this.tangents[index + 3] = tangentTransformed.w;
  311. }
  312. }
  313. if (flip && this.indices) {
  314. for (index = 0; index < this.indices!.length; index += 3) {
  315. let tmp = this.indices[index + 1];
  316. this.indices[index + 1] = this.indices[index + 2];
  317. this.indices[index + 2] = tmp;
  318. }
  319. }
  320. return this;
  321. }
  322. /**
  323. * Merges the passed VertexData into the current one
  324. * @param other the VertexData to be merged into the current one
  325. * @returns the modified VertexData
  326. */
  327. public merge(other: VertexData): VertexData {
  328. this._validate();
  329. other._validate();
  330. if (!this.normals !== !other.normals ||
  331. !this.tangents !== !other.tangents ||
  332. !this.uvs !== !other.uvs ||
  333. !this.uvs2 !== !other.uvs2 ||
  334. !this.uvs3 !== !other.uvs3 ||
  335. !this.uvs4 !== !other.uvs4 ||
  336. !this.uvs5 !== !other.uvs5 ||
  337. !this.uvs6 !== !other.uvs6 ||
  338. !this.colors !== !other.colors ||
  339. !this.matricesIndices !== !other.matricesIndices ||
  340. !this.matricesWeights !== !other.matricesWeights ||
  341. !this.matricesIndicesExtra !== !other.matricesIndicesExtra ||
  342. !this.matricesWeightsExtra !== !other.matricesWeightsExtra)
  343. {
  344. throw new Error("Cannot merge vertex data that do not have the same set of attributes");
  345. }
  346. if (other.indices) {
  347. if (!this.indices) {
  348. this.indices = [];
  349. }
  350. var offset = this.positions ? this.positions.length / 3 : 0;
  351. for (var index = 0; index < other.indices.length; index++) {
  352. //TODO check type - if Int32Array | Uint32Array | Uint16Array!
  353. (<number[]>this.indices).push(other.indices[index] + offset);
  354. }
  355. }
  356. this.positions = this._mergeElement(this.positions, other.positions);
  357. this.normals = this._mergeElement(this.normals, other.normals);
  358. this.tangents = this._mergeElement(this.tangents, other.tangents);
  359. this.uvs = this._mergeElement(this.uvs, other.uvs);
  360. this.uvs2 = this._mergeElement(this.uvs2, other.uvs2);
  361. this.uvs3 = this._mergeElement(this.uvs3, other.uvs3);
  362. this.uvs4 = this._mergeElement(this.uvs4, other.uvs4);
  363. this.uvs5 = this._mergeElement(this.uvs5, other.uvs5);
  364. this.uvs6 = this._mergeElement(this.uvs6, other.uvs6);
  365. this.colors = this._mergeElement(this.colors, other.colors);
  366. this.matricesIndices = this._mergeElement(this.matricesIndices, other.matricesIndices);
  367. this.matricesWeights = this._mergeElement(this.matricesWeights, other.matricesWeights);
  368. this.matricesIndicesExtra = this._mergeElement(this.matricesIndicesExtra, other.matricesIndicesExtra);
  369. this.matricesWeightsExtra = this._mergeElement(this.matricesWeightsExtra, other.matricesWeightsExtra);
  370. return this;
  371. }
  372. private _mergeElement(source: Nullable<FloatArray>, other: Nullable<FloatArray>): Nullable<FloatArray> {
  373. if (!source) {
  374. return other;
  375. }
  376. if (!other) {
  377. return source;
  378. }
  379. var len = other.length + source.length;
  380. var isSrcTypedArray = source instanceof Float32Array;
  381. var isOthTypedArray = other instanceof Float32Array;
  382. // use non-loop method when the source is Float32Array
  383. if (isSrcTypedArray) {
  384. var ret32 = new Float32Array(len);
  385. ret32.set(source);
  386. ret32.set(other, source.length);
  387. return ret32;
  388. // source is number[], when other is also use concat
  389. } else if (!isOthTypedArray) {
  390. return (<number[]>source).concat(<number[]>other);
  391. // source is a number[], but other is a Float32Array, loop required
  392. } else {
  393. var ret = (<number[]>source).slice(0); // copy source to a separate array
  394. for (var i = 0, len = other.length; i < len; i++) {
  395. ret.push(other[i]);
  396. }
  397. return ret;
  398. }
  399. }
  400. private _validate(): void {
  401. if (!this.positions) {
  402. throw new Error("Positions are required");
  403. }
  404. const getElementCount = (kind: string, values: FloatArray) => {
  405. const stride = VertexBuffer.DeduceStride(kind);
  406. if ((values.length % stride) !== 0) {
  407. throw new Error("The " + kind + "s array count must be a multiple of " + stride);
  408. }
  409. return values.length / stride;
  410. };
  411. const positionsElementCount = getElementCount(VertexBuffer.PositionKind, this.positions);
  412. const validateElementCount = (kind: string, values: FloatArray) => {
  413. const elementCount = getElementCount(kind, values);
  414. if (elementCount !== positionsElementCount) {
  415. throw new Error("The " + kind + "s element count (" + elementCount + ") does not match the positions count (" + positionsElementCount + ")");
  416. }
  417. };
  418. if (this.normals) validateElementCount(VertexBuffer.NormalKind, this.normals);
  419. if (this.tangents) validateElementCount(VertexBuffer.TangentKind, this.tangents);
  420. if (this.uvs) validateElementCount(VertexBuffer.UVKind, this.uvs);
  421. if (this.uvs2) validateElementCount(VertexBuffer.UV2Kind, this.uvs2);
  422. if (this.uvs3) validateElementCount(VertexBuffer.UV3Kind, this.uvs3);
  423. if (this.uvs4) validateElementCount(VertexBuffer.UV4Kind, this.uvs4);
  424. if (this.uvs5) validateElementCount(VertexBuffer.UV5Kind, this.uvs5);
  425. if (this.uvs6) validateElementCount(VertexBuffer.UV6Kind, this.uvs6);
  426. if (this.colors) validateElementCount(VertexBuffer.ColorKind, this.colors);
  427. if (this.matricesIndices) validateElementCount(VertexBuffer.MatricesIndicesKind, this.matricesIndices);
  428. if (this.matricesWeights) validateElementCount(VertexBuffer.MatricesWeightsKind, this.matricesWeights);
  429. if (this.matricesIndicesExtra) validateElementCount(VertexBuffer.MatricesIndicesExtraKind, this.matricesIndicesExtra);
  430. if (this.matricesWeightsExtra) validateElementCount(VertexBuffer.MatricesWeightsExtraKind, this.matricesWeightsExtra);
  431. }
  432. /**
  433. * Serializes the VertexData
  434. * @returns a serialized object
  435. */
  436. public serialize(): any {
  437. var serializationObject = this.serialize();
  438. if (this.positions) {
  439. serializationObject.positions = this.positions;
  440. }
  441. if (this.normals) {
  442. serializationObject.normals = this.normals;
  443. }
  444. if (this.tangents) {
  445. serializationObject.tangents = this.tangents;
  446. }
  447. if (this.uvs) {
  448. serializationObject.uvs = this.uvs;
  449. }
  450. if (this.uvs2) {
  451. serializationObject.uvs2 = this.uvs2;
  452. }
  453. if (this.uvs3) {
  454. serializationObject.uvs3 = this.uvs3;
  455. }
  456. if (this.uvs4) {
  457. serializationObject.uvs4 = this.uvs4;
  458. }
  459. if (this.uvs5) {
  460. serializationObject.uvs5 = this.uvs5;
  461. }
  462. if (this.uvs6) {
  463. serializationObject.uvs6 = this.uvs6;
  464. }
  465. if (this.colors) {
  466. serializationObject.colors = this.colors;
  467. }
  468. if (this.matricesIndices) {
  469. serializationObject.matricesIndices = this.matricesIndices;
  470. serializationObject.matricesIndices._isExpanded = true;
  471. }
  472. if (this.matricesWeights) {
  473. serializationObject.matricesWeights = this.matricesWeights;
  474. }
  475. if (this.matricesIndicesExtra) {
  476. serializationObject.matricesIndicesExtra = this.matricesIndicesExtra;
  477. serializationObject.matricesIndicesExtra._isExpanded = true;
  478. }
  479. if (this.matricesWeightsExtra) {
  480. serializationObject.matricesWeightsExtra = this.matricesWeightsExtra;
  481. }
  482. serializationObject.indices = this.indices;
  483. return serializationObject;
  484. }
  485. // Statics
  486. /**
  487. * Extracts the vertexData from a mesh
  488. * @param mesh the mesh from which to extract the VertexData
  489. * @param copyWhenShared defines if the VertexData must be cloned when shared between multiple meshes, optional, default false
  490. * @param forceCopy indicating that the VertexData must be cloned, optional, default false
  491. * @returns the object VertexData associated to the passed mesh
  492. */
  493. public static ExtractFromMesh(mesh: Mesh, copyWhenShared?: boolean, forceCopy?: boolean): VertexData {
  494. return VertexData._ExtractFrom(mesh, copyWhenShared, forceCopy);
  495. }
  496. /**
  497. * Extracts the vertexData from the geometry
  498. * @param geometry the geometry from which to extract the VertexData
  499. * @param copyWhenShared defines if the VertexData must be cloned when the geometrty is shared between multiple meshes, optional, default false
  500. * @param forceCopy indicating that the VertexData must be cloned, optional, default false
  501. * @returns the object VertexData associated to the passed mesh
  502. */
  503. public static ExtractFromGeometry(geometry: Geometry, copyWhenShared?: boolean, forceCopy?: boolean): VertexData {
  504. return VertexData._ExtractFrom(geometry, copyWhenShared, forceCopy);
  505. }
  506. private static _ExtractFrom(meshOrGeometry: IGetSetVerticesData, copyWhenShared?: boolean, forceCopy?: boolean): VertexData {
  507. var result = new VertexData();
  508. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.PositionKind)) {
  509. result.positions = meshOrGeometry.getVerticesData(VertexBuffer.PositionKind, copyWhenShared, forceCopy);
  510. }
  511. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.NormalKind)) {
  512. result.normals = meshOrGeometry.getVerticesData(VertexBuffer.NormalKind, copyWhenShared, forceCopy);
  513. }
  514. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.TangentKind)) {
  515. result.tangents = meshOrGeometry.getVerticesData(VertexBuffer.TangentKind, copyWhenShared, forceCopy);
  516. }
  517. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.UVKind)) {
  518. result.uvs = meshOrGeometry.getVerticesData(VertexBuffer.UVKind, copyWhenShared, forceCopy);
  519. }
  520. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  521. result.uvs2 = meshOrGeometry.getVerticesData(VertexBuffer.UV2Kind, copyWhenShared, forceCopy);
  522. }
  523. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.UV3Kind)) {
  524. result.uvs3 = meshOrGeometry.getVerticesData(VertexBuffer.UV3Kind, copyWhenShared, forceCopy);
  525. }
  526. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.UV4Kind)) {
  527. result.uvs4 = meshOrGeometry.getVerticesData(VertexBuffer.UV4Kind, copyWhenShared, forceCopy);
  528. }
  529. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.UV5Kind)) {
  530. result.uvs5 = meshOrGeometry.getVerticesData(VertexBuffer.UV5Kind, copyWhenShared, forceCopy);
  531. }
  532. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.UV6Kind)) {
  533. result.uvs6 = meshOrGeometry.getVerticesData(VertexBuffer.UV6Kind, copyWhenShared, forceCopy);
  534. }
  535. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.ColorKind)) {
  536. result.colors = meshOrGeometry.getVerticesData(VertexBuffer.ColorKind, copyWhenShared, forceCopy);
  537. }
  538. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind)) {
  539. result.matricesIndices = meshOrGeometry.getVerticesData(VertexBuffer.MatricesIndicesKind, copyWhenShared, forceCopy);
  540. }
  541. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind)) {
  542. result.matricesWeights = meshOrGeometry.getVerticesData(VertexBuffer.MatricesWeightsKind, copyWhenShared, forceCopy);
  543. }
  544. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.MatricesIndicesExtraKind)) {
  545. result.matricesIndicesExtra = meshOrGeometry.getVerticesData(VertexBuffer.MatricesIndicesExtraKind, copyWhenShared, forceCopy);
  546. }
  547. if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.MatricesWeightsExtraKind)) {
  548. result.matricesWeightsExtra = meshOrGeometry.getVerticesData(VertexBuffer.MatricesWeightsExtraKind, copyWhenShared, forceCopy);
  549. }
  550. result.indices = meshOrGeometry.getIndices(copyWhenShared);
  551. return result;
  552. }
  553. /**
  554. * Creates the VertexData for a Ribbon
  555. * @param options an object used to set the following optional parameters for the ribbon, required but can be empty
  556. * * pathArray array of paths, each of which an array of successive Vector3
  557. * * closeArray creates a seam between the first and the last paths of the pathArray, optional, default false
  558. * * closePath creates a seam between the first and the last points of each path of the path array, optional, default false
  559. * * offset a positive integer, only used when pathArray contains a single path (offset = 10 means the point 1 is joined to the point 11), default rounded half size of the pathArray length
  560. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  561. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  562. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  563. * * invertUV swaps in the U and V coordinates when applying a texture, optional, default false
  564. * * uvs a linear array, of length 2 * number of vertices, of custom UV values, optional
  565. * * colors a linear array, of length 4 * number of vertices, of custom color values, optional
  566. * @returns the VertexData of the ribbon
  567. */
  568. public static CreateRibbon(options: { pathArray: Vector3[][], closeArray?: boolean, closePath?: boolean, offset?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, invertUV?: boolean, uvs?: Vector2[], colors?: Color4[] }): VertexData {
  569. var pathArray: Vector3[][] = options.pathArray;
  570. var closeArray: boolean = options.closeArray || false;
  571. var closePath: boolean = options.closePath || false;
  572. var invertUV: boolean = options.invertUV || false;
  573. var defaultOffset: number = Math.floor(pathArray[0].length / 2);
  574. var offset: number = options.offset || defaultOffset;
  575. offset = offset > defaultOffset ? defaultOffset : Math.floor(offset); // offset max allowed : defaultOffset
  576. var sideOrientation: number = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  577. var customUV = options.uvs;
  578. var customColors = options.colors;
  579. var positions: number[] = [];
  580. var indices: number[] = [];
  581. var normals: number[] = [];
  582. var uvs: number[] = [];
  583. var us: number[][] = []; // us[path_id] = [uDist1, uDist2, uDist3 ... ] distances between points on path path_id
  584. var vs: number[][] = []; // vs[i] = [vDist1, vDist2, vDist3, ... ] distances between points i of consecutives paths from pathArray
  585. var uTotalDistance: number[] = []; // uTotalDistance[p] : total distance of path p
  586. var vTotalDistance: number[] = []; // vTotalDistance[i] : total distance between points i of first and last path from pathArray
  587. var minlg: number; // minimal length among all paths from pathArray
  588. var lg: number[] = []; // array of path lengths : nb of vertex per path
  589. var idx: number[] = []; // array of path indexes : index of each path (first vertex) in the total vertex number
  590. var p: number; // path iterator
  591. var i: number; // point iterator
  592. var j: number; // point iterator
  593. // if single path in pathArray
  594. if (pathArray.length < 2) {
  595. var ar1: Vector3[] = [];
  596. var ar2: Vector3[] = [];
  597. for (i = 0; i < pathArray[0].length - offset; i++) {
  598. ar1.push(pathArray[0][i]);
  599. ar2.push(pathArray[0][i + offset]);
  600. }
  601. pathArray = [ar1, ar2];
  602. }
  603. // positions and horizontal distances (u)
  604. var idc: number = 0;
  605. var closePathCorr: number = (closePath) ? 1 : 0; // the final index will be +1 if closePath
  606. var path: Vector3[];
  607. var l: number;
  608. minlg = pathArray[0].length;
  609. var vectlg: number;
  610. var dist: number;
  611. for (p = 0; p < pathArray.length; p++) {
  612. uTotalDistance[p] = 0;
  613. us[p] = [0];
  614. path = pathArray[p];
  615. l = path.length;
  616. minlg = (minlg < l) ? minlg : l;
  617. j = 0;
  618. while (j < l) {
  619. positions.push(path[j].x, path[j].y, path[j].z);
  620. if (j > 0) {
  621. vectlg = path[j].subtract(path[j - 1]).length();
  622. dist = vectlg + uTotalDistance[p];
  623. us[p].push(dist);
  624. uTotalDistance[p] = dist;
  625. }
  626. j++;
  627. }
  628. if (closePath) { // an extra hidden vertex is added in the "positions" array
  629. j--;
  630. positions.push(path[0].x, path[0].y, path[0].z);
  631. vectlg = path[j].subtract(path[0]).length();
  632. dist = vectlg + uTotalDistance[p];
  633. us[p].push(dist);
  634. uTotalDistance[p] = dist;
  635. }
  636. lg[p] = l + closePathCorr;
  637. idx[p] = idc;
  638. idc += (l + closePathCorr);
  639. }
  640. // vertical distances (v)
  641. var path1: Vector3[];
  642. var path2: Vector3[];
  643. var vertex1: Nullable<Vector3> = null;
  644. var vertex2: Nullable<Vector3> = null;
  645. for (i = 0; i < minlg + closePathCorr; i++) {
  646. vTotalDistance[i] = 0;
  647. vs[i] = [0];
  648. for (p = 0; p < pathArray.length - 1; p++) {
  649. path1 = pathArray[p];
  650. path2 = pathArray[p + 1];
  651. if (i === minlg) { // closePath
  652. vertex1 = path1[0];
  653. vertex2 = path2[0];
  654. }
  655. else {
  656. vertex1 = path1[i];
  657. vertex2 = path2[i];
  658. }
  659. vectlg = vertex2.subtract(vertex1).length();
  660. dist = vectlg + vTotalDistance[i];
  661. vs[i].push(dist);
  662. vTotalDistance[i] = dist;
  663. }
  664. if (closeArray && vertex2 && vertex1) {
  665. path1 = pathArray[p];
  666. path2 = pathArray[0];
  667. if (i === minlg) { // closePath
  668. vertex2 = path2[0];
  669. }
  670. vectlg = vertex2.subtract(vertex1).length();
  671. dist = vectlg + vTotalDistance[i];
  672. vTotalDistance[i] = dist;
  673. }
  674. }
  675. // uvs
  676. var u: number;
  677. var v: number;
  678. if (customUV) {
  679. for (p = 0; p < customUV.length; p++) {
  680. uvs.push(customUV[p].x, customUV[p].y);
  681. }
  682. }
  683. else {
  684. for (p = 0; p < pathArray.length; p++) {
  685. for (i = 0; i < minlg + closePathCorr; i++) {
  686. u = (uTotalDistance[p] != 0.0) ? us[p][i] / uTotalDistance[p] : 0.0;
  687. v = (vTotalDistance[i] != 0.0) ? vs[i][p] / vTotalDistance[i] : 0.0;
  688. if (invertUV) {
  689. uvs.push(v, u);
  690. } else {
  691. uvs.push(u, v);
  692. }
  693. }
  694. }
  695. }
  696. // indices
  697. p = 0; // path index
  698. var pi: number = 0; // positions array index
  699. var l1: number = lg[p] - 1; // path1 length
  700. var l2: number = lg[p + 1] - 1; // path2 length
  701. var min: number = (l1 < l2) ? l1 : l2; // current path stop index
  702. var shft: number = idx[1] - idx[0]; // shift
  703. var path1nb: number = closeArray ? lg.length : lg.length - 1; // number of path1 to iterate on
  704. while (pi <= min && p < path1nb) { // stay under min and don't go over next to last path
  705. // draw two triangles between path1 (p1) and path2 (p2) : (p1.pi, p2.pi, p1.pi+1) and (p2.pi+1, p1.pi+1, p2.pi) clockwise
  706. indices.push(pi, pi + shft, pi + 1);
  707. indices.push(pi + shft + 1, pi + 1, pi + shft);
  708. pi += 1;
  709. if (pi === min) { // if end of one of two consecutive paths reached, go to next existing path
  710. p++;
  711. if (p === lg.length - 1) { // last path of pathArray reached <=> closeArray == true
  712. shft = idx[0] - idx[p];
  713. l1 = lg[p] - 1;
  714. l2 = lg[0] - 1;
  715. }
  716. else {
  717. shft = idx[p + 1] - idx[p];
  718. l1 = lg[p] - 1;
  719. l2 = lg[p + 1] - 1;
  720. }
  721. pi = idx[p];
  722. min = (l1 < l2) ? l1 + pi : l2 + pi;
  723. }
  724. }
  725. // normals
  726. VertexData.ComputeNormals(positions, indices, normals);
  727. if (closePath) { // update both the first and last vertex normals to their average value
  728. var indexFirst: number = 0;
  729. var indexLast: number = 0;
  730. for (p = 0; p < pathArray.length; p++) {
  731. indexFirst = idx[p] * 3;
  732. if (p + 1 < pathArray.length) {
  733. indexLast = (idx[p + 1] - 1) * 3;
  734. }
  735. else {
  736. indexLast = normals.length - 3;
  737. }
  738. normals[indexFirst] = (normals[indexFirst] + normals[indexLast]) * 0.5;
  739. normals[indexFirst + 1] = (normals[indexFirst + 1] + normals[indexLast + 1]) * 0.5;
  740. normals[indexFirst + 2] = (normals[indexFirst + 2] + normals[indexLast + 2]) * 0.5;
  741. normals[indexLast] = normals[indexFirst];
  742. normals[indexLast + 1] = normals[indexFirst + 1];
  743. normals[indexLast + 2] = normals[indexFirst + 2];
  744. }
  745. }
  746. // sides
  747. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  748. // Colors
  749. let colors: Nullable<Float32Array> = null;
  750. if (customColors) {
  751. colors = new Float32Array(customColors.length * 4);
  752. for (var c = 0; c < customColors.length; c++) {
  753. colors[c * 4] = customColors[c].r;
  754. colors[c * 4 + 1] = customColors[c].g;
  755. colors[c * 4 + 2] = customColors[c].b;
  756. colors[c * 4 + 3] = customColors[c].a;
  757. }
  758. }
  759. // Result
  760. var vertexData = new VertexData();
  761. var positions32 = new Float32Array(positions);
  762. var normals32 = new Float32Array(normals);
  763. var uvs32 = new Float32Array(uvs);
  764. vertexData.indices = indices;
  765. vertexData.positions = positions32;
  766. vertexData.normals = normals32;
  767. vertexData.uvs = uvs32;
  768. if (colors) {
  769. vertexData.set(colors, VertexBuffer.ColorKind);
  770. }
  771. if (closePath) {
  772. (<any>vertexData)._idx = idx;
  773. }
  774. return vertexData;
  775. }
  776. /**
  777. * Creates the VertexData for a box
  778. * @param options an object used to set the following optional parameters for the box, required but can be empty
  779. * * size sets the width, height and depth of the box to the value of size, optional default 1
  780. * * width sets the width (x direction) of the box, overwrites the width set by size, optional, default size
  781. * * height sets the height (y direction) of the box, overwrites the height set by size, optional, default size
  782. * * depth sets the depth (z direction) of the box, overwrites the depth set by size, optional, default size
  783. * * faceUV an array of 6 Vector4 elements used to set different images to each box side
  784. * * faceColors an array of 6 Color3 elements used to set different colors to each box side
  785. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  786. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  787. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  788. * @returns the VertexData of the box
  789. */
  790. public static CreateBox(options: { size?: number, width?: number, height?: number, depth?: number, faceUV?: Vector4[], faceColors?: Color4[], sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  791. var normalsSource = [
  792. new Vector3(0, 0, 1),
  793. new Vector3(0, 0, -1),
  794. new Vector3(1, 0, 0),
  795. new Vector3(-1, 0, 0),
  796. new Vector3(0, 1, 0),
  797. new Vector3(0, -1, 0)
  798. ];
  799. var indices = [];
  800. var positions = [];
  801. var normals = [];
  802. var uvs = [];
  803. var width = options.width || options.size || 1;
  804. var height = options.height || options.size || 1;
  805. var depth = options.depth || options.size || 1;
  806. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  807. var faceUV: Vector4[] = options.faceUV || new Array<Vector4>(6);
  808. var faceColors = options.faceColors;
  809. var colors = [];
  810. // default face colors and UV if undefined
  811. for (var f = 0; f < 6; f++) {
  812. if (faceUV[f] === undefined) {
  813. faceUV[f] = new Vector4(0, 0, 1, 1);
  814. }
  815. if (faceColors && faceColors[f] === undefined) {
  816. faceColors[f] = new Color4(1, 1, 1, 1);
  817. }
  818. }
  819. var scaleVector = new Vector3(width / 2, height / 2, depth / 2);
  820. // Create each face in turn.
  821. for (var index = 0; index < normalsSource.length; index++) {
  822. var normal = normalsSource[index];
  823. // Get two vectors perpendicular to the face normal and to each other.
  824. var side1 = new Vector3(normal.y, normal.z, normal.x);
  825. var side2 = Vector3.Cross(normal, side1);
  826. // Six indices (two triangles) per face.
  827. var verticesLength = positions.length / 3;
  828. indices.push(verticesLength);
  829. indices.push(verticesLength + 1);
  830. indices.push(verticesLength + 2);
  831. indices.push(verticesLength);
  832. indices.push(verticesLength + 2);
  833. indices.push(verticesLength + 3);
  834. // Four vertices per face.
  835. var vertex = normal.subtract(side1).subtract(side2).multiply(scaleVector);
  836. positions.push(vertex.x, vertex.y, vertex.z);
  837. normals.push(normal.x, normal.y, normal.z);
  838. uvs.push(faceUV[index].z, faceUV[index].w);
  839. if (faceColors) {
  840. colors.push(faceColors[index].r, faceColors[index].g, faceColors[index].b, faceColors[index].a);
  841. }
  842. vertex = normal.subtract(side1).add(side2).multiply(scaleVector);
  843. positions.push(vertex.x, vertex.y, vertex.z);
  844. normals.push(normal.x, normal.y, normal.z);
  845. uvs.push(faceUV[index].x, faceUV[index].w);
  846. if (faceColors) {
  847. colors.push(faceColors[index].r, faceColors[index].g, faceColors[index].b, faceColors[index].a);
  848. }
  849. vertex = normal.add(side1).add(side2).multiply(scaleVector);
  850. positions.push(vertex.x, vertex.y, vertex.z);
  851. normals.push(normal.x, normal.y, normal.z);
  852. uvs.push(faceUV[index].x, faceUV[index].y);
  853. if (faceColors) {
  854. colors.push(faceColors[index].r, faceColors[index].g, faceColors[index].b, faceColors[index].a);
  855. }
  856. vertex = normal.add(side1).subtract(side2).multiply(scaleVector);
  857. positions.push(vertex.x, vertex.y, vertex.z);
  858. normals.push(normal.x, normal.y, normal.z);
  859. uvs.push(faceUV[index].z, faceUV[index].y);
  860. if (faceColors) {
  861. colors.push(faceColors[index].r, faceColors[index].g, faceColors[index].b, faceColors[index].a);
  862. }
  863. }
  864. // sides
  865. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  866. // Result
  867. var vertexData = new VertexData();
  868. vertexData.indices = indices;
  869. vertexData.positions = positions;
  870. vertexData.normals = normals;
  871. vertexData.uvs = uvs;
  872. if (faceColors) {
  873. var totalColors = (sideOrientation === Mesh.DOUBLESIDE) ? colors.concat(colors) : colors;
  874. vertexData.colors = totalColors;
  875. }
  876. return vertexData;
  877. }
  878. /**
  879. * Creates the VertexData for an ellipsoid, defaults to a sphere
  880. * @param options an object used to set the following optional parameters for the box, required but can be empty
  881. * * segments sets the number of horizontal strips optional, default 32
  882. * * diameter sets the axes dimensions, diameterX, diameterY and diameterZ to the value of diameter, optional default 1
  883. * * diameterX sets the diameterX (x direction) of the ellipsoid, overwrites the diameterX set by diameter, optional, default diameter
  884. * * diameterY sets the diameterY (y direction) of the ellipsoid, overwrites the diameterY set by diameter, optional, default diameter
  885. * * diameterZ sets the diameterZ (z direction) of the ellipsoid, overwrites the diameterZ set by diameter, optional, default diameter
  886. * * arc a number from 0 to 1, to create an unclosed ellipsoid based on the fraction of the circumference (latitude) given by the arc value, optional, default 1
  887. * * slice a number from 0 to 1, to create an unclosed ellipsoid based on the fraction of the height (latitude) given by the arc value, optional, default 1
  888. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  889. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  890. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  891. * @returns the VertexData of the ellipsoid
  892. */
  893. public static CreateSphere(options: { segments?: number, diameter?: number, diameterX?: number, diameterY?: number, diameterZ?: number, arc?: number, slice?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  894. var segments: number = options.segments || 32;
  895. var diameterX: number = options.diameterX || options.diameter || 1;
  896. var diameterY: number = options.diameterY || options.diameter || 1;
  897. var diameterZ: number = options.diameterZ || options.diameter || 1;
  898. var arc: number = options.arc && (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
  899. var slice: number = options.slice && (options.slice <= 0) ? 1.0 : options.slice || 1.0;
  900. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  901. var radius = new Vector3(diameterX / 2, diameterY / 2, diameterZ / 2);
  902. var totalZRotationSteps = 2 + segments;
  903. var totalYRotationSteps = 2 * totalZRotationSteps;
  904. var indices = [];
  905. var positions = [];
  906. var normals = [];
  907. var uvs = [];
  908. for (var zRotationStep = 0; zRotationStep <= totalZRotationSteps; zRotationStep++) {
  909. var normalizedZ = zRotationStep / totalZRotationSteps;
  910. var angleZ = normalizedZ * Math.PI * slice;
  911. for (var yRotationStep = 0; yRotationStep <= totalYRotationSteps; yRotationStep++) {
  912. var normalizedY = yRotationStep / totalYRotationSteps;
  913. var angleY = normalizedY * Math.PI * 2 * arc;
  914. var rotationZ = Matrix.RotationZ(-angleZ);
  915. var rotationY = Matrix.RotationY(angleY);
  916. var afterRotZ = Vector3.TransformCoordinates(Vector3.Up(), rotationZ);
  917. var complete = Vector3.TransformCoordinates(afterRotZ, rotationY);
  918. var vertex = complete.multiply(radius);
  919. var normal = complete.divide(radius).normalize();
  920. positions.push(vertex.x, vertex.y, vertex.z);
  921. normals.push(normal.x, normal.y, normal.z);
  922. uvs.push(normalizedY, normalizedZ);
  923. }
  924. if (zRotationStep > 0) {
  925. var verticesCount = positions.length / 3;
  926. for (var firstIndex = verticesCount - 2 * (totalYRotationSteps + 1); (firstIndex + totalYRotationSteps + 2) < verticesCount; firstIndex++) {
  927. indices.push((firstIndex));
  928. indices.push((firstIndex + 1));
  929. indices.push(firstIndex + totalYRotationSteps + 1);
  930. indices.push((firstIndex + totalYRotationSteps + 1));
  931. indices.push((firstIndex + 1));
  932. indices.push((firstIndex + totalYRotationSteps + 2));
  933. }
  934. }
  935. }
  936. // Sides
  937. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  938. // Result
  939. var vertexData = new VertexData();
  940. vertexData.indices = indices;
  941. vertexData.positions = positions;
  942. vertexData.normals = normals;
  943. vertexData.uvs = uvs;
  944. return vertexData;
  945. }
  946. /**
  947. * Creates the VertexData for a cylinder, cone or prism
  948. * @param options an object used to set the following optional parameters for the box, required but can be empty
  949. * * height sets the height (y direction) of the cylinder, optional, default 2
  950. * * diameterTop sets the diameter of the top of the cone, overwrites diameter, optional, default diameter
  951. * * diameterBottom sets the diameter of the bottom of the cone, overwrites diameter, optional, default diameter
  952. * * diameter sets the diameter of the top and bottom of the cone, optional default 1
  953. * * tessellation the number of prism sides, 3 for a triangular prism, optional, default 24
  954. * * subdivisions` the number of rings along the cylinder height, optional, default 1
  955. * * arc a number from 0 to 1, to create an unclosed cylinder based on the fraction of the circumference given by the arc value, optional, default 1
  956. * * faceColors an array of Color3 elements used to set different colors to the top, rings and bottom respectively
  957. * * faceUV an array of Vector4 elements used to set different images to the top, rings and bottom respectively
  958. * * hasRings when true makes each subdivision independantly treated as a face for faceUV and faceColors, optional, default false
  959. * * enclose when true closes an open cylinder by adding extra flat faces between the height axis and vertical edges, think cut cake
  960. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  961. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  962. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  963. * @returns the VertexData of the cylinder, cone or prism
  964. */
  965. public static CreateCylinder(options: { height?: number, diameterTop?: number, diameterBottom?: number, diameter?: number, tessellation?: number, subdivisions?: number, arc?: number, faceColors?: Color4[], faceUV?: Vector4[], hasRings?: boolean, enclose?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  966. var height: number = options.height || 2;
  967. var diameterTop: number = (options.diameterTop === 0) ? 0 : options.diameterTop || options.diameter || 1;
  968. var diameterBottom: number = (options.diameterBottom === 0) ? 0 : options.diameterBottom || options.diameter || 1;
  969. var tessellation: number = options.tessellation || 24;
  970. var subdivisions: number = options.subdivisions || 1;
  971. var hasRings: boolean = options.hasRings ? true : false;
  972. var enclose: boolean = options.enclose ? true : false
  973. var arc: number = options.arc && (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
  974. var sideOrientation: number = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  975. var faceUV: Vector4[] = options.faceUV || new Array<Vector4>(3);
  976. var faceColors = options.faceColors;
  977. // default face colors and UV if undefined
  978. var quadNb: number = (arc !== 1 && enclose) ? 2 : 0;
  979. var ringNb: number = (hasRings) ? subdivisions : 1;
  980. var surfaceNb: number = 2 + (1 + quadNb) * ringNb;
  981. var f: number;
  982. for (f = 0; f < surfaceNb; f++) {
  983. if (faceColors && faceColors[f] === undefined) {
  984. faceColors[f] = new Color4(1, 1, 1, 1);
  985. }
  986. }
  987. for (f = 0; f < surfaceNb; f++) {
  988. if (faceUV && faceUV[f] === undefined) {
  989. faceUV[f] = new Vector4(0, 0, 1, 1);
  990. }
  991. }
  992. var indices = new Array<number>();
  993. var positions = new Array<number>();
  994. var normals = new Array<number>();
  995. var uvs = new Array<number>();
  996. var colors = new Array<number>();
  997. var angle_step = Math.PI * 2 * arc / tessellation;
  998. var angle: number;
  999. var h: number;
  1000. var radius: number;
  1001. var tan = (diameterBottom - diameterTop) / 2 / height;
  1002. var ringVertex: Vector3 = Vector3.Zero();
  1003. var ringNormal: Vector3 = Vector3.Zero();
  1004. var ringFirstVertex: Vector3 = Vector3.Zero();
  1005. var ringFirstNormal: Vector3 = Vector3.Zero();
  1006. var quadNormal: Vector3 = Vector3.Zero();
  1007. var Y: Vector3 = Axis.Y;
  1008. // positions, normals, uvs
  1009. var i: number;
  1010. var j: number;
  1011. var r: number;
  1012. var ringIdx: number = 1;
  1013. var s: number = 1; // surface index
  1014. var cs: number = 0;
  1015. var v: number = 0;
  1016. for (i = 0; i <= subdivisions; i++) {
  1017. h = i / subdivisions;
  1018. radius = (h * (diameterTop - diameterBottom) + diameterBottom) / 2;
  1019. ringIdx = (hasRings && i !== 0 && i !== subdivisions) ? 2 : 1;
  1020. for (r = 0; r < ringIdx; r++) {
  1021. if (hasRings) {
  1022. s += r;
  1023. }
  1024. if (enclose) {
  1025. s += 2 * r;
  1026. }
  1027. for (j = 0; j <= tessellation; j++) {
  1028. angle = j * angle_step;
  1029. // position
  1030. ringVertex.x = Math.cos(-angle) * radius;
  1031. ringVertex.y = -height / 2 + h * height;
  1032. ringVertex.z = Math.sin(-angle) * radius;
  1033. // normal
  1034. if (diameterTop === 0 && i === subdivisions) {
  1035. // if no top cap, reuse former normals
  1036. ringNormal.x = normals[normals.length - (tessellation + 1) * 3];
  1037. ringNormal.y = normals[normals.length - (tessellation + 1) * 3 + 1];
  1038. ringNormal.z = normals[normals.length - (tessellation + 1) * 3 + 2];
  1039. }
  1040. else {
  1041. ringNormal.x = ringVertex.x;
  1042. ringNormal.z = ringVertex.z;
  1043. ringNormal.y = Math.sqrt(ringNormal.x * ringNormal.x + ringNormal.z * ringNormal.z) * tan;
  1044. ringNormal.normalize();
  1045. }
  1046. // keep first ring vertex values for enclose
  1047. if (j === 0) {
  1048. ringFirstVertex.copyFrom(ringVertex);
  1049. ringFirstNormal.copyFrom(ringNormal);
  1050. }
  1051. positions.push(ringVertex.x, ringVertex.y, ringVertex.z);
  1052. normals.push(ringNormal.x, ringNormal.y, ringNormal.z);
  1053. if (hasRings) {
  1054. v = (cs !== s) ? faceUV[s].y : faceUV[s].w;
  1055. } else {
  1056. v = faceUV[s].y + (faceUV[s].w - faceUV[s].y) * h;
  1057. }
  1058. uvs.push(faceUV[s].x + (faceUV[s].z - faceUV[s].x) * j / tessellation, v);
  1059. if (faceColors) {
  1060. colors.push(faceColors[s].r, faceColors[s].g, faceColors[s].b, faceColors[s].a);
  1061. }
  1062. }
  1063. // if enclose, add four vertices and their dedicated normals
  1064. if (arc !== 1 && enclose) {
  1065. positions.push(ringVertex.x, ringVertex.y, ringVertex.z);
  1066. positions.push(0, ringVertex.y, 0);
  1067. positions.push(0, ringVertex.y, 0);
  1068. positions.push(ringFirstVertex.x, ringFirstVertex.y, ringFirstVertex.z);
  1069. Vector3.CrossToRef(Y, ringNormal, quadNormal);
  1070. quadNormal.normalize();
  1071. normals.push(quadNormal.x, quadNormal.y, quadNormal.z, quadNormal.x, quadNormal.y, quadNormal.z);
  1072. Vector3.CrossToRef(ringFirstNormal, Y, quadNormal);
  1073. quadNormal.normalize();
  1074. normals.push(quadNormal.x, quadNormal.y, quadNormal.z, quadNormal.x, quadNormal.y, quadNormal.z);
  1075. if (hasRings) {
  1076. v = (cs !== s) ? faceUV[s + 1].y : faceUV[s + 1].w;
  1077. } else {
  1078. v = faceUV[s + 1].y + (faceUV[s + 1].w - faceUV[s + 1].y) * h;
  1079. }
  1080. uvs.push(faceUV[s + 1].x, v);
  1081. uvs.push(faceUV[s + 1].z, v);
  1082. if (hasRings) {
  1083. v = (cs !== s) ? faceUV[s + 2].y : faceUV[s + 2].w;
  1084. } else {
  1085. v = faceUV[s + 2].y + (faceUV[s + 2].w - faceUV[s + 2].y) * h;
  1086. }
  1087. uvs.push(faceUV[s + 2].x, v);
  1088. uvs.push(faceUV[s + 2].z, v);
  1089. if (faceColors) {
  1090. colors.push(faceColors[s + 1].r, faceColors[s + 1].g, faceColors[s + 1].b, faceColors[s + 1].a);
  1091. colors.push(faceColors[s + 1].r, faceColors[s + 1].g, faceColors[s + 1].b, faceColors[s + 1].a);
  1092. colors.push(faceColors[s + 2].r, faceColors[s + 2].g, faceColors[s + 2].b, faceColors[s + 2].a);
  1093. colors.push(faceColors[s + 2].r, faceColors[s + 2].g, faceColors[s + 2].b, faceColors[s + 2].a);
  1094. }
  1095. }
  1096. if (cs !== s) {
  1097. cs = s;
  1098. }
  1099. }
  1100. }
  1101. // indices
  1102. var e: number = (arc !== 1 && enclose) ? tessellation + 4 : tessellation; // correction of number of iteration if enclose
  1103. var s: number;
  1104. i = 0;
  1105. for (s = 0; s < subdivisions; s++) {
  1106. let i0: number = 0;
  1107. let i1: number = 0;
  1108. let i2: number = 0;
  1109. let i3: number = 0;
  1110. for (j = 0; j < tessellation; j++) {
  1111. i0 = i * (e + 1) + j;
  1112. i1 = (i + 1) * (e + 1) + j;
  1113. i2 = i * (e + 1) + (j + 1);
  1114. i3 = (i + 1) * (e + 1) + (j + 1);
  1115. indices.push(i0, i1, i2);
  1116. indices.push(i3, i2, i1);
  1117. }
  1118. if (arc !== 1 && enclose) { // if enclose, add two quads
  1119. indices.push(i0 + 2, i1 + 2, i2 + 2);
  1120. indices.push(i3 + 2, i2 + 2, i1 + 2);
  1121. indices.push(i0 + 4, i1 + 4, i2 + 4);
  1122. indices.push(i3 + 4, i2 + 4, i1 + 4);
  1123. }
  1124. i = (hasRings) ? (i + 2) : (i + 1);
  1125. }
  1126. // Caps
  1127. var createCylinderCap = (isTop: boolean) => {
  1128. var radius = isTop ? diameterTop / 2 : diameterBottom / 2;
  1129. if (radius === 0) {
  1130. return;
  1131. }
  1132. // Cap positions, normals & uvs
  1133. var angle;
  1134. var circleVector;
  1135. var i: number;
  1136. var u: Vector4 = (isTop) ? faceUV[surfaceNb - 1] : faceUV[0];
  1137. var c: Nullable<Color4> = null;
  1138. if (faceColors) {
  1139. c = (isTop) ? faceColors[surfaceNb - 1] : faceColors[0];
  1140. }
  1141. // cap center
  1142. var vbase = positions.length / 3;
  1143. var offset = isTop ? height / 2 : -height / 2;
  1144. var center = new Vector3(0, offset, 0);
  1145. positions.push(center.x, center.y, center.z);
  1146. normals.push(0, isTop ? 1 : -1, 0);
  1147. uvs.push(u.x + (u.z - u.x) * 0.5, u.y + (u.w - u.y) * 0.5);
  1148. if (c) {
  1149. colors.push(c.r, c.g, c.b, c.a);
  1150. }
  1151. var textureScale = new Vector2(0.5, 0.5);
  1152. for (i = 0; i <= tessellation; i++) {
  1153. angle = Math.PI * 2 * i * arc / tessellation;
  1154. var cos = Math.cos(-angle);
  1155. var sin = Math.sin(-angle);
  1156. circleVector = new Vector3(cos * radius, offset, sin * radius);
  1157. var textureCoordinate = new Vector2(cos * textureScale.x + 0.5, sin * textureScale.y + 0.5);
  1158. positions.push(circleVector.x, circleVector.y, circleVector.z);
  1159. normals.push(0, isTop ? 1 : -1, 0);
  1160. uvs.push(u.x + (u.z - u.x) * textureCoordinate.x, u.y + (u.w - u.y) * textureCoordinate.y);
  1161. if (c) {
  1162. colors.push(c.r, c.g, c.b, c.a);
  1163. }
  1164. }
  1165. // Cap indices
  1166. for (i = 0; i < tessellation; i++) {
  1167. if (!isTop) {
  1168. indices.push(vbase);
  1169. indices.push(vbase + (i + 1));
  1170. indices.push(vbase + (i + 2));
  1171. }
  1172. else {
  1173. indices.push(vbase);
  1174. indices.push(vbase + (i + 2));
  1175. indices.push(vbase + (i + 1));
  1176. }
  1177. }
  1178. };
  1179. // add caps to geometry
  1180. createCylinderCap(false);
  1181. createCylinderCap(true);
  1182. // Sides
  1183. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  1184. var vertexData = new VertexData();
  1185. vertexData.indices = indices;
  1186. vertexData.positions = positions;
  1187. vertexData.normals = normals;
  1188. vertexData.uvs = uvs;
  1189. if (faceColors) {
  1190. vertexData.colors = colors;
  1191. }
  1192. return vertexData;
  1193. }
  1194. /**
  1195. * Creates the VertexData for a torus
  1196. * @param options an object used to set the following optional parameters for the box, required but can be empty
  1197. * * diameter the diameter of the torus, optional default 1
  1198. * * thickness the diameter of the tube forming the torus, optional default 0.5
  1199. * * tessellation the number of prism sides, 3 for a triangular prism, optional, default 24
  1200. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  1201. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  1202. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  1203. * @returns the VertexData of the torus
  1204. */
  1205. public static CreateTorus(options: { diameter?: number, thickness?: number, tessellation?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }) {
  1206. var indices = [];
  1207. var positions = [];
  1208. var normals = [];
  1209. var uvs = [];
  1210. var diameter = options.diameter || 1;
  1211. var thickness = options.thickness || 0.5;
  1212. var tessellation = options.tessellation || 16;
  1213. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  1214. var stride = tessellation + 1;
  1215. for (var i = 0; i <= tessellation; i++) {
  1216. var u = i / tessellation;
  1217. var outerAngle = i * Math.PI * 2.0 / tessellation - Math.PI / 2.0;
  1218. var transform = Matrix.Translation(diameter / 2.0, 0, 0).multiply(Matrix.RotationY(outerAngle));
  1219. for (var j = 0; j <= tessellation; j++) {
  1220. var v = 1 - j / tessellation;
  1221. var innerAngle = j * Math.PI * 2.0 / tessellation + Math.PI;
  1222. var dx = Math.cos(innerAngle);
  1223. var dy = Math.sin(innerAngle);
  1224. // Create a vertex.
  1225. var normal = new Vector3(dx, dy, 0);
  1226. var position = normal.scale(thickness / 2);
  1227. var textureCoordinate = new Vector2(u, v);
  1228. position = Vector3.TransformCoordinates(position, transform);
  1229. normal = Vector3.TransformNormal(normal, transform);
  1230. positions.push(position.x, position.y, position.z);
  1231. normals.push(normal.x, normal.y, normal.z);
  1232. uvs.push(textureCoordinate.x, textureCoordinate.y);
  1233. // And create indices for two triangles.
  1234. var nextI = (i + 1) % stride;
  1235. var nextJ = (j + 1) % stride;
  1236. indices.push(i * stride + j);
  1237. indices.push(i * stride + nextJ);
  1238. indices.push(nextI * stride + j);
  1239. indices.push(i * stride + nextJ);
  1240. indices.push(nextI * stride + nextJ);
  1241. indices.push(nextI * stride + j);
  1242. }
  1243. }
  1244. // Sides
  1245. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  1246. // Result
  1247. var vertexData = new VertexData();
  1248. vertexData.indices = indices;
  1249. vertexData.positions = positions;
  1250. vertexData.normals = normals;
  1251. vertexData.uvs = uvs;
  1252. return vertexData;
  1253. }
  1254. /**
  1255. * Creates the VertexData of the LineSystem
  1256. * @param options an object used to set the following optional parameters for the LineSystem, required but can be empty
  1257. * - lines an array of lines, each line being an array of successive Vector3
  1258. * - colors an array of line colors, each of the line colors being an array of successive Color4, one per line point
  1259. * @returns the VertexData of the LineSystem
  1260. */
  1261. public static CreateLineSystem(options: { lines: Vector3[][], colors?: Nullable<Color4[][]> }): VertexData {
  1262. var indices = [];
  1263. var positions = [];
  1264. var lines = options.lines;
  1265. var colors = options.colors;
  1266. var vertexColors = [];
  1267. var idx = 0;
  1268. for (var l = 0; l < lines.length; l++) {
  1269. var points = lines[l];
  1270. for (var index = 0; index < points.length; index++) {
  1271. positions.push(points[index].x, points[index].y, points[index].z);
  1272. if (colors) {
  1273. var color = colors[l];
  1274. vertexColors.push(color[index].r, color[index].g, color[index].b, color[index].a);
  1275. }
  1276. if (index > 0) {
  1277. indices.push(idx - 1);
  1278. indices.push(idx);
  1279. }
  1280. idx++;
  1281. }
  1282. }
  1283. var vertexData = new VertexData();
  1284. vertexData.indices = indices;
  1285. vertexData.positions = positions;
  1286. if (colors) {
  1287. vertexData.colors = vertexColors;
  1288. }
  1289. return vertexData;
  1290. }
  1291. /**
  1292. * Create the VertexData for a DashedLines
  1293. * @param options an object used to set the following optional parameters for the DashedLines, required but can be empty
  1294. * - points an array successive Vector3
  1295. * - dashSize the size of the dashes relative to the dash number, optional, default 3
  1296. * - gapSize the size of the gap between two successive dashes relative to the dash number, optional, default 1
  1297. * - dashNb the intended total number of dashes, optional, default 200
  1298. * @returns the VertexData for the DashedLines
  1299. */
  1300. public static CreateDashedLines(options: { points: Vector3[], dashSize?: number, gapSize?: number, dashNb?: number }): VertexData {
  1301. var dashSize = options.dashSize || 3;
  1302. var gapSize = options.gapSize || 1;
  1303. var dashNb = options.dashNb || 200;
  1304. var points = options.points;
  1305. var positions = new Array<number>();
  1306. var indices = new Array<number>();
  1307. var curvect = Vector3.Zero();
  1308. var lg = 0;
  1309. var nb = 0;
  1310. var shft = 0;
  1311. var dashshft = 0;
  1312. var curshft = 0;
  1313. var idx = 0;
  1314. var i = 0;
  1315. for (i = 0; i < points.length - 1; i++) {
  1316. points[i + 1].subtractToRef(points[i], curvect);
  1317. lg += curvect.length();
  1318. }
  1319. shft = lg / dashNb;
  1320. dashshft = dashSize * shft / (dashSize + gapSize);
  1321. for (i = 0; i < points.length - 1; i++) {
  1322. points[i + 1].subtractToRef(points[i], curvect);
  1323. nb = Math.floor(curvect.length() / shft);
  1324. curvect.normalize();
  1325. for (var j = 0; j < nb; j++) {
  1326. curshft = shft * j;
  1327. positions.push(points[i].x + curshft * curvect.x, points[i].y + curshft * curvect.y, points[i].z + curshft * curvect.z);
  1328. positions.push(points[i].x + (curshft + dashshft) * curvect.x, points[i].y + (curshft + dashshft) * curvect.y, points[i].z + (curshft + dashshft) * curvect.z);
  1329. indices.push(idx, idx + 1);
  1330. idx += 2;
  1331. }
  1332. }
  1333. // Result
  1334. var vertexData = new VertexData();
  1335. vertexData.positions = positions;
  1336. vertexData.indices = indices;
  1337. return vertexData;
  1338. }
  1339. /**
  1340. * Creates the VertexData for a Ground
  1341. * @param options an object used to set the following optional parameters for the Ground, required but can be empty
  1342. * - width the width (x direction) of the ground, optional, default 1
  1343. * - height the height (z direction) of the ground, optional, default 1
  1344. * - subdivisions the number of subdivisions per side, optional, default 1
  1345. * @returns the VertexData of the Ground
  1346. */
  1347. public static CreateGround(options: { width?: number, height?: number, subdivisions?: number, subdivisionsX?: number, subdivisionsY?: number }): VertexData {
  1348. var indices = [];
  1349. var positions = [];
  1350. var normals = [];
  1351. var uvs = [];
  1352. var row: number, col: number;
  1353. var width: number = options.width || 1;
  1354. var height: number = options.height || 1;
  1355. var subdivisionsX: number = options.subdivisionsX || options.subdivisions || 1;
  1356. var subdivisionsY: number = options.subdivisionsY || options.subdivisions || 1;
  1357. for (row = 0; row <= subdivisionsY; row++) {
  1358. for (col = 0; col <= subdivisionsX; col++) {
  1359. var position = new Vector3((col * width) / subdivisionsX - (width / 2.0), 0, ((subdivisionsY - row) * height) / subdivisionsY - (height / 2.0));
  1360. var normal = new Vector3(0, 1.0, 0);
  1361. positions.push(position.x, position.y, position.z);
  1362. normals.push(normal.x, normal.y, normal.z);
  1363. uvs.push(col / subdivisionsX, 1.0 - row / subdivisionsY);
  1364. }
  1365. }
  1366. for (row = 0; row < subdivisionsY; row++) {
  1367. for (col = 0; col < subdivisionsX; col++) {
  1368. indices.push(col + 1 + (row + 1) * (subdivisionsX + 1));
  1369. indices.push(col + 1 + row * (subdivisionsX + 1));
  1370. indices.push(col + row * (subdivisionsX + 1));
  1371. indices.push(col + (row + 1) * (subdivisionsX + 1));
  1372. indices.push(col + 1 + (row + 1) * (subdivisionsX + 1));
  1373. indices.push(col + row * (subdivisionsX + 1));
  1374. }
  1375. }
  1376. // Result
  1377. var vertexData = new VertexData();
  1378. vertexData.indices = indices;
  1379. vertexData.positions = positions;
  1380. vertexData.normals = normals;
  1381. vertexData.uvs = uvs;
  1382. return vertexData;
  1383. }
  1384. /**
  1385. * Creates the VertexData for a TiledGround by subdividing the ground into tiles
  1386. * @param options an object used to set the following optional parameters for the Ground, required but can be empty
  1387. * * xmin the ground minimum X coordinate, optional, default -1
  1388. * * zmin the ground minimum Z coordinate, optional, default -1
  1389. * * xmax the ground maximum X coordinate, optional, default 1
  1390. * * zmax the ground maximum Z coordinate, optional, default 1
  1391. * * subdivisions a javascript object {w: positive integer, h: positive integer}, `w` and `h` are the numbers of subdivisions on the ground width and height creating 'tiles', default {w: 6, h: 6}
  1392. * * precision a javascript object {w: positive integer, h: positive integer}, `w` and `h` are the numbers of subdivisions on the tile width and height, default {w: 2, h: 2}
  1393. * @returns the VertexData of the TiledGround
  1394. */
  1395. public static CreateTiledGround(options: { xmin: number, zmin: number, xmax: number, zmax: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; } }): VertexData {
  1396. var xmin = (options.xmin !== undefined && options.xmin !== null) ? options.xmin : -1.0;
  1397. var zmin = (options.zmin !== undefined && options.zmin !== null) ? options.zmin : -1.0;
  1398. var xmax = (options.xmax !== undefined && options.xmax !== null) ? options.xmax : 1.0;
  1399. var zmax = (options.zmax !== undefined && options.zmax !== null) ? options.zmax : 1.0;
  1400. var subdivisions = options.subdivisions || { w: 1, h: 1 };
  1401. var precision = options.precision || { w: 1, h: 1 };
  1402. var indices = new Array<number>();
  1403. var positions = new Array<number>();
  1404. var normals = new Array<number>();
  1405. var uvs = new Array<number>();
  1406. var row: number, col: number, tileRow: number, tileCol: number;
  1407. subdivisions.h = (subdivisions.h < 1) ? 1 : subdivisions.h;
  1408. subdivisions.w = (subdivisions.w < 1) ? 1 : subdivisions.w;
  1409. precision.w = (precision.w < 1) ? 1 : precision.w;
  1410. precision.h = (precision.h < 1) ? 1 : precision.h;
  1411. var tileSize = {
  1412. 'w': (xmax - xmin) / subdivisions.w,
  1413. 'h': (zmax - zmin) / subdivisions.h
  1414. };
  1415. function applyTile(xTileMin: number, zTileMin: number, xTileMax: number, zTileMax: number) {
  1416. // Indices
  1417. var base = positions.length / 3;
  1418. var rowLength = precision.w + 1;
  1419. for (row = 0; row < precision.h; row++) {
  1420. for (col = 0; col < precision.w; col++) {
  1421. var square = [
  1422. base + col + row * rowLength,
  1423. base + (col + 1) + row * rowLength,
  1424. base + (col + 1) + (row + 1) * rowLength,
  1425. base + col + (row + 1) * rowLength
  1426. ];
  1427. indices.push(square[1]);
  1428. indices.push(square[2]);
  1429. indices.push(square[3]);
  1430. indices.push(square[0]);
  1431. indices.push(square[1]);
  1432. indices.push(square[3]);
  1433. }
  1434. }
  1435. // Position, normals and uvs
  1436. var position = Vector3.Zero();
  1437. var normal = new Vector3(0, 1.0, 0);
  1438. for (row = 0; row <= precision.h; row++) {
  1439. position.z = (row * (zTileMax - zTileMin)) / precision.h + zTileMin;
  1440. for (col = 0; col <= precision.w; col++) {
  1441. position.x = (col * (xTileMax - xTileMin)) / precision.w + xTileMin;
  1442. position.y = 0;
  1443. positions.push(position.x, position.y, position.z);
  1444. normals.push(normal.x, normal.y, normal.z);
  1445. uvs.push(col / precision.w, row / precision.h);
  1446. }
  1447. }
  1448. }
  1449. for (tileRow = 0; tileRow < subdivisions.h; tileRow++) {
  1450. for (tileCol = 0; tileCol < subdivisions.w; tileCol++) {
  1451. applyTile(
  1452. xmin + tileCol * tileSize.w,
  1453. zmin + tileRow * tileSize.h,
  1454. xmin + (tileCol + 1) * tileSize.w,
  1455. zmin + (tileRow + 1) * tileSize.h
  1456. );
  1457. }
  1458. }
  1459. // Result
  1460. var vertexData = new VertexData();
  1461. vertexData.indices = indices;
  1462. vertexData.positions = positions;
  1463. vertexData.normals = normals;
  1464. vertexData.uvs = uvs;
  1465. return vertexData;
  1466. }
  1467. /**
  1468. * Creates the VertexData of the Ground designed from a heightmap
  1469. * @param options an object used to set the following parameters for the Ground, required and provided by MeshBuilder.CreateGroundFromHeightMap
  1470. * * width the width (x direction) of the ground
  1471. * * height the height (z direction) of the ground
  1472. * * subdivisions the number of subdivisions per side
  1473. * * minHeight the minimum altitude on the ground, optional, default 0
  1474. * * maxHeight the maximum altitude on the ground, optional default 1
  1475. * * colorFilter the filter to apply to the image pixel colors to compute the height, optional Color3, default (0.3, 0.59, 0.11)
  1476. * * buffer the array holding the image color data
  1477. * * bufferWidth the width of image
  1478. * * bufferHeight the height of image
  1479. * @returns the VertexData of the Ground designed from a heightmap
  1480. */
  1481. public static CreateGroundFromHeightMap(options: { width: number, height: number, subdivisions: number, minHeight: number, maxHeight: number, colorFilter: Color3, buffer: Uint8Array, bufferWidth: number, bufferHeight: number }): VertexData {
  1482. var indices = [];
  1483. var positions = [];
  1484. var normals = [];
  1485. var uvs = [];
  1486. var row, col;
  1487. var filter = options.colorFilter || new Color3(0.3, 0.59, 0.11);
  1488. // Vertices
  1489. for (row = 0; row <= options.subdivisions; row++) {
  1490. for (col = 0; col <= options.subdivisions; col++) {
  1491. var position = new Vector3((col * options.width) / options.subdivisions - (options.width / 2.0), 0, ((options.subdivisions - row) * options.height) / options.subdivisions - (options.height / 2.0));
  1492. // Compute height
  1493. var heightMapX = (((position.x + options.width / 2) / options.width) * (options.bufferWidth - 1)) | 0;
  1494. var heightMapY = ((1.0 - (position.z + options.height / 2) / options.height) * (options.bufferHeight - 1)) | 0;
  1495. var pos = (heightMapX + heightMapY * options.bufferWidth) * 4;
  1496. var r = options.buffer[pos] / 255.0;
  1497. var g = options.buffer[pos + 1] / 255.0;
  1498. var b = options.buffer[pos + 2] / 255.0;
  1499. var gradient = r * filter.r + g * filter.g + b * filter.b;
  1500. position.y = options.minHeight + (options.maxHeight - options.minHeight) * gradient;
  1501. // Add vertex
  1502. positions.push(position.x, position.y, position.z);
  1503. normals.push(0, 0, 0);
  1504. uvs.push(col / options.subdivisions, 1.0 - row / options.subdivisions);
  1505. }
  1506. }
  1507. // Indices
  1508. for (row = 0; row < options.subdivisions; row++) {
  1509. for (col = 0; col < options.subdivisions; col++) {
  1510. indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
  1511. indices.push(col + 1 + row * (options.subdivisions + 1));
  1512. indices.push(col + row * (options.subdivisions + 1));
  1513. indices.push(col + (row + 1) * (options.subdivisions + 1));
  1514. indices.push(col + 1 + (row + 1) * (options.subdivisions + 1));
  1515. indices.push(col + row * (options.subdivisions + 1));
  1516. }
  1517. }
  1518. // Normals
  1519. VertexData.ComputeNormals(positions, indices, normals);
  1520. // Result
  1521. var vertexData = new VertexData();
  1522. vertexData.indices = indices;
  1523. vertexData.positions = positions;
  1524. vertexData.normals = normals;
  1525. vertexData.uvs = uvs;
  1526. return vertexData;
  1527. }
  1528. /**
  1529. * Creates the VertexData for a Plane
  1530. * @param options an object used to set the following optional parameters for the plane, required but can be empty
  1531. * * size sets the width and height of the plane to the value of size, optional default 1
  1532. * * width sets the width (x direction) of the plane, overwrites the width set by size, optional, default size
  1533. * * height sets the height (y direction) of the plane, overwrites the height set by size, optional, default size
  1534. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  1535. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  1536. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  1537. * @returns the VertexData of the box
  1538. */
  1539. public static CreatePlane(options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  1540. var indices = [];
  1541. var positions = [];
  1542. var normals = [];
  1543. var uvs = [];
  1544. var width: number = options.width || options.size || 1;
  1545. var height: number = options.height || options.size || 1;
  1546. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  1547. // Vertices
  1548. var halfWidth = width / 2.0;
  1549. var halfHeight = height / 2.0;
  1550. positions.push(-halfWidth, -halfHeight, 0);
  1551. normals.push(0, 0, -1.0);
  1552. uvs.push(0.0, 0.0);
  1553. positions.push(halfWidth, -halfHeight, 0);
  1554. normals.push(0, 0, -1.0);
  1555. uvs.push(1.0, 0.0);
  1556. positions.push(halfWidth, halfHeight, 0);
  1557. normals.push(0, 0, -1.0);
  1558. uvs.push(1.0, 1.0);
  1559. positions.push(-halfWidth, halfHeight, 0);
  1560. normals.push(0, 0, -1.0);
  1561. uvs.push(0.0, 1.0);
  1562. // Indices
  1563. indices.push(0);
  1564. indices.push(1);
  1565. indices.push(2);
  1566. indices.push(0);
  1567. indices.push(2);
  1568. indices.push(3);
  1569. // Sides
  1570. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  1571. // Result
  1572. var vertexData = new VertexData();
  1573. vertexData.indices = indices;
  1574. vertexData.positions = positions;
  1575. vertexData.normals = normals;
  1576. vertexData.uvs = uvs;
  1577. return vertexData;
  1578. }
  1579. /**
  1580. * Creates the VertexData of the Disc or regular Polygon
  1581. * @param options an object used to set the following optional parameters for the disc, required but can be empty
  1582. * * radius the radius of the disc, optional default 0.5
  1583. * * tessellation the number of polygon sides, optional, default 64
  1584. * * arc a number from 0 to 1, to create an unclosed polygon based on the fraction of the circumference given by the arc value, optional, default 1
  1585. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  1586. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  1587. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  1588. * @returns the VertexData of the box
  1589. */
  1590. public static CreateDisc(options: { radius?: number, tessellation?: number, arc?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  1591. var positions = new Array<number>();
  1592. var indices = new Array<number>();
  1593. var normals = new Array<number>();
  1594. var uvs = new Array<number>();
  1595. var radius = options.radius || 0.5;
  1596. var tessellation = options.tessellation || 64;
  1597. var arc: number = options.arc && (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
  1598. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  1599. // positions and uvs
  1600. positions.push(0, 0, 0); // disc center first
  1601. uvs.push(0.5, 0.5);
  1602. var theta = Math.PI * 2 * arc;
  1603. var step = theta / tessellation;
  1604. for (var a = 0; a < theta; a += step) {
  1605. var x = Math.cos(a);
  1606. var y = Math.sin(a);
  1607. var u = (x + 1) / 2;
  1608. var v = (1 - y) / 2;
  1609. positions.push(radius * x, radius * y, 0);
  1610. uvs.push(u, v);
  1611. }
  1612. if (arc === 1) {
  1613. positions.push(positions[3], positions[4], positions[5]); // close the circle
  1614. uvs.push(uvs[2], uvs[3]);
  1615. }
  1616. //indices
  1617. var vertexNb = positions.length / 3;
  1618. for (var i = 1; i < vertexNb - 1; i++) {
  1619. indices.push(i + 1, 0, i);
  1620. }
  1621. // result
  1622. VertexData.ComputeNormals(positions, indices, normals);
  1623. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  1624. var vertexData = new VertexData();
  1625. vertexData.indices = indices;
  1626. vertexData.positions = positions;
  1627. vertexData.normals = normals;
  1628. vertexData.uvs = uvs;
  1629. return vertexData;
  1630. }
  1631. /**
  1632. * Creates the VertexData for an irregular Polygon in the XoZ plane using a mesh built by polygonTriangulation.build()
  1633. * All parameters are provided by MeshBuilder.CreatePolygon as needed
  1634. * @param polygon a mesh built from polygonTriangulation.build()
  1635. * @param sideOrientation takes the values BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  1636. * @param fUV an array of Vector4 elements used to set different images to the top, rings and bottom respectively
  1637. * @param fColors an array of Color3 elements used to set different colors to the top, rings and bottom respectively
  1638. * @param frontUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  1639. * @param backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  1640. * @returns the VertexData of the Polygon
  1641. */
  1642. public static CreatePolygon(polygon: Mesh, sideOrientation: number, fUV?: Vector4[], fColors?: Color4[], frontUVs?: Vector4, backUVs?: Vector4) {
  1643. var faceUV: Vector4[] = fUV || new Array<Vector4>(3);
  1644. var faceColors = fColors;
  1645. var colors = [];
  1646. // default face colors and UV if undefined
  1647. for (var f = 0; f < 3; f++) {
  1648. if (faceUV[f] === undefined) {
  1649. faceUV[f] = new Vector4(0, 0, 1, 1);
  1650. }
  1651. if (faceColors && faceColors[f] === undefined) {
  1652. faceColors[f] = new Color4(1, 1, 1, 1);
  1653. }
  1654. }
  1655. var positions = <FloatArray>polygon.getVerticesData(VertexBuffer.PositionKind);
  1656. var normals = <FloatArray>polygon.getVerticesData(VertexBuffer.NormalKind);
  1657. var uvs = <FloatArray>polygon.getVerticesData(VertexBuffer.UVKind);
  1658. var indices = <IndicesArray>polygon.getIndices();
  1659. // set face colours and textures
  1660. var idx: number = 0;
  1661. var face: number = 0;
  1662. for (var index = 0; index < normals.length; index += 3) {
  1663. //Edge Face no. 1
  1664. if (Math.abs(normals[index + 1]) < 0.001) {
  1665. face = 1;
  1666. }
  1667. //Top Face no. 0
  1668. if (Math.abs(normals[index + 1] - 1) < 0.001) {
  1669. face = 0;
  1670. }
  1671. //Bottom Face no. 2
  1672. if (Math.abs(normals[index + 1] + 1) < 0.001) {
  1673. face = 2;
  1674. }
  1675. idx = index / 3;
  1676. uvs[2 * idx] = (1 - uvs[2 * idx]) * faceUV[face].x + uvs[2 * idx] * faceUV[face].z;
  1677. uvs[2 * idx + 1] = (1 - uvs[2 * idx + 1]) * faceUV[face].y + uvs[2 * idx + 1] * faceUV[face].w;
  1678. if (faceColors) {
  1679. colors.push(faceColors[face].r, faceColors[face].g, faceColors[face].b, faceColors[face].a);
  1680. }
  1681. }
  1682. // sides
  1683. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, frontUVs, backUVs);
  1684. // Result
  1685. var vertexData = new VertexData();
  1686. vertexData.indices = indices;
  1687. vertexData.positions = positions;
  1688. vertexData.normals = normals;
  1689. vertexData.uvs = uvs;
  1690. if (faceColors) {
  1691. var totalColors = (sideOrientation === Mesh.DOUBLESIDE) ? colors.concat(colors) : colors;
  1692. vertexData.colors = totalColors;
  1693. }
  1694. return vertexData;
  1695. }
  1696. /**
  1697. * Creates the VertexData of the IcoSphere
  1698. * @param options an object used to set the following optional parameters for the IcoSphere, required but can be empty
  1699. * * radius the radius of the IcoSphere, optional default 1
  1700. * * radiusX allows stretching in the x direction, optional, default radius
  1701. * * radiusY allows stretching in the y direction, optional, default radius
  1702. * * radiusZ allows stretching in the z direction, optional, default radius
  1703. * * flat when true creates a flat shaded mesh, optional, default true
  1704. * * subdivisions increasing the subdivisions increases the number of faces, optional, default 4
  1705. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  1706. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  1707. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  1708. * @returns the VertexData of the IcoSphere
  1709. */
  1710. public static CreateIcoSphere(options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  1711. var sideOrientation = options.sideOrientation || Mesh.DEFAULTSIDE;
  1712. var radius = options.radius || 1;
  1713. var flat = (options.flat === undefined) ? true : options.flat;
  1714. var subdivisions = options.subdivisions || 4;
  1715. var radiusX = options.radiusX || radius;
  1716. var radiusY = options.radiusY || radius;
  1717. var radiusZ = options.radiusZ || radius;
  1718. var t = (1 + Math.sqrt(5)) / 2;
  1719. // 12 vertex x,y,z
  1720. var ico_vertices = [
  1721. -1, t, -0, 1, t, 0, -1, -t, 0, 1, -t, 0, // v0-3
  1722. 0, -1, -t, 0, 1, -t, 0, -1, t, 0, 1, t, // v4-7
  1723. t, 0, 1, t, 0, -1, -t, 0, 1, -t, 0, -1 // v8-11
  1724. ];
  1725. // index of 3 vertex makes a face of icopshere
  1726. var ico_indices = [
  1727. 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 12, 22, 23,
  1728. 1, 5, 20, 5, 11, 4, 23, 22, 13, 22, 18, 6, 7, 1, 8,
  1729. 14, 21, 4, 14, 4, 2, 16, 13, 6, 15, 6, 19, 3, 8, 9,
  1730. 4, 21, 5, 13, 17, 23, 6, 13, 22, 19, 6, 18, 9, 8, 1
  1731. ];
  1732. // vertex for uv have aliased position, not for UV
  1733. var vertices_unalias_id = [
  1734. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  1735. // vertex alias
  1736. 0, // 12: 0 + 12
  1737. 2, // 13: 2 + 11
  1738. 3, // 14: 3 + 11
  1739. 3, // 15: 3 + 12
  1740. 3, // 16: 3 + 13
  1741. 4, // 17: 4 + 13
  1742. 7, // 18: 7 + 11
  1743. 8, // 19: 8 + 11
  1744. 9, // 20: 9 + 11
  1745. 9, // 21: 9 + 12
  1746. 10, // 22: A + 12
  1747. 11 // 23: B + 12
  1748. ];
  1749. // uv as integer step (not pixels !)
  1750. var ico_vertexuv = [
  1751. 5, 1, 3, 1, 6, 4, 0, 0, // v0-3
  1752. 5, 3, 4, 2, 2, 2, 4, 0, // v4-7
  1753. 2, 0, 1, 1, 6, 0, 6, 2, // v8-11
  1754. // vertex alias (for same vertex on different faces)
  1755. 0, 4, // 12: 0 + 12
  1756. 3, 3, // 13: 2 + 11
  1757. 4, 4, // 14: 3 + 11
  1758. 3, 1, // 15: 3 + 12
  1759. 4, 2, // 16: 3 + 13
  1760. 4, 4, // 17: 4 + 13
  1761. 0, 2, // 18: 7 + 11
  1762. 1, 1, // 19: 8 + 11
  1763. 2, 2, // 20: 9 + 11
  1764. 3, 3, // 21: 9 + 12
  1765. 1, 3, // 22: A + 12
  1766. 2, 4 // 23: B + 12
  1767. ];
  1768. // Vertices[0, 1, ...9, A, B] : position on UV plane
  1769. // '+' indicate duplicate position to be fixed (3,9:0,2,3,4,7,8,A,B)
  1770. // First island of uv mapping
  1771. // v = 4h 3+ 2
  1772. // v = 3h 9+ 4
  1773. // v = 2h 9+ 5 B
  1774. // v = 1h 9 1 0
  1775. // v = 0h 3 8 7 A
  1776. // u = 0 1 2 3 4 5 6 *a
  1777. // Second island of uv mapping
  1778. // v = 4h 0+ B+ 4+
  1779. // v = 3h A+ 2+
  1780. // v = 2h 7+ 6 3+
  1781. // v = 1h 8+ 3+
  1782. // v = 0h
  1783. // u = 0 1 2 3 4 5 6 *a
  1784. // Face layout on texture UV mapping
  1785. // ============
  1786. // \ 4 /\ 16 / ======
  1787. // \ / \ / /\ 11 /
  1788. // \/ 7 \/ / \ /
  1789. // ======= / 10 \/
  1790. // /\ 17 /\ =======
  1791. // / \ / \ \ 15 /\
  1792. // / 8 \/ 12 \ \ / \
  1793. // ============ \/ 6 \
  1794. // \ 18 /\ ============
  1795. // \ / \ \ 5 /\ 0 /
  1796. // \/ 13 \ \ / \ /
  1797. // ======= \/ 1 \/
  1798. // =============
  1799. // /\ 19 /\ 2 /\
  1800. // / \ / \ / \
  1801. // / 14 \/ 9 \/ 3 \
  1802. // ===================
  1803. // uv step is u:1 or 0.5, v:cos(30)=sqrt(3)/2, ratio approx is 84/97
  1804. var ustep = 138 / 1024;
  1805. var vstep = 239 / 1024;
  1806. var uoffset = 60 / 1024;
  1807. var voffset = 26 / 1024;
  1808. // Second island should have margin, not to touch the first island
  1809. // avoid any borderline artefact in pixel rounding
  1810. var island_u_offset = -40 / 1024;
  1811. var island_v_offset = +20 / 1024;
  1812. // face is either island 0 or 1 :
  1813. // second island is for faces : [4, 7, 8, 12, 13, 16, 17, 18]
  1814. var island = [
  1815. 0, 0, 0, 0, 1, // 0 - 4
  1816. 0, 0, 1, 1, 0, // 5 - 9
  1817. 0, 0, 1, 1, 0, // 10 - 14
  1818. 0, 1, 1, 1, 0 // 15 - 19
  1819. ];
  1820. var indices = new Array<number>();
  1821. var positions = new Array<number>();
  1822. var normals = new Array<number>();
  1823. var uvs = new Array<number>();
  1824. var current_indice = 0;
  1825. // prepare array of 3 vector (empty) (to be worked in place, shared for each face)
  1826. var face_vertex_pos = new Array(3);
  1827. var face_vertex_uv = new Array(3);
  1828. var v012;
  1829. for (v012 = 0; v012 < 3; v012++) {
  1830. face_vertex_pos[v012] = Vector3.Zero();
  1831. face_vertex_uv[v012] = Vector2.Zero();
  1832. }
  1833. // create all with normals
  1834. for (var face = 0; face < 20; face++) {
  1835. // 3 vertex per face
  1836. for (v012 = 0; v012 < 3; v012++) {
  1837. // look up vertex 0,1,2 to its index in 0 to 11 (or 23 including alias)
  1838. var v_id = ico_indices[3 * face + v012];
  1839. // vertex have 3D position (x,y,z)
  1840. face_vertex_pos[v012].copyFromFloats(
  1841. ico_vertices[3 * vertices_unalias_id[v_id]],
  1842. ico_vertices[3 * vertices_unalias_id[v_id] + 1],
  1843. ico_vertices[3 * vertices_unalias_id[v_id] + 2]);
  1844. // Normalize to get normal, then scale to radius
  1845. face_vertex_pos[v012].normalize().scaleInPlace(radius);
  1846. // uv Coordinates from vertex ID
  1847. face_vertex_uv[v012].copyFromFloats(
  1848. ico_vertexuv[2 * v_id] * ustep + uoffset + island[face] * island_u_offset,
  1849. ico_vertexuv[2 * v_id + 1] * vstep + voffset + island[face] * island_v_offset);
  1850. }
  1851. // Subdivide the face (interpolate pos, norm, uv)
  1852. // - pos is linear interpolation, then projected to sphere (converge polyhedron to sphere)
  1853. // - norm is linear interpolation of vertex corner normal
  1854. // (to be checked if better to re-calc from face vertex, or if approximation is OK ??? )
  1855. // - uv is linear interpolation
  1856. //
  1857. // Topology is as below for sub-divide by 2
  1858. // vertex shown as v0,v1,v2
  1859. // interp index is i1 to progress in range [v0,v1[
  1860. // interp index is i2 to progress in range [v0,v2[
  1861. // face index as (i1,i2) for /\ : (i1,i2),(i1+1,i2),(i1,i2+1)
  1862. // and (i1,i2)' for \/ : (i1+1,i2),(i1+1,i2+1),(i1,i2+1)
  1863. //
  1864. //
  1865. // i2 v2
  1866. // ^ ^
  1867. // / / \
  1868. // / / \
  1869. // / / \
  1870. // / / (0,1) \
  1871. // / #---------\
  1872. // / / \ (0,0)'/ \
  1873. // / / \ / \
  1874. // / / \ / \
  1875. // / / (0,0) \ / (1,0) \
  1876. // / #---------#---------\
  1877. // v0 v1
  1878. //
  1879. // --------------------> i1
  1880. //
  1881. // interp of (i1,i2):
  1882. // along i2 : x0=lerp(v0,v2, i2/S) <---> x1=lerp(v1,v2, i2/S)
  1883. // along i1 : lerp(x0,x1, i1/(S-i2))
  1884. //
  1885. // centroid of triangle is needed to get help normal computation
  1886. // (c1,c2) are used for centroid location
  1887. var interp_vertex = (i1: number, i2: number, c1: number, c2: number) => {
  1888. // vertex is interpolated from
  1889. // - face_vertex_pos[0..2]
  1890. // - face_vertex_uv[0..2]
  1891. var pos_x0 = Vector3.Lerp(face_vertex_pos[0], face_vertex_pos[2], i2 / subdivisions);
  1892. var pos_x1 = Vector3.Lerp(face_vertex_pos[1], face_vertex_pos[2], i2 / subdivisions);
  1893. var pos_interp = (subdivisions === i2) ? face_vertex_pos[2] : Vector3.Lerp(pos_x0, pos_x1, i1 / (subdivisions - i2));
  1894. pos_interp.normalize();
  1895. var vertex_normal;
  1896. if (flat) {
  1897. // in flat mode, recalculate normal as face centroid normal
  1898. var centroid_x0 = Vector3.Lerp(face_vertex_pos[0], face_vertex_pos[2], c2 / subdivisions);
  1899. var centroid_x1 = Vector3.Lerp(face_vertex_pos[1], face_vertex_pos[2], c2 / subdivisions);
  1900. vertex_normal = Vector3.Lerp(centroid_x0, centroid_x1, c1 / (subdivisions - c2));
  1901. } else {
  1902. // in smooth mode, recalculate normal from each single vertex position
  1903. vertex_normal = new Vector3(pos_interp.x, pos_interp.y, pos_interp.z);
  1904. }
  1905. // Vertex normal need correction due to X,Y,Z radius scaling
  1906. vertex_normal.x /= radiusX;
  1907. vertex_normal.y /= radiusY;
  1908. vertex_normal.z /= radiusZ;
  1909. vertex_normal.normalize();
  1910. var uv_x0 = Vector2.Lerp(face_vertex_uv[0], face_vertex_uv[2], i2 / subdivisions);
  1911. var uv_x1 = Vector2.Lerp(face_vertex_uv[1], face_vertex_uv[2], i2 / subdivisions);
  1912. var uv_interp = (subdivisions === i2) ? face_vertex_uv[2] : Vector2.Lerp(uv_x0, uv_x1, i1 / (subdivisions - i2));
  1913. positions.push(pos_interp.x * radiusX, pos_interp.y * radiusY, pos_interp.z * radiusZ);
  1914. normals.push(vertex_normal.x, vertex_normal.y, vertex_normal.z);
  1915. uvs.push(uv_interp.x, uv_interp.y);
  1916. // push each vertex has member of a face
  1917. // Same vertex can bleong to multiple face, it is pushed multiple time (duplicate vertex are present)
  1918. indices.push(current_indice);
  1919. current_indice++;
  1920. }
  1921. for (var i2 = 0; i2 < subdivisions; i2++) {
  1922. for (var i1 = 0; i1 + i2 < subdivisions; i1++) {
  1923. // face : (i1,i2) for /\ :
  1924. // interp for : (i1,i2),(i1+1,i2),(i1,i2+1)
  1925. interp_vertex(i1, i2, i1 + 1.0 / 3, i2 + 1.0 / 3);
  1926. interp_vertex(i1 + 1, i2, i1 + 1.0 / 3, i2 + 1.0 / 3);
  1927. interp_vertex(i1, i2 + 1, i1 + 1.0 / 3, i2 + 1.0 / 3);
  1928. if (i1 + i2 + 1 < subdivisions) {
  1929. // face : (i1,i2)' for \/ :
  1930. // interp for (i1+1,i2),(i1+1,i2+1),(i1,i2+1)
  1931. interp_vertex(i1 + 1, i2, i1 + 2.0 / 3, i2 + 2.0 / 3);
  1932. interp_vertex(i1 + 1, i2 + 1, i1 + 2.0 / 3, i2 + 2.0 / 3);
  1933. interp_vertex(i1, i2 + 1, i1 + 2.0 / 3, i2 + 2.0 / 3);
  1934. }
  1935. }
  1936. }
  1937. }
  1938. // Sides
  1939. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  1940. // Result
  1941. var vertexData = new VertexData();
  1942. vertexData.indices = indices;
  1943. vertexData.positions = positions;
  1944. vertexData.normals = normals;
  1945. vertexData.uvs = uvs;
  1946. return vertexData;
  1947. }
  1948. // inspired from // http://stemkoski.github.io/Three.js/Polyhedra.html
  1949. /**
  1950. * Creates the VertexData for a Polyhedron
  1951. * @param options an object used to set the following optional parameters for the polyhedron, required but can be empty
  1952. * * type provided types are:
  1953. * * 0 : Tetrahedron, 1 : Octahedron, 2 : Dodecahedron, 3 : Icosahedron, 4 : Rhombicuboctahedron, 5 : Triangular Prism, 6 : Pentagonal Prism, 7 : Hexagonal Prism, 8 : Square Pyramid (J1)
  1954. * * 9 : Pentagonal Pyramid (J2), 10 : Triangular Dipyramid (J12), 11 : Pentagonal Dipyramid (J13), 12 : Elongated Square Dipyramid (J15), 13 : Elongated Pentagonal Dipyramid (J16), 14 : Elongated Pentagonal Cupola (J20)
  1955. * * size the size of the IcoSphere, optional default 1
  1956. * * sizeX allows stretching in the x direction, optional, default size
  1957. * * sizeY allows stretching in the y direction, optional, default size
  1958. * * sizeZ allows stretching in the z direction, optional, default size
  1959. * * custom a number that overwrites the type to create from an extended set of polyhedron from https://www.babylonjs-playground.com/#21QRSK#15 with minimised editor
  1960. * * faceUV an array of Vector4 elements used to set different images to the top, rings and bottom respectively
  1961. * * faceColors an array of Color3 elements used to set different colors to the top, rings and bottom respectively
  1962. * * flat when true creates a flat shaded mesh, optional, default true
  1963. * * subdivisions increasing the subdivisions increases the number of faces, optional, default 4
  1964. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  1965. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  1966. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  1967. * @returns the VertexData of the Polyhedron
  1968. */
  1969. public static CreatePolyhedron(options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  1970. // provided polyhedron types :
  1971. // 0 : Tetrahedron, 1 : Octahedron, 2 : Dodecahedron, 3 : Icosahedron, 4 : Rhombicuboctahedron, 5 : Triangular Prism, 6 : Pentagonal Prism, 7 : Hexagonal Prism, 8 : Square Pyramid (J1)
  1972. // 9 : Pentagonal Pyramid (J2), 10 : Triangular Dipyramid (J12), 11 : Pentagonal Dipyramid (J13), 12 : Elongated Square Dipyramid (J15), 13 : Elongated Pentagonal Dipyramid (J16), 14 : Elongated Pentagonal Cupola (J20)
  1973. var polyhedra: { vertex: number[][], face: number[][] }[] = [];
  1974. polyhedra[0] = { vertex: [[0, 0, 1.732051], [1.632993, 0, -0.5773503], [-0.8164966, 1.414214, -0.5773503], [-0.8164966, -1.414214, -0.5773503]], face: [[0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 3, 2]] };
  1975. polyhedra[1] = { vertex: [[0, 0, 1.414214], [1.414214, 0, 0], [0, 1.414214, 0], [-1.414214, 0, 0], [0, -1.414214, 0], [0, 0, -1.414214]], face: [[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [3, 5, 4]] };
  1976. polyhedra[2] = {
  1977. vertex: [[0, 0, 1.070466], [0.7136442, 0, 0.7978784], [-0.3568221, 0.618034, 0.7978784], [-0.3568221, -0.618034, 0.7978784], [0.7978784, 0.618034, 0.3568221], [0.7978784, -0.618034, 0.3568221], [-0.9341724, 0.381966, 0.3568221], [0.1362939, 1, 0.3568221], [0.1362939, -1, 0.3568221], [-0.9341724, -0.381966, 0.3568221], [0.9341724, 0.381966, -0.3568221], [0.9341724, -0.381966, -0.3568221], [-0.7978784, 0.618034, -0.3568221], [-0.1362939, 1, -0.3568221], [-0.1362939, -1, -0.3568221], [-0.7978784, -0.618034, -0.3568221], [0.3568221, 0.618034, -0.7978784], [0.3568221, -0.618034, -0.7978784], [-0.7136442, 0, -0.7978784], [0, 0, -1.070466]],
  1978. face: [[0, 1, 4, 7, 2], [0, 2, 6, 9, 3], [0, 3, 8, 5, 1], [1, 5, 11, 10, 4], [2, 7, 13, 12, 6], [3, 9, 15, 14, 8], [4, 10, 16, 13, 7], [5, 8, 14, 17, 11], [6, 12, 18, 15, 9], [10, 11, 17, 19, 16], [12, 13, 16, 19, 18], [14, 15, 18, 19, 17]]
  1979. };
  1980. polyhedra[3] = {
  1981. vertex: [[0, 0, 1.175571], [1.051462, 0, 0.5257311], [0.3249197, 1, 0.5257311], [-0.8506508, 0.618034, 0.5257311], [-0.8506508, -0.618034, 0.5257311], [0.3249197, -1, 0.5257311], [0.8506508, 0.618034, -0.5257311], [0.8506508, -0.618034, -0.5257311], [-0.3249197, 1, -0.5257311], [-1.051462, 0, -0.5257311], [-0.3249197, -1, -0.5257311], [0, 0, -1.175571]],
  1982. face: [[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 5, 7], [1, 7, 6], [1, 6, 2], [2, 6, 8], [2, 8, 3], [3, 8, 9], [3, 9, 4], [4, 9, 10], [4, 10, 5], [5, 10, 7], [6, 7, 11], [6, 11, 8], [7, 10, 11], [8, 11, 9], [9, 11, 10]]
  1983. };
  1984. polyhedra[4] = {
  1985. vertex: [[0, 0, 1.070722], [0.7148135, 0, 0.7971752], [-0.104682, 0.7071068, 0.7971752], [-0.6841528, 0.2071068, 0.7971752], [-0.104682, -0.7071068, 0.7971752], [0.6101315, 0.7071068, 0.5236279], [1.04156, 0.2071068, 0.1367736], [0.6101315, -0.7071068, 0.5236279], [-0.3574067, 1, 0.1367736], [-0.7888348, -0.5, 0.5236279], [-0.9368776, 0.5, 0.1367736], [-0.3574067, -1, 0.1367736], [0.3574067, 1, -0.1367736], [0.9368776, -0.5, -0.1367736], [0.7888348, 0.5, -0.5236279], [0.3574067, -1, -0.1367736], [-0.6101315, 0.7071068, -0.5236279], [-1.04156, -0.2071068, -0.1367736], [-0.6101315, -0.7071068, -0.5236279], [0.104682, 0.7071068, -0.7971752], [0.6841528, -0.2071068, -0.7971752], [0.104682, -0.7071068, -0.7971752], [-0.7148135, 0, -0.7971752], [0, 0, -1.070722]],
  1986. face: [[0, 2, 3], [1, 6, 5], [4, 9, 11], [7, 15, 13], [8, 16, 10], [12, 14, 19], [17, 22, 18], [20, 21, 23], [0, 1, 5, 2], [0, 3, 9, 4], [0, 4, 7, 1], [1, 7, 13, 6], [2, 5, 12, 8], [2, 8, 10, 3], [3, 10, 17, 9], [4, 11, 15, 7], [5, 6, 14, 12], [6, 13, 20, 14], [8, 12, 19, 16], [9, 17, 18, 11], [10, 16, 22, 17], [11, 18, 21, 15], [13, 15, 21, 20], [14, 20, 23, 19], [16, 19, 23, 22], [18, 22, 23, 21]]
  1987. };
  1988. polyhedra[5] = { vertex: [[0, 0, 1.322876], [1.309307, 0, 0.1889822], [-0.9819805, 0.8660254, 0.1889822], [0.1636634, -1.299038, 0.1889822], [0.3273268, 0.8660254, -0.9449112], [-0.8183171, -0.4330127, -0.9449112]], face: [[0, 3, 1], [2, 4, 5], [0, 1, 4, 2], [0, 2, 5, 3], [1, 3, 5, 4]] };
  1989. polyhedra[6] = { vertex: [[0, 0, 1.159953], [1.013464, 0, 0.5642542], [-0.3501431, 0.9510565, 0.5642542], [-0.7715208, -0.6571639, 0.5642542], [0.6633206, 0.9510565, -0.03144481], [0.8682979, -0.6571639, -0.3996071], [-1.121664, 0.2938926, -0.03144481], [-0.2348831, -1.063314, -0.3996071], [0.5181548, 0.2938926, -0.9953061], [-0.5850262, -0.112257, -0.9953061]], face: [[0, 1, 4, 2], [0, 2, 6, 3], [1, 5, 8, 4], [3, 6, 9, 7], [5, 7, 9, 8], [0, 3, 7, 5, 1], [2, 4, 8, 9, 6]] };
  1990. polyhedra[7] = { vertex: [[0, 0, 1.118034], [0.8944272, 0, 0.6708204], [-0.2236068, 0.8660254, 0.6708204], [-0.7826238, -0.4330127, 0.6708204], [0.6708204, 0.8660254, 0.2236068], [1.006231, -0.4330127, -0.2236068], [-1.006231, 0.4330127, 0.2236068], [-0.6708204, -0.8660254, -0.2236068], [0.7826238, 0.4330127, -0.6708204], [0.2236068, -0.8660254, -0.6708204], [-0.8944272, 0, -0.6708204], [0, 0, -1.118034]], face: [[0, 1, 4, 2], [0, 2, 6, 3], [1, 5, 8, 4], [3, 6, 10, 7], [5, 9, 11, 8], [7, 10, 11, 9], [0, 3, 7, 9, 5, 1], [2, 4, 8, 11, 10, 6]] };
  1991. polyhedra[8] = { vertex: [[-0.729665, 0.670121, 0.319155], [-0.655235, -0.29213, -0.754096], [-0.093922, -0.607123, 0.537818], [0.702196, 0.595691, 0.485187], [0.776626, -0.36656, -0.588064]], face: [[1, 4, 2], [0, 1, 2], [3, 0, 2], [4, 3, 2], [4, 1, 0, 3]] };
  1992. polyhedra[9] = { vertex: [[-0.868849, -0.100041, 0.61257], [-0.329458, 0.976099, 0.28078], [-0.26629, -0.013796, -0.477654], [-0.13392, -1.034115, 0.229829], [0.738834, 0.707117, -0.307018], [0.859683, -0.535264, -0.338508]], face: [[3, 0, 2], [5, 3, 2], [4, 5, 2], [1, 4, 2], [0, 1, 2], [0, 3, 5, 4, 1]] };
  1993. polyhedra[10] = { vertex: [[-0.610389, 0.243975, 0.531213], [-0.187812, -0.48795, -0.664016], [-0.187812, 0.9759, -0.664016], [0.187812, -0.9759, 0.664016], [0.798201, 0.243975, 0.132803]], face: [[1, 3, 0], [3, 4, 0], [3, 1, 4], [0, 2, 1], [0, 4, 2], [2, 4, 1]] };
  1994. polyhedra[11] = { vertex: [[-1.028778, 0.392027, -0.048786], [-0.640503, -0.646161, 0.621837], [-0.125162, -0.395663, -0.540059], [0.004683, 0.888447, -0.651988], [0.125161, 0.395663, 0.540059], [0.632925, -0.791376, 0.433102], [1.031672, 0.157063, -0.354165]], face: [[3, 2, 0], [2, 1, 0], [2, 5, 1], [0, 4, 3], [0, 1, 4], [4, 1, 5], [2, 3, 6], [3, 4, 6], [5, 2, 6], [4, 5, 6]] };
  1995. polyhedra[12] = { vertex: [[-0.669867, 0.334933, -0.529576], [-0.669867, 0.334933, 0.529577], [-0.4043, 1.212901, 0], [-0.334933, -0.669867, -0.529576], [-0.334933, -0.669867, 0.529577], [0.334933, 0.669867, -0.529576], [0.334933, 0.669867, 0.529577], [0.4043, -1.212901, 0], [0.669867, -0.334933, -0.529576], [0.669867, -0.334933, 0.529577]], face: [[8, 9, 7], [6, 5, 2], [3, 8, 7], [5, 0, 2], [4, 3, 7], [0, 1, 2], [9, 4, 7], [1, 6, 2], [9, 8, 5, 6], [8, 3, 0, 5], [3, 4, 1, 0], [4, 9, 6, 1]] };
  1996. polyhedra[13] = { vertex: [[-0.931836, 0.219976, -0.264632], [-0.636706, 0.318353, 0.692816], [-0.613483, -0.735083, -0.264632], [-0.326545, 0.979634, 0], [-0.318353, -0.636706, 0.692816], [-0.159176, 0.477529, -0.856368], [0.159176, -0.477529, -0.856368], [0.318353, 0.636706, 0.692816], [0.326545, -0.979634, 0], [0.613482, 0.735082, -0.264632], [0.636706, -0.318353, 0.692816], [0.931835, -0.219977, -0.264632]], face: [[11, 10, 8], [7, 9, 3], [6, 11, 8], [9, 5, 3], [2, 6, 8], [5, 0, 3], [4, 2, 8], [0, 1, 3], [10, 4, 8], [1, 7, 3], [10, 11, 9, 7], [11, 6, 5, 9], [6, 2, 0, 5], [2, 4, 1, 0], [4, 10, 7, 1]] };
  1997. polyhedra[14] = {
  1998. vertex: [[-0.93465, 0.300459, -0.271185], [-0.838689, -0.260219, -0.516017], [-0.711319, 0.717591, 0.128359], [-0.710334, -0.156922, 0.080946], [-0.599799, 0.556003, -0.725148], [-0.503838, -0.004675, -0.969981], [-0.487004, 0.26021, 0.48049], [-0.460089, -0.750282, -0.512622], [-0.376468, 0.973135, -0.325605], [-0.331735, -0.646985, 0.084342], [-0.254001, 0.831847, 0.530001], [-0.125239, -0.494738, -0.966586], [0.029622, 0.027949, 0.730817], [0.056536, -0.982543, -0.262295], [0.08085, 1.087391, 0.076037], [0.125583, -0.532729, 0.485984], [0.262625, 0.599586, 0.780328], [0.391387, -0.726999, -0.716259], [0.513854, -0.868287, 0.139347], [0.597475, 0.85513, 0.326364], [0.641224, 0.109523, 0.783723], [0.737185, -0.451155, 0.538891], [0.848705, -0.612742, -0.314616], [0.976075, 0.365067, 0.32976], [1.072036, -0.19561, 0.084927]],
  1999. face: [[15, 18, 21], [12, 20, 16], [6, 10, 2], [3, 0, 1], [9, 7, 13], [2, 8, 4, 0], [0, 4, 5, 1], [1, 5, 11, 7], [7, 11, 17, 13], [13, 17, 22, 18], [18, 22, 24, 21], [21, 24, 23, 20], [20, 23, 19, 16], [16, 19, 14, 10], [10, 14, 8, 2], [15, 9, 13, 18], [12, 15, 21, 20], [6, 12, 16, 10], [3, 6, 2, 0], [9, 3, 1, 7], [9, 15, 12, 6, 3], [22, 17, 11, 5, 4, 8, 14, 19, 23, 24]]
  2000. };
  2001. var type: number = options.type && (options.type < 0 || options.type >= polyhedra.length) ? 0 : options.type || 0;
  2002. var size = options.size;
  2003. var sizeX: number = options.sizeX || size || 1;
  2004. var sizeY: number = options.sizeY || size || 1;
  2005. var sizeZ: number = options.sizeZ || size || 1;
  2006. var data: { vertex: number[][], face: number[][], name?: string, category?: string } = options.custom || polyhedra[type];
  2007. var nbfaces = data.face.length;
  2008. var faceUV = options.faceUV || new Array(nbfaces);
  2009. var faceColors = options.faceColors;
  2010. var flat = (options.flat === undefined) ? true : options.flat;
  2011. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  2012. var positions = new Array<number>();
  2013. var indices = new Array<number>();
  2014. var normals = new Array<number>();
  2015. var uvs = new Array<number>();
  2016. var colors = new Array<number>();
  2017. var index = 0;
  2018. var faceIdx = 0; // face cursor in the array "indexes"
  2019. var indexes = new Array<number>();
  2020. var i = 0;
  2021. var f = 0;
  2022. var u: number, v: number, ang: number, x: number, y: number, tmp: number;
  2023. // default face colors and UV if undefined
  2024. if (flat) {
  2025. for (f = 0; f < nbfaces; f++) {
  2026. if (faceColors && faceColors[f] === undefined) {
  2027. faceColors[f] = new Color4(1, 1, 1, 1);
  2028. }
  2029. if (faceUV && faceUV[f] === undefined) {
  2030. faceUV[f] = new Vector4(0, 0, 1, 1);
  2031. }
  2032. }
  2033. }
  2034. if (!flat) {
  2035. for (i = 0; i < data.vertex.length; i++) {
  2036. positions.push(data.vertex[i][0] * sizeX, data.vertex[i][1] * sizeY, data.vertex[i][2] * sizeZ);
  2037. uvs.push(0, 0);
  2038. }
  2039. for (f = 0; f < nbfaces; f++) {
  2040. for (i = 0; i < data.face[f].length - 2; i++) {
  2041. indices.push(data.face[f][0], data.face[f][i + 2], data.face[f][i + 1]);
  2042. }
  2043. }
  2044. } else {
  2045. for (f = 0; f < nbfaces; f++) {
  2046. var fl = data.face[f].length; // number of vertices of the current face
  2047. ang = 2 * Math.PI / fl;
  2048. x = 0.5 * Math.tan(ang / 2);
  2049. y = 0.5;
  2050. // positions, uvs, colors
  2051. for (i = 0; i < fl; i++) {
  2052. // positions
  2053. positions.push(data.vertex[data.face[f][i]][0] * sizeX, data.vertex[data.face[f][i]][1] * sizeY, data.vertex[data.face[f][i]][2] * sizeZ);
  2054. indexes.push(index);
  2055. index++;
  2056. // uvs
  2057. u = faceUV[f].x + (faceUV[f].z - faceUV[f].x) * (0.5 + x);
  2058. v = faceUV[f].y + (faceUV[f].w - faceUV[f].y) * (y - 0.5);
  2059. uvs.push(u, v);
  2060. tmp = x * Math.cos(ang) - y * Math.sin(ang);
  2061. y = x * Math.sin(ang) + y * Math.cos(ang);
  2062. x = tmp;
  2063. // colors
  2064. if (faceColors) {
  2065. colors.push(faceColors[f].r, faceColors[f].g, faceColors[f].b, faceColors[f].a);
  2066. }
  2067. }
  2068. // indices from indexes
  2069. for (i = 0; i < fl - 2; i++) {
  2070. indices.push(indexes[0 + faceIdx], indexes[i + 2 + faceIdx], indexes[i + 1 + faceIdx]);
  2071. }
  2072. faceIdx += fl;
  2073. }
  2074. }
  2075. VertexData.ComputeNormals(positions, indices, normals);
  2076. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  2077. var vertexData = new VertexData();
  2078. vertexData.positions = positions;
  2079. vertexData.indices = indices;
  2080. vertexData.normals = normals;
  2081. vertexData.uvs = uvs;
  2082. if (faceColors && flat) {
  2083. vertexData.colors = colors;
  2084. }
  2085. return vertexData;
  2086. }
  2087. // based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
  2088. /**
  2089. * Creates the VertexData for a TorusKnot
  2090. * @param options an object used to set the following optional parameters for the TorusKnot, required but can be empty
  2091. * * radius the radius of the torus knot, optional, default 2
  2092. * * tube the thickness of the tube, optional, default 0.5
  2093. * * radialSegments the number of sides on each tube segments, optional, default 32
  2094. * * tubularSegments the number of tubes to decompose the knot into, optional, default 32
  2095. * * p the number of windings around the z axis, optional, default 2
  2096. * * q the number of windings around the x axis, optional, default 3
  2097. * * sideOrientation optional and takes the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  2098. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  2099. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  2100. * @returns the VertexData of the Torus Knot
  2101. */
  2102. public static CreateTorusKnot(options: { radius?: number, tube?: number, radialSegments?: number, tubularSegments?: number, p?: number, q?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
  2103. var indices = new Array<number>();
  2104. var positions = new Array<number>();
  2105. var normals = new Array<number>();
  2106. var uvs = new Array<number>();
  2107. var radius = options.radius || 2;
  2108. var tube = options.tube || 0.5;
  2109. var radialSegments = options.radialSegments || 32;
  2110. var tubularSegments = options.tubularSegments || 32;
  2111. var p = options.p || 2;
  2112. var q = options.q || 3;
  2113. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  2114. // Helper
  2115. var getPos = (angle: number) => {
  2116. var cu = Math.cos(angle);
  2117. var su = Math.sin(angle);
  2118. var quOverP = q / p * angle;
  2119. var cs = Math.cos(quOverP);
  2120. var tx = radius * (2 + cs) * 0.5 * cu;
  2121. var ty = radius * (2 + cs) * su * 0.5;
  2122. var tz = radius * Math.sin(quOverP) * 0.5;
  2123. return new Vector3(tx, ty, tz);
  2124. };
  2125. // Vertices
  2126. var i: number;
  2127. var j: number;
  2128. for (i = 0; i <= radialSegments; i++) {
  2129. var modI = i % radialSegments;
  2130. var u = modI / radialSegments * 2 * p * Math.PI;
  2131. var p1 = getPos(u);
  2132. var p2 = getPos(u + 0.01);
  2133. var tang = p2.subtract(p1);
  2134. var n = p2.add(p1);
  2135. var bitan = Vector3.Cross(tang, n);
  2136. n = Vector3.Cross(bitan, tang);
  2137. bitan.normalize();
  2138. n.normalize();
  2139. for (j = 0; j < tubularSegments; j++) {
  2140. var modJ = j % tubularSegments;
  2141. var v = modJ / tubularSegments * 2 * Math.PI;
  2142. var cx = -tube * Math.cos(v);
  2143. var cy = tube * Math.sin(v);
  2144. positions.push(p1.x + cx * n.x + cy * bitan.x);
  2145. positions.push(p1.y + cx * n.y + cy * bitan.y);
  2146. positions.push(p1.z + cx * n.z + cy * bitan.z);
  2147. uvs.push(i / radialSegments);
  2148. uvs.push(j / tubularSegments);
  2149. }
  2150. }
  2151. for (i = 0; i < radialSegments; i++) {
  2152. for (j = 0; j < tubularSegments; j++) {
  2153. var jNext = (j + 1) % tubularSegments;
  2154. var a = i * tubularSegments + j;
  2155. var b = (i + 1) * tubularSegments + j;
  2156. var c = (i + 1) * tubularSegments + jNext;
  2157. var d = i * tubularSegments + jNext;
  2158. indices.push(d); indices.push(b); indices.push(a);
  2159. indices.push(d); indices.push(c); indices.push(b);
  2160. }
  2161. }
  2162. // Normals
  2163. VertexData.ComputeNormals(positions, indices, normals);
  2164. // Sides
  2165. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  2166. // Result
  2167. var vertexData = new VertexData();
  2168. vertexData.indices = indices;
  2169. vertexData.positions = positions;
  2170. vertexData.normals = normals;
  2171. vertexData.uvs = uvs;
  2172. return vertexData;
  2173. }
  2174. // Tools
  2175. /**
  2176. * Compute normals for given positions and indices
  2177. * @param positions an array of vertex positions, [...., x, y, z, ......]
  2178. * @param indices an array of indices in groups of three for each triangular facet, [...., i, j, k, ......]
  2179. * @param normals an array of vertex normals, [...., x, y, z, ......]
  2180. * @param options an object used to set the following optional parameters for the TorusKnot, optional
  2181. * * facetNormals : optional array of facet normals (vector3)
  2182. * * facetPositions : optional array of facet positions (vector3)
  2183. * * facetPartitioning : optional partitioning array. facetPositions is required for facetPartitioning computation
  2184. * * ratio : optional partitioning ratio / bounding box, required for facetPartitioning computation
  2185. * * bInfo : optional bounding info, required for facetPartitioning computation
  2186. * * bbSize : optional bounding box size data, required for facetPartitioning computation
  2187. * * subDiv : optional partitioning data about subdivsions on each axis (int), required for facetPartitioning computation
  2188. * * useRightHandedSystem: optional boolean to for right handed system computation
  2189. * * depthSort : optional boolean to enable the facet depth sort computation
  2190. * * distanceTo : optional Vector3 to compute the facet depth from this location
  2191. * * depthSortedFacets : optional array of depthSortedFacets to store the facet distances from the reference location
  2192. */
  2193. public static ComputeNormals(positions: any, indices: any, normals: any,
  2194. options?: {
  2195. facetNormals?: any, facetPositions?: any, facetPartitioning?: any, ratio?: number, bInfo?: any, bbSize?: Vector3, subDiv?: any,
  2196. useRightHandedSystem?: boolean, depthSort?: boolean, distanceTo?: Vector3, depthSortedFacets?: any
  2197. }): void {
  2198. // temporary scalar variables
  2199. var index = 0; // facet index
  2200. var p1p2x = 0.0; // p1p2 vector x coordinate
  2201. var p1p2y = 0.0; // p1p2 vector y coordinate
  2202. var p1p2z = 0.0; // p1p2 vector z coordinate
  2203. var p3p2x = 0.0; // p3p2 vector x coordinate
  2204. var p3p2y = 0.0; // p3p2 vector y coordinate
  2205. var p3p2z = 0.0; // p3p2 vector z coordinate
  2206. var faceNormalx = 0.0; // facet normal x coordinate
  2207. var faceNormaly = 0.0; // facet normal y coordinate
  2208. var faceNormalz = 0.0; // facet normal z coordinate
  2209. var length = 0.0; // facet normal length before normalization
  2210. var v1x = 0; // vector1 x index in the positions array
  2211. var v1y = 0; // vector1 y index in the positions array
  2212. var v1z = 0; // vector1 z index in the positions array
  2213. var v2x = 0; // vector2 x index in the positions array
  2214. var v2y = 0; // vector2 y index in the positions array
  2215. var v2z = 0; // vector2 z index in the positions array
  2216. var v3x = 0; // vector3 x index in the positions array
  2217. var v3y = 0; // vector3 y index in the positions array
  2218. var v3z = 0; // vector3 z index in the positions array
  2219. var computeFacetNormals = false;
  2220. var computeFacetPositions = false;
  2221. var computeFacetPartitioning = false;
  2222. var computeDepthSort = false;
  2223. var faceNormalSign = 1;
  2224. let ratio = 0;
  2225. var distanceTo: Nullable<Vector3> = null;
  2226. if (options) {
  2227. computeFacetNormals = (options.facetNormals) ? true : false;
  2228. computeFacetPositions = (options.facetPositions) ? true : false;
  2229. computeFacetPartitioning = (options.facetPartitioning) ? true : false;
  2230. faceNormalSign = (options.useRightHandedSystem === true) ? -1 : 1;
  2231. ratio = options.ratio || 0;
  2232. computeDepthSort = (options.depthSort) ? true : false;
  2233. distanceTo = <Vector3>(options.distanceTo);
  2234. if (computeDepthSort) {
  2235. if (distanceTo === undefined) {
  2236. distanceTo = Vector3.Zero();
  2237. }
  2238. var depthSortedFacets = options.depthSortedFacets;
  2239. }
  2240. }
  2241. // facetPartitioning reinit if needed
  2242. let xSubRatio = 0;
  2243. let ySubRatio = 0;
  2244. let zSubRatio = 0;
  2245. let subSq = 0;
  2246. if (computeFacetPartitioning && options && options.bbSize) {
  2247. var ox = 0; // X partitioning index for facet position
  2248. var oy = 0; // Y partinioning index for facet position
  2249. var oz = 0; // Z partinioning index for facet position
  2250. var b1x = 0; // X partitioning index for facet v1 vertex
  2251. var b1y = 0; // Y partitioning index for facet v1 vertex
  2252. var b1z = 0; // z partitioning index for facet v1 vertex
  2253. var b2x = 0; // X partitioning index for facet v2 vertex
  2254. var b2y = 0; // Y partitioning index for facet v2 vertex
  2255. var b2z = 0; // Z partitioning index for facet v2 vertex
  2256. var b3x = 0; // X partitioning index for facet v3 vertex
  2257. var b3y = 0; // Y partitioning index for facet v3 vertex
  2258. var b3z = 0; // Z partitioning index for facet v3 vertex
  2259. var block_idx_o = 0; // facet barycenter block index
  2260. var block_idx_v1 = 0; // v1 vertex block index
  2261. var block_idx_v2 = 0; // v2 vertex block index
  2262. var block_idx_v3 = 0; // v3 vertex block index
  2263. var bbSizeMax = (options.bbSize.x > options.bbSize.y) ? options.bbSize.x : options.bbSize.y;
  2264. bbSizeMax = (bbSizeMax > options.bbSize.z) ? bbSizeMax : options.bbSize.z;
  2265. xSubRatio = options.subDiv.X * ratio / options.bbSize.x;
  2266. ySubRatio = options.subDiv.Y * ratio / options.bbSize.y;
  2267. zSubRatio = options.subDiv.Z * ratio / options.bbSize.z;
  2268. subSq = options.subDiv.max * options.subDiv.max;
  2269. options.facetPartitioning.length = 0;
  2270. }
  2271. // reset the normals
  2272. for (index = 0; index < positions.length; index++) {
  2273. normals[index] = 0.0;
  2274. }
  2275. // Loop : 1 indice triplet = 1 facet
  2276. var nbFaces = (indices.length / 3) | 0;
  2277. for (index = 0; index < nbFaces; index++) {
  2278. // get the indexes of the coordinates of each vertex of the facet
  2279. v1x = indices[index * 3] * 3;
  2280. v1y = v1x + 1;
  2281. v1z = v1x + 2;
  2282. v2x = indices[index * 3 + 1] * 3;
  2283. v2y = v2x + 1;
  2284. v2z = v2x + 2;
  2285. v3x = indices[index * 3 + 2] * 3;
  2286. v3y = v3x + 1;
  2287. v3z = v3x + 2;
  2288. p1p2x = positions[v1x] - positions[v2x]; // compute two vectors per facet : p1p2 and p3p2
  2289. p1p2y = positions[v1y] - positions[v2y];
  2290. p1p2z = positions[v1z] - positions[v2z];
  2291. p3p2x = positions[v3x] - positions[v2x];
  2292. p3p2y = positions[v3y] - positions[v2y];
  2293. p3p2z = positions[v3z] - positions[v2z];
  2294. // compute the face normal with the cross product
  2295. faceNormalx = faceNormalSign * (p1p2y * p3p2z - p1p2z * p3p2y);
  2296. faceNormaly = faceNormalSign * (p1p2z * p3p2x - p1p2x * p3p2z);
  2297. faceNormalz = faceNormalSign * (p1p2x * p3p2y - p1p2y * p3p2x);
  2298. // normalize this normal and store it in the array facetData
  2299. length = Math.sqrt(faceNormalx * faceNormalx + faceNormaly * faceNormaly + faceNormalz * faceNormalz);
  2300. length = (length === 0) ? 1.0 : length;
  2301. faceNormalx /= length;
  2302. faceNormaly /= length;
  2303. faceNormalz /= length;
  2304. if (computeFacetNormals && options) {
  2305. options.facetNormals[index].x = faceNormalx;
  2306. options.facetNormals[index].y = faceNormaly;
  2307. options.facetNormals[index].z = faceNormalz;
  2308. }
  2309. if (computeFacetPositions && options) {
  2310. // compute and the facet barycenter coordinates in the array facetPositions
  2311. options.facetPositions[index].x = (positions[v1x] + positions[v2x] + positions[v3x]) / 3.0;
  2312. options.facetPositions[index].y = (positions[v1y] + positions[v2y] + positions[v3y]) / 3.0;
  2313. options.facetPositions[index].z = (positions[v1z] + positions[v2z] + positions[v3z]) / 3.0;
  2314. }
  2315. if (computeFacetPartitioning && options) {
  2316. // store the facet indexes in arrays in the main facetPartitioning array :
  2317. // compute each facet vertex (+ facet barycenter) index in the partiniong array
  2318. ox = Math.floor((options.facetPositions[index].x - options.bInfo.minimum.x * ratio) * xSubRatio);
  2319. oy = Math.floor((options.facetPositions[index].y - options.bInfo.minimum.y * ratio) * ySubRatio);
  2320. oz = Math.floor((options.facetPositions[index].z - options.bInfo.minimum.z * ratio) * zSubRatio);
  2321. b1x = Math.floor((positions[v1x] - options.bInfo.minimum.x * ratio) * xSubRatio);
  2322. b1y = Math.floor((positions[v1y] - options.bInfo.minimum.y * ratio) * ySubRatio);
  2323. b1z = Math.floor((positions[v1z] - options.bInfo.minimum.z * ratio) * zSubRatio);
  2324. b2x = Math.floor((positions[v2x] - options.bInfo.minimum.x * ratio) * xSubRatio);
  2325. b2y = Math.floor((positions[v2y] - options.bInfo.minimum.y * ratio) * ySubRatio);
  2326. b2z = Math.floor((positions[v2z] - options.bInfo.minimum.z * ratio) * zSubRatio);
  2327. b3x = Math.floor((positions[v3x] - options.bInfo.minimum.x * ratio) * xSubRatio);
  2328. b3y = Math.floor((positions[v3y] - options.bInfo.minimum.y * ratio) * ySubRatio);
  2329. b3z = Math.floor((positions[v3z] - options.bInfo.minimum.z * ratio) * zSubRatio);
  2330. block_idx_v1 = b1x + options.subDiv.max * b1y + subSq * b1z;
  2331. block_idx_v2 = b2x + options.subDiv.max * b2y + subSq * b2z;
  2332. block_idx_v3 = b3x + options.subDiv.max * b3y + subSq * b3z;
  2333. block_idx_o = ox + options.subDiv.max * oy + subSq * oz;
  2334. options.facetPartitioning[block_idx_o] = options.facetPartitioning[block_idx_o] ? options.facetPartitioning[block_idx_o] : new Array();
  2335. options.facetPartitioning[block_idx_v1] = options.facetPartitioning[block_idx_v1] ? options.facetPartitioning[block_idx_v1] : new Array();
  2336. options.facetPartitioning[block_idx_v2] = options.facetPartitioning[block_idx_v2] ? options.facetPartitioning[block_idx_v2] : new Array();
  2337. options.facetPartitioning[block_idx_v3] = options.facetPartitioning[block_idx_v3] ? options.facetPartitioning[block_idx_v3] : new Array();
  2338. // push each facet index in each block containing the vertex
  2339. options.facetPartitioning[block_idx_v1].push(index);
  2340. if (block_idx_v2 != block_idx_v1) {
  2341. options.facetPartitioning[block_idx_v2].push(index);
  2342. }
  2343. if (!(block_idx_v3 == block_idx_v2 || block_idx_v3 == block_idx_v1)) {
  2344. options.facetPartitioning[block_idx_v3].push(index);
  2345. }
  2346. if (!(block_idx_o == block_idx_v1 || block_idx_o == block_idx_v2 || block_idx_o == block_idx_v3)) {
  2347. options.facetPartitioning[block_idx_o].push(index);
  2348. }
  2349. }
  2350. if (computeDepthSort && options && options.facetPositions) {
  2351. var dsf = depthSortedFacets[index];
  2352. dsf.ind = index * 3;
  2353. dsf.sqDistance = Vector3.DistanceSquared(options.facetPositions[index], distanceTo!)
  2354. }
  2355. // compute the normals anyway
  2356. normals[v1x] += faceNormalx; // accumulate all the normals per face
  2357. normals[v1y] += faceNormaly;
  2358. normals[v1z] += faceNormalz;
  2359. normals[v2x] += faceNormalx;
  2360. normals[v2y] += faceNormaly;
  2361. normals[v2z] += faceNormalz;
  2362. normals[v3x] += faceNormalx;
  2363. normals[v3y] += faceNormaly;
  2364. normals[v3z] += faceNormalz;
  2365. }
  2366. // last normalization of each normal
  2367. for (index = 0; index < normals.length / 3; index++) {
  2368. faceNormalx = normals[index * 3];
  2369. faceNormaly = normals[index * 3 + 1];
  2370. faceNormalz = normals[index * 3 + 2];
  2371. length = Math.sqrt(faceNormalx * faceNormalx + faceNormaly * faceNormaly + faceNormalz * faceNormalz);
  2372. length = (length === 0) ? 1.0 : length;
  2373. faceNormalx /= length;
  2374. faceNormaly /= length;
  2375. faceNormalz /= length;
  2376. normals[index * 3] = faceNormalx;
  2377. normals[index * 3 + 1] = faceNormaly;
  2378. normals[index * 3 + 2] = faceNormalz;
  2379. }
  2380. }
  2381. private static _ComputeSides(sideOrientation: number, positions: FloatArray, indices: FloatArray, normals: FloatArray, uvs: FloatArray, frontUVs?: Vector4, backUVs?: Vector4) {
  2382. var li: number = indices.length;
  2383. var ln: number = normals.length;
  2384. var i: number;
  2385. var n: number;
  2386. sideOrientation = sideOrientation || Mesh.DEFAULTSIDE;
  2387. switch (sideOrientation) {
  2388. case Mesh.FRONTSIDE:
  2389. // nothing changed
  2390. break;
  2391. case Mesh.BACKSIDE:
  2392. var tmp: number;
  2393. // indices
  2394. for (i = 0; i < li; i += 3) {
  2395. tmp = indices[i];
  2396. indices[i] = indices[i + 2];
  2397. indices[i + 2] = tmp;
  2398. }
  2399. // normals
  2400. for (n = 0; n < ln; n++) {
  2401. normals[n] = -normals[n];
  2402. }
  2403. break;
  2404. case Mesh.DOUBLESIDE:
  2405. // positions
  2406. var lp: number = positions.length;
  2407. var l: number = lp / 3;
  2408. for (var p = 0; p < lp; p++) {
  2409. positions[lp + p] = positions[p];
  2410. }
  2411. // indices
  2412. for (i = 0; i < li; i += 3) {
  2413. indices[i + li] = indices[i + 2] + l;
  2414. indices[i + 1 + li] = indices[i + 1] + l;
  2415. indices[i + 2 + li] = indices[i] + l;
  2416. }
  2417. // normals
  2418. for (n = 0; n < ln; n++) {
  2419. normals[ln + n] = -normals[n];
  2420. }
  2421. // uvs
  2422. var lu: number = uvs.length;
  2423. var u: number = 0;
  2424. for (u = 0; u < lu; u++) {
  2425. uvs[u + lu] = uvs[u];
  2426. }
  2427. frontUVs = frontUVs ? frontUVs : new Vector4(0.0, 0.0, 1.0, 1.0);
  2428. backUVs = backUVs ? backUVs : new Vector4(0.0, 0.0, 1.0, 1.0);
  2429. u = 0;
  2430. for (i = 0; i < lu / 2; i++) {
  2431. uvs[u] = frontUVs.x + (frontUVs.z - frontUVs.x) * uvs[u];
  2432. uvs[u + 1] = frontUVs.y + (frontUVs.w - frontUVs.y) * uvs[u + 1];
  2433. uvs[u + lu] = backUVs.x + (backUVs.z - backUVs.x) * uvs[u + lu];
  2434. uvs[u + lu + 1] = backUVs.y + (backUVs.w - backUVs.y) * uvs[u + lu + 1];
  2435. u += 2;
  2436. }
  2437. break;
  2438. }
  2439. }
  2440. /**
  2441. * Applies VertexData created from the imported parameters to the geometry
  2442. * @param parsedVertexData the parsed data from an imported file
  2443. * @param geometry the geometry to apply the VertexData to
  2444. */
  2445. public static ImportVertexData(parsedVertexData: any, geometry: Geometry) {
  2446. var vertexData = new VertexData();
  2447. // positions
  2448. var positions = parsedVertexData.positions;
  2449. if (positions) {
  2450. vertexData.set(positions, VertexBuffer.PositionKind);
  2451. }
  2452. // normals
  2453. var normals = parsedVertexData.normals;
  2454. if (normals) {
  2455. vertexData.set(normals, VertexBuffer.NormalKind);
  2456. }
  2457. // tangents
  2458. var tangents = parsedVertexData.tangents;
  2459. if (tangents) {
  2460. vertexData.set(tangents, VertexBuffer.TangentKind);
  2461. }
  2462. // uvs
  2463. var uvs = parsedVertexData.uvs;
  2464. if (uvs) {
  2465. vertexData.set(uvs, VertexBuffer.UVKind);
  2466. }
  2467. // uv2s
  2468. var uv2s = parsedVertexData.uv2s;
  2469. if (uv2s) {
  2470. vertexData.set(uv2s, VertexBuffer.UV2Kind);
  2471. }
  2472. // uv3s
  2473. var uv3s = parsedVertexData.uv3s;
  2474. if (uv3s) {
  2475. vertexData.set(uv3s, VertexBuffer.UV3Kind);
  2476. }
  2477. // uv4s
  2478. var uv4s = parsedVertexData.uv4s;
  2479. if (uv4s) {
  2480. vertexData.set(uv4s, VertexBuffer.UV4Kind);
  2481. }
  2482. // uv5s
  2483. var uv5s = parsedVertexData.uv5s;
  2484. if (uv5s) {
  2485. vertexData.set(uv5s, VertexBuffer.UV5Kind);
  2486. }
  2487. // uv6s
  2488. var uv6s = parsedVertexData.uv6s;
  2489. if (uv6s) {
  2490. vertexData.set(uv6s, VertexBuffer.UV6Kind);
  2491. }
  2492. // colors
  2493. var colors = parsedVertexData.colors;
  2494. if (colors) {
  2495. vertexData.set(Color4.CheckColors4(colors, positions.length / 3), VertexBuffer.ColorKind);
  2496. }
  2497. // matricesIndices
  2498. var matricesIndices = parsedVertexData.matricesIndices;
  2499. if (matricesIndices) {
  2500. vertexData.set(matricesIndices, VertexBuffer.MatricesIndicesKind);
  2501. }
  2502. // matricesWeights
  2503. var matricesWeights = parsedVertexData.matricesWeights;
  2504. if (matricesWeights) {
  2505. vertexData.set(matricesWeights, VertexBuffer.MatricesWeightsKind);
  2506. }
  2507. // indices
  2508. var indices = parsedVertexData.indices;
  2509. if (indices) {
  2510. vertexData.indices = indices;
  2511. }
  2512. geometry.setAllVerticesData(vertexData, parsedVertexData.updatable);
  2513. }
  2514. }
  2515. }