babylon.mesh.vertexData.ts 153 KB

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