mesh.vertexData.ts 156 KB

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