GLS.MeshBuilder.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.MeshBuilder;
  5. (*
  6. Build mesh objects.
  7. This unit is intended to create and draw some mesh objects using flexible functions
  8. with lots of options, including applying materials and textures for different facets.
  9. Started by Joen Joensen, who contributed procedures: BuildMeshCube, BuildMeshCylinder.
  10. *)
  11. interface
  12. uses
  13. System.SysUtils,
  14. System.Classes,
  15. GLS.Scene,
  16. GLS.VectorTypes,
  17. GLS.VectorGeometry,
  18. GLS.VectorLists,
  19. GLS.PersistentClasses,
  20. GLS.VectorFileObjects,
  21. GLS.MeshUtils;
  22. type
  23. (*
  24. Properties of a hexahedron with 6 quad parts
  25. *)
  26. TGLHexahedronProperties = record
  27. Normal3f: TVector3f;
  28. VertexCoords: array [0 .. 3] of TVector3f;
  29. TextureCoords: array [0 .. 3] of TVector2f;
  30. PartIndices: array [0 .. 5] of Integer;
  31. Material: string; // for 6 colors or cubic map from MaterialLibrary
  32. end;
  33. (*
  34. Properties of a sphere with two hemisphere parts
  35. using 5 points to make each hemisphere
  36. *)
  37. TGLSphereProperties = record
  38. Normal3f: TVector3f;
  39. VertexCoords: array [0 .. 4] of TVector3f;
  40. TextureCoords: array [0 .. 4] of TVector2f;
  41. PartIndices: array [0 .. 1] of Integer;
  42. Material: string; // for 2 colors or textures
  43. end;
  44. (*
  45. Properties of a cylinder with 8 parts for 2 hemicylinders
  46. using 6 points to make each part for hemidisk caps and side surfaces
  47. *)
  48. TGLCylinderProperties = record
  49. Normal3f: TVector3f;
  50. VertexCoords: array [0 .. 5] of TVector3f;
  51. TextureCoords: array [0 .. 5] of TVector2f;
  52. PartIndices: array [0 .. 7] of Integer;
  53. Material: string; // for 8 colors or textures
  54. end;
  55. type
  56. TGLMeshOptimizerOption = (mooStandardize, mooVertexCache, mooSortByMaterials,
  57. mooMergeObjects);
  58. TGLMeshOptimizerOptions = set of TGLMeshOptimizerOption;
  59. // Hexahedron arrays for 6 parts
  60. const
  61. cMeshHexahedron: array [0 .. 5] of TGLHexahedronProperties = ((
  62. // Front Quad
  63. VertexCoords: ((X: - 1; Y: - 1; Z: 1), (X: 1; Y: - 1; Z: 1), (X: 1; Y: 1;
  64. Z: 1), (X: - 1; Y: 1; Z: 1)); TextureCoords: ((X: 0; Y: 0), (X: 1; Y: 0), (X: 1;
  65. Y: 1), (X: 0; Y: 1)); PartIndices: (0, 1, 2, 2, 3, 0);
  66. Material: 'Front';), (
  67. // Back Quad
  68. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: - 1; Y: 1; Z: - 1), (X: 1; Y: 1;
  69. Z: - 1), (X: 1; Y: - 1; Z: - 1)); TextureCoords: ((X: 1; Y: 0), (X: 1;
  70. Y: 1), (X: 0; Y: 1), (X: 0; Y: 0)); PartIndices: (4, 5, 6, 6, 7, 4);
  71. Material: 'Back';), (
  72. // Top Quad
  73. VertexCoords: ((X: - 1; Y: 1; Z: - 1), (X: - 1; Y: 1; Z: 1), (X: 1; Y: 1;
  74. Z: 1), (X: 1; Y: 1; Z: - 1)); TextureCoords: ((X: 0; Y: 1), (X: 0; Y: 0), (X: 1;
  75. Y: 0), (X: 1; Y: 1)); PartIndices: (8, 9, 10, 10, 11, 8);
  76. Material: 'Top';), (
  77. // Bottom Quad
  78. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: 1; Y: - 1; Z: - 1), (X: 1; Y: - 1;
  79. Z: 1), (X: - 1; Y: - 1; Z: 1)); TextureCoords: ((X: 1; Y: 1), (X: 0;
  80. Y: 1), (X: 0; Y: 0), (X: 1; Y: 0)); PartIndices: (12, 13, 14, 14, 15, 12);
  81. Material: 'Bottom';), (
  82. // Right Quad
  83. VertexCoords: ((X: 1; Y: - 1; Z: - 1), (X: 1; Y: 1; Z: - 1), (X: 1; Y: 1;
  84. Z: 1), (X: 1; Y: - 1; Z: 1)); TextureCoords: ((X: 1; Y: 0), (X: 1; Y: 1), (X: 0;
  85. Y: 1), (X: 0; Y: 0)); PartIndices: (16, 17, 18, 18, 19, 16);
  86. Material: 'Right';), (
  87. // Left Quad
  88. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: - 1; Y: - 1; Z: 1), (X: - 1; Y: 1;
  89. Z: 1), (X: - 1; Y: 1; Z: - 1)); TextureCoords: ((X: 0; Y: 0), (X: 1;
  90. Y: 0), (X: 1; Y: 1), (X: 0; Y: 1)); PartIndices: (20, 21, 22, 22, 23, 20);
  91. Material: 'Left';));
  92. // Sphere arrays for parts with 2 hemispheres
  93. const
  94. cMeshSphere: array [0 .. 1] of TGLSphereProperties = ((
  95. // Top HemiSphere
  96. VertexCoords: ((X: - 1; Y: 1; Z: - 1), (X: - 1; Y: 1; Z: 1), (X: 1; Y: 1;
  97. Z: 1), (X: 1; Y: 1; Z: - 1), (X: 0; Y: 1; Z: 0)); TextureCoords: ((X: 0; Y: 1), (X: 0; Y: 0), (X: 1;
  98. Y: 0), (X: 1; Y: 1), (X: 1; Y: 1)); PartIndices: (0, 1);
  99. Material: 'Top';), (
  100. // Bottom HemiSphere
  101. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: 1; Y: - 1; Z: - 1), (X: 1; Y: - 1;
  102. Z: 1), (X: - 1; Y: - 1; Z: 1), (X: - 1; Y: - 1; Z: 1)); TextureCoords: ((X: 1; Y: 1), (X: 0;
  103. Y: 1), (X: 0; Y: 0), (X: 1; Y: 0), (X: 0; Y: 0)); PartIndices: (1, 2);
  104. Material: 'Bottom';));
  105. (*
  106. // Cylinder arrays
  107. const
  108. cMeshCylinder: array [0 .. 3] of TGLCylinderProperties = ((
  109. // Front Disk
  110. VertexCoords: ((X: - 1; Y: - 1; Z: 1), (X: 1; Y: - 1; Z: 1), (X: 1; Y: 1;
  111. Z: 1), (X: - 1; Y: 1; Z: 1)); TextureCoords: ((X: 0; Y: 0), (X: 1; Y: 0), (X: 1;
  112. Y: 1), (X: 0; Y: 1)); PartIndices: (0, 1, 2);
  113. Material: 'Front';), (
  114. // Back Disk
  115. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: - 1; Y: 1; Z: - 1), (X: 1; Y: 1;
  116. Z: - 1), (X: 1; Y: - 1; Z: - 1)); TextureCoords: ((X: 1; Y: 0), (X: 1;
  117. Y: 1), (X: 0; Y: 1), (X: 0; Y: 0)); PartIndices: (3, 4, 5);
  118. Material: 'Back';), (
  119. // Top Dome
  120. VertexCoords: ((X: - 1; Y: 1; Z: - 1), (X: - 1; Y: 1; Z: 1), (X: 1; Y: 1;
  121. Z: 1), (X: 1; Y: 1; Z: - 1)); TextureCoords: ((X: 0; Y: 1), (X: 0; Y: 0), (X: 1;
  122. Y: 0), (X: 1; Y: 1)); PartIndices: (6, 7, 8);
  123. Material: 'Top';), (
  124. // Bottom Dome
  125. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: 1; Y: - 1; Z: - 1), (X: 1; Y: - 1;
  126. Z: 1), (X: - 1; Y: - 1; Z: 1)); TextureCoords: ((X: 1; Y: 1), (X: 0;
  127. Y: 1), (X: 0; Y: 0), (X: 1; Y: 0)); PartIndices: (9, 10, 11);
  128. Material: 'Bottom';));
  129. // Tetrahedron part arrays
  130. const
  131. cMeshTetrahedron: array [0 .. 3] of TGLFacetProperties = ((
  132. // Front HemiDisk
  133. VertexCoords: ((X: - 1; Y: - 1; Z: 1), (X: 1; Y: - 1; Z: 1), (X: 1; Y: 1;
  134. Z: 1), (X: - 1; Y: 1; Z: 1)); TextureCoords: ((X: 0; Y: 0), (X: 1; Y: 0), (X: 1;
  135. Y: 1), (X: 0; Y: 1)); FacetIndex: (0, 1, 2, 2, 3, 0);
  136. Material: 'Front';), (
  137. // Back HemiDisk
  138. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: - 1; Y: 1; Z: - 1), (X: 1; Y: 1;
  139. Z: - 1), (X: 1; Y: - 1; Z: - 1)); TextureCoords: ((X: 1; Y: 0), (X: 1;
  140. Y: 1), (X: 0; Y: 1), (X: 0; Y: 0)); FacetIndex: (4, 5, 6, 6, 7, 4);
  141. Material: 'Back';), (
  142. // Top HemiDome
  143. VertexCoords: ((X: - 1; Y: 1; Z: - 1), (X: - 1; Y: 1; Z: 1), (X: 1; Y: 1;
  144. Z: 1), (X: 1; Y: 1; Z: - 1)); TextureCoords: ((X: 0; Y: 1), (X: 0; Y: 0), (X: 1;
  145. Y: 0), (X: 1; Y: 1)); FacetIndex: (8, 9, 10, 10, 11, 8);
  146. Material: 'Top';), (
  147. // Bottom Square
  148. VertexCoords: ((X: - 1; Y: - 1; Z: - 1), (X: 1; Y: - 1; Z: - 1), (X: 1; Y: - 1;
  149. Z: 1), (X: - 1; Y: - 1; Z: 1)); TextureCoords: ((X: 1; Y: 1), (X: 0;
  150. Y: 1), (X: 0; Y: 0), (X: 1; Y: 0)); FacetIndex: (12, 13, 14, 14, 15, 12);
  151. Material: 'Bottom';));
  152. *)
  153. (* ---------------- Build Meshes ------------------- *)
  154. procedure BuildMeshCube(Mesh : TGLMeshObject; const Position, Scale : TAffineVector);
  155. procedure BuildMeshCylinder(Mesh : TGLMeshObject; const Position, Scale : TAffineVector; Slices : Integer);
  156. procedure BuildMeshCylinderAdv(Mesh: TGLMeshObject;
  157. const Position, Scale: TAffineVector; TopRadius, BottomRadius, Height: single;
  158. Slices: Integer);
  159. // Not implemented
  160. procedure BuildMeshHemiSphere(Mesh: TGLMeshObject; const Position, Scale: TAffineVector);
  161. procedure BuildMeshHemiCylinder(Mesh: TGLMeshObject; const Position, Scale: TAffineVector;
  162. Slices: Integer);
  163. (* ---------------- Make Meshes ------------------- *)
  164. procedure MakeMeshHexahedron(MeshObject: TGLMeshObject);
  165. // Not implemented
  166. procedure MakeMeshTetrahedron(MeshObject: TGLMeshObject);
  167. procedure MakeMeshSphere(MeshObject: TGLMeshObject);
  168. (* ------ -------- Mesh optimization --------------- *)
  169. // Optimize Mesh (list, default options)
  170. procedure OptimizeMesh(aList: TGLMeshObjectList; options: TGLMeshOptimizerOptions); overload;
  171. procedure OptimizeMesh(aList: TGLMeshObjectList); overload;
  172. // OptimizeMesh (object, with options)
  173. procedure OptimizeMesh(aMeshObject: TGLMeshObject; options: TGLMeshOptimizerOptions); overload;
  174. // OptimizeMesh (object, default options)
  175. procedure OptimizeMesh(aMeshObject: TGLMeshObject); overload;
  176. procedure FacesSmooth(aMeshObj: TGLMeshObject;
  177. aWeldDistance: Single = 0.0000001; aThreshold: Single = 35.0;
  178. InvertNormals: boolean = false);
  179. var
  180. vDefaultMeshOptimizerOptions: TGLMeshOptimizerOptions = [mooStandardize,
  181. mooVertexCache, mooSortByMaterials, mooMergeObjects];
  182. //------------------------------------------------------------------
  183. implementation
  184. //------------------------------------------------------------------
  185. function VectorCombineWeighted(const Position, Scale: TAffineVector; X, Y, Z: single)
  186. : TAffineVector;
  187. begin
  188. Result.X := Position.X + Scale.X * X;
  189. Result.Y := Position.Y + Scale.Y * Y;
  190. Result.Z := Position.Z + Scale.Z * Z;
  191. end;
  192. procedure BuildMeshCube(Mesh: TGLMeshObject; const Position, Scale: TAffineVector);
  193. var
  194. FGR : TFGVertexNormalTexIndexList;
  195. VertexOffset : Integer;
  196. NormalOffset : Integer;
  197. TextureOffset : Integer;
  198. begin
  199. // Vertexes
  200. VertexOffset :=
  201. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,0.5,0.5,0.5));
  202. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,-0.5,0.5,0.5));
  203. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,0.5,-0.5,0.5));
  204. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,-0.5,-0.5,0.5));
  205. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,0.5,0.5,-0.5));
  206. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,-0.5,0.5,-0.5));
  207. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,0.5,-0.5,-0.5));
  208. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,-0.5,-0.5,-0.5));
  209. // Normals
  210. NormalOffset :=
  211. Mesh.Normals.Add(AffineVectorMake(0,0,1));
  212. Mesh.Normals.Add(AffineVectorMake(0,0,-1));
  213. Mesh.Normals.Add(AffineVectorMake(1,0,0));
  214. Mesh.Normals.Add(AffineVectorMake(-1,0,0));
  215. Mesh.Normals.Add(AffineVectorMake(0,1,0));
  216. Mesh.Normals.Add(AffineVectorMake(0,-1,0));
  217. // Texture Coordinates
  218. TextureOffset :=
  219. Mesh.TexCoords.Add(AffineVectorMake(1,1,1));
  220. Mesh.TexCoords.Add(AffineVectorMake(0,1,1));
  221. Mesh.TexCoords.Add(AffineVectorMake(1,0,1));
  222. Mesh.TexCoords.Add(AffineVectorMake(0,0,1));
  223. Mesh.TexCoords.Add(AffineVectorMake(1,1,0));
  224. Mesh.TexCoords.Add(AffineVectorMake(0,1,0));
  225. Mesh.TexCoords.Add(AffineVectorMake(1,0,0));
  226. Mesh.TexCoords.Add(AffineVectorMake(0,0,0));
  227. FGR := TFGVertexNormalTexIndexList.CreateOwned(Mesh.FaceGroups);
  228. FGR.Mode := fgmmTriangles;
  229. // Front
  230. FGR.VertexIndices.Add(VertexOffset + 0, VertexOffset + 1, VertexOffset + 3);
  231. FGR.VertexIndices.Add(VertexOffset + 0, VertexOffset + 3, VertexOffset + 2);
  232. FGR.NormalIndices.Add(NormalOffset + 0, NormalOffset + 0, NormalOffset + 0);
  233. FGR.NormalIndices.Add(NormalOffset + 0, NormalOffset + 0, NormalOffset + 0);
  234. FGR.TexCoordIndices.Add(TextureOffset + 0, TextureOffset + 1, TextureOffset + 3);
  235. FGR.TexCoordIndices.Add(TextureOffset + 0, TextureOffset + 3, TextureOffset + 2);
  236. // Back
  237. FGR.VertexIndices.Add(VertexOffset + 4, VertexOffset + 6, VertexOffset + 7);
  238. FGR.VertexIndices.Add(VertexOffset + 4, VertexOffset + 7, VertexOffset + 5);
  239. FGR.NormalIndices.Add(NormalOffset + 1, NormalOffset + 1, NormalOffset + 1);
  240. FGR.NormalIndices.Add(NormalOffset + 1, NormalOffset + 1, NormalOffset + 1);
  241. FGR.TexCoordIndices.Add(TextureOffset + 4, TextureOffset + 6, TextureOffset + 7);
  242. FGR.TexCoordIndices.Add(TextureOffset + 4, TextureOffset + 7, TextureOffset + 5);
  243. // Right
  244. FGR.VertexIndices.Add(VertexOffset + 0, VertexOffset + 2, VertexOffset + 6);
  245. FGR.VertexIndices.Add(VertexOffset + 0, VertexOffset + 6, VertexOffset + 4);
  246. FGR.NormalIndices.Add(NormalOffset + 2, NormalOffset + 2, NormalOffset + 2);
  247. FGR.NormalIndices.Add(NormalOffset + 2, NormalOffset + 2, NormalOffset + 2);
  248. FGR.TexCoordIndices.Add(TextureOffset + 0, TextureOffset + 2, TextureOffset + 6);
  249. FGR.TexCoordIndices.Add(TextureOffset + 0, TextureOffset + 6, TextureOffset + 4);
  250. // Left
  251. FGR.VertexIndices.Add(VertexOffset + 1, VertexOffset + 5, VertexOffset + 7);
  252. FGR.VertexIndices.Add(VertexOffset + 1, VertexOffset + 7, VertexOffset + 3);
  253. FGR.NormalIndices.Add(NormalOffset + 3, NormalOffset + 3, NormalOffset + 3);
  254. FGR.NormalIndices.Add(NormalOffset + 3, NormalOffset + 3, NormalOffset + 3);
  255. FGR.TexCoordIndices.Add(TextureOffset + 1, TextureOffset + 5, TextureOffset + 7);
  256. FGR.TexCoordIndices.Add(TextureOffset + 1, TextureOffset + 7, TextureOffset + 3);
  257. // Top
  258. FGR.VertexIndices.Add(VertexOffset + 0, VertexOffset + 4, VertexOffset + 5);
  259. FGR.VertexIndices.Add(VertexOffset + 0, VertexOffset + 5, VertexOffset + 1);
  260. FGR.NormalIndices.Add(NormalOffset + 4, NormalOffset + 4, NormalOffset + 4);
  261. FGR.NormalIndices.Add(NormalOffset + 4, NormalOffset + 4, NormalOffset + 4);
  262. FGR.TexCoordIndices.Add(TextureOffset + 0, TextureOffset + 4, TextureOffset + 5);
  263. FGR.TexCoordIndices.Add(TextureOffset + 0, TextureOffset + 5, TextureOffset + 1);
  264. // Bottom
  265. FGR.VertexIndices.Add(VertexOffset + 2, VertexOffset + 3, VertexOffset + 7);
  266. FGR.VertexIndices.Add(VertexOffset + 2, VertexOffset + 7, VertexOffset + 6);
  267. FGR.NormalIndices.Add(NormalOffset + 5, NormalOffset + 5, NormalOffset + 5);
  268. FGR.NormalIndices.Add(NormalOffset + 5, NormalOffset + 5, NormalOffset + 5);
  269. FGR.TexCoordIndices.Add(TextureOffset + 2, TextureOffset + 3, TextureOffset + 7);
  270. FGR.TexCoordIndices.Add(TextureOffset + 2, TextureOffset + 7, TextureOffset + 6);
  271. end;
  272. // Mesh cylinder
  273. //
  274. procedure BuildMeshCylinder(Mesh : TGLMeshObject; const Position, Scale : TAffineVector; Slices : Integer);
  275. var
  276. FGR : TFGVertexNormalTexIndexList;
  277. VertexOffset : Integer;
  278. NormalOffset : Integer;
  279. TextureOffset : Integer;
  280. Cosine,Sine : array of Single;
  281. xc,yc : Integer;
  282. begin
  283. if Slices < 3 then Exit;
  284. SetLength(Sine,Slices+1);
  285. SetLength(Cosine,Slices+1);
  286. PrepareSinCosCache(Sine,Cosine,0,360);
  287. VertexOffset := Mesh.Vertices.Count;
  288. NormalOffset := Mesh.Normals.Count;
  289. TextureOffset := Mesh.TexCoords.Count;
  290. for xc := 0 to Slices-1 do
  291. begin
  292. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,0.5*cosine[xc],0.5*sine[xc],0.5));
  293. Mesh.Vertices.Add(VectorCombineWeighted(Position,Scale,0.5*cosine[xc],0.5*sine[xc],-0.5));
  294. // Normals
  295. Mesh.Normals.add(AffineVectorMake(cosine[xc],sine[xc],0));
  296. // Texture Coordinates
  297. Mesh.TexCoords.add(VectorCombineWeighted(Position,XYZVector,0.5*cosine[xc],0.5*sine[xc],0.5));
  298. Mesh.TexCoords.add(VectorCombineWeighted(Position,XYZVector,0.5*cosine[xc],0.5*sine[xc],-0.5));
  299. end;
  300. Mesh.Normals.add(AffineVectorMake(0,0,1));
  301. Mesh.Normals.add(AffineVectorMake(0,0,-1));
  302. FGR := TFGVertexNormalTexIndexList.CreateOwned(Mesh.FaceGroups);
  303. FGR.Mode := fgmmTriangles;
  304. for xc := 0 to Slices - 1 do
  305. begin
  306. yc := xc + 1;
  307. if yc = slices then yc := 0;
  308. FGR.VertexIndices.Add(VertexOffset + xc * 2, VertexOffset + xc * 2 + 1, VertexOffset + yc * 2 + 1);
  309. FGR.VertexIndices.Add(VertexOffset + xc * 2, VertexOffset + yc * 2 + 1, VertexOffset + yc * 2);
  310. FGR.NormalIndices.Add(NormalOffset + xc, NormalOffset + xc, NormalOffset + yc);
  311. FGR.NormalIndices.Add(NormalOffset + xc, NormalOffset + yc, NormalOffset + yc);
  312. FGR.TexCoordIndices.Add(TextureOffset + xc * 2, TextureOffset + xc * 2 + 1, TextureOffset + yc * 2 + 1);
  313. FGR.TexCoordIndices.Add(TextureOffset + xc * 2, TextureOffset + yc * 2 + 1, TextureOffset + yc * 2);
  314. End;
  315. for xc := 1 to Slices - 2 do
  316. begin
  317. yc := xc + 1;
  318. FGR.VertexIndices.Add(VertexOffset, VertexOffset + xc * 2, VertexOffset + yc * 2);
  319. FGR.VertexIndices.Add(VertexOffset + 1, VertexOffset + yc * 2 + 1, VertexOffset + xc * 2 + 1);
  320. FGR.NormalIndices.Add(NormalOffset + Slices, NormalOffset + Slices, NormalOffset + Slices);
  321. FGR.NormalIndices.Add(NormalOffset + Slices + 1, NormalOffset + Slices + 1, NormalOffset + Slices + 1);
  322. FGR.TexCoordIndices.Add(TextureOffset, TextureOffset + xc * 2, TextureOffset + yc * 2);
  323. FGR.TexCoordIndices.Add(TextureOffset + 1, TextureOffset + yc * 2 + 1, TextureOffset + xc * 2 + 1);
  324. end;
  325. end;
  326. //
  327. // Mesh Cylinder with advanced options
  328. //
  329. procedure BuildMeshCylinderAdv(Mesh: TGLMeshObject;
  330. const Position, Scale: TAffineVector; TopRadius, BottomRadius, Height: single; Slices: Integer);
  331. var
  332. FGR: TFGVertexNormalTexIndexList;
  333. VertexOffset: Integer;
  334. NormalOffset: Integer;
  335. TextureOffset: Integer;
  336. Cosine, Sine: array of single;
  337. xc, yc: Integer;
  338. begin
  339. if Slices < 3 then
  340. Exit;
  341. SetLength(Sine, Slices + 1);
  342. SetLength(Cosine, Slices + 1);
  343. PrepareSinCosCache(Sine, Cosine, 0, 360);
  344. VertexOffset := Mesh.Vertices.Count;
  345. NormalOffset := Mesh.Normals.Count;
  346. TextureOffset := Mesh.TexCoords.Count;
  347. for xc := 0 to Slices - 1 do
  348. begin
  349. Mesh.Vertices.Add(VectorCombineWeighted(Position, Scale, TopRadius * 0.5 * Cosine[xc],
  350. TopRadius * 0.5 * Sine[xc], Height / 2));
  351. Mesh.Vertices.Add(VectorCombineWeighted(Position, Scale, BottomRadius * 0.5 * Cosine[xc],
  352. BottomRadius * 0.5 * Sine[xc], -Height / 2));
  353. // Normals
  354. Mesh.Normals.Add(AffineVectorMake(Cosine[xc], Sine[xc], 0));
  355. // Texture Coordinates
  356. Mesh.TexCoords.Add(VectorCombineWeighted(Position, XYZVector, TopRadius * 0.5 * Cosine[xc],
  357. TopRadius * 0.5 * Sine[xc], Height / 2));
  358. Mesh.TexCoords.Add(VectorCombineWeighted(Position, XYZVector, BottomRadius * 0.5 * Cosine[xc],
  359. BottomRadius * 0.5 * Sine[xc], -Height / 2));
  360. end;
  361. Mesh.Normals.Add(AffineVectorMake(0, 0, 1));
  362. Mesh.Normals.Add(AffineVectorMake(0, 0, -1));
  363. FGR := TFGVertexNormalTexIndexList.CreateOwned(Mesh.FaceGroups);
  364. FGR.Mode := fgmmTriangles;
  365. for xc := 0 to Slices - 1 do
  366. begin
  367. yc := xc + 1;
  368. if yc = Slices then
  369. yc := 0;
  370. FGR.VertexIndices.Add(VertexOffset + xc * 2, VertexOffset + xc * 2 + 1,
  371. VertexOffset + yc * 2 + 1);
  372. FGR.VertexIndices.Add(VertexOffset + xc * 2, VertexOffset + yc * 2 + 1, VertexOffset + yc * 2);
  373. FGR.NormalIndices.Add(NormalOffset + xc, NormalOffset + xc, NormalOffset + yc);
  374. FGR.NormalIndices.Add(NormalOffset + xc, NormalOffset + yc, NormalOffset + yc);
  375. FGR.TexCoordIndices.Add(TextureOffset + xc * 2, TextureOffset + xc * 2 + 1,
  376. TextureOffset + yc * 2 + 1);
  377. FGR.TexCoordIndices.Add(TextureOffset + xc * 2, TextureOffset + yc * 2 + 1,
  378. TextureOffset + yc * 2);
  379. end;
  380. for xc := 1 to Slices - 2 do
  381. begin
  382. yc := xc + 1;
  383. FGR.VertexIndices.Add(VertexOffset, VertexOffset + xc * 2, VertexOffset + yc * 2);
  384. FGR.VertexIndices.Add(VertexOffset + 1, VertexOffset + yc * 2 + 1, VertexOffset + xc * 2 + 1);
  385. FGR.NormalIndices.Add(NormalOffset + Slices, NormalOffset + Slices, NormalOffset + Slices);
  386. FGR.NormalIndices.Add(NormalOffset + Slices + 1, NormalOffset + Slices + 1,
  387. NormalOffset + Slices + 1);
  388. FGR.TexCoordIndices.Add(TextureOffset, TextureOffset + xc * 2, TextureOffset + yc * 2);
  389. FGR.TexCoordIndices.Add(TextureOffset + 1, TextureOffset + yc * 2 + 1,
  390. TextureOffset + xc * 2 + 1);
  391. end;
  392. end;
  393. // -----------------------------------------------------------
  394. // Make Mesh Hexahedron
  395. // -----------------------------------------------------------
  396. procedure MakeMeshHexahedron(MeshObject: TGLMeshObject);
  397. var
  398. FaceGroupList: TFGVertexIndexList;
  399. i, j: Integer;
  400. begin
  401. for i := Low(cMeshHexahedron) to High(cMeshHexahedron) do
  402. begin
  403. // Add vertex coordinates
  404. for j := Low(cMeshHexahedron[i].VertexCoords) to High(cMeshHexahedron[i].VertexCoords) do
  405. MeshObject.Vertices.Add(cMeshHexahedron[i].VertexCoords[j]);
  406. // Add texture coordinates
  407. for j := Low(cMeshHexahedron[i].TextureCoords) to High(cMeshHexahedron[i].TextureCoords) do
  408. MeshObject.TexCoords.Add(cMeshHexahedron[i].TextureCoords[j]);
  409. FaceGroupList := TFGVertexIndexList.CreateOwned(MeshObject.FaceGroups);
  410. for j := Low(cMeshHexahedron[i].PartIndices) to High(cMeshHexahedron[i].PartIndices) do
  411. FaceGroupList.Add(cMeshHexahedron[i].PartIndices[j]);
  412. FaceGroupList.MaterialName := cMeshHexahedron[i].Material;
  413. end;
  414. end;
  415. // --------------------------------------------------------------------------------------
  416. procedure BuildMeshHemiSphere(Mesh : TGLMeshObject; const Position, Scale : TAffineVector);
  417. begin
  418. //
  419. end;
  420. procedure BuildMeshHemiCylinder(Mesh : TGLMeshObject; const Position, Scale : TAffineVector; Slices : Integer);
  421. begin
  422. //
  423. end;
  424. // --------------------------------------------------------------------------------------
  425. procedure MakeMeshSphere(MeshObject : TGLMeshObject);
  426. begin
  427. //
  428. end;
  429. procedure MakeMeshTetrahedron(MeshObject: TGLMeshObject);
  430. begin
  431. //
  432. end;
  433. // --------------- Mesh Optimization ---------------
  434. procedure OptimizeMesh(aList: TGLMeshObjectList);
  435. begin
  436. OptimizeMesh(aList, vDefaultMeshOptimizerOptions);
  437. end;
  438. procedure OptimizeMesh(aList: TGLMeshObjectList;
  439. options: TGLMeshOptimizerOptions);
  440. var
  441. i, k: Integer;
  442. mob, mo: TGLMeshObject;
  443. fg: TGLFaceGroup;
  444. fgvi: TFGVertexIndexList;
  445. begin
  446. // optimize all mesh objects
  447. for i := 0 to aList.Count - 1 do
  448. begin
  449. OptimizeMesh(aList[i], options);
  450. end;
  451. if (mooStandardize in options) then
  452. begin
  453. // drop mesh objects that have become empty
  454. for i := aList.Count - 1 downto 0 do
  455. begin
  456. if (aList[i].Mode = momFaceGroups) and (aList[i].FaceGroups.Count = 0)
  457. then
  458. aList[i].Free;
  459. end;
  460. end;
  461. if (aList.Count > 0) and (mooMergeObjects in options) then
  462. begin
  463. mob := aList[0];
  464. Assert(mob.Mode = momFaceGroups);
  465. for i := 1 to aList.Count - 1 do
  466. begin
  467. mo := aList[i];
  468. Assert(mo.Mode = momFaceGroups);
  469. k := mob.Vertices.Count;
  470. mob.Vertices.Add(mo.Vertices);
  471. mob.Normals.Add(mo.Normals);
  472. mob.TexCoords.Add(mo.TexCoords);
  473. while mo.FaceGroups.Count > 0 do
  474. begin
  475. fg := mo.FaceGroups[0];
  476. fgvi := (fg as TFGVertexIndexList);
  477. fgvi.Owner := mob.FaceGroups;
  478. mob.FaceGroups.Add(fgvi);
  479. mo.FaceGroups.Delete(0);
  480. fgvi.VertexIndices.Offset(k);
  481. end;
  482. end;
  483. for i := aList.Count - 1 downto 1 do
  484. aList[i].Free;
  485. end;
  486. end;
  487. procedure OptimizeMesh(aMeshObject: TGLMeshObject);
  488. begin
  489. OptimizeMesh(aMeshObject, vDefaultMeshOptimizerOptions);
  490. end;
  491. procedure OptimizeMesh(aMeshObject: TGLMeshObject;
  492. options: TGLMeshOptimizerOptions);
  493. var
  494. i: Integer;
  495. fg: TGLFaceGroup;
  496. coords, TexCoords, Normals: TGLAffineVectorList;
  497. il: TGLIntegerList;
  498. materialName: String;
  499. begin
  500. if (mooMergeObjects in options) then
  501. begin
  502. if aMeshObject.Mode = momFaceGroups then
  503. begin
  504. // remove empty facegroups
  505. for i := aMeshObject.FaceGroups.Count - 1 downto 0 do
  506. begin
  507. fg := aMeshObject.FaceGroups[i];
  508. if fg.TriangleCount = 0 then
  509. fg.Free;
  510. end;
  511. end;
  512. end;
  513. if (mooStandardize in options) then
  514. begin
  515. if (aMeshObject.Mode <> momFaceGroups) or (aMeshObject.FaceGroups.Count <= 1)
  516. then
  517. begin
  518. if aMeshObject.FaceGroups.Count = 1 then
  519. materialName := aMeshObject.FaceGroups[0].materialName;
  520. TexCoords := TGLAffineVectorList.Create;
  521. Normals := TGLAffineVectorList.Create;
  522. coords := aMeshObject.ExtractTriangles(TexCoords, Normals);
  523. try
  524. il := BuildVectorCountOptimizedIndices(coords, Normals, TexCoords);
  525. try
  526. aMeshObject.Clear;
  527. if il.Count > 0 then
  528. begin
  529. RemapReferences(Normals, il);
  530. RemapReferences(TexCoords, il);
  531. RemapAndCleanupReferences(coords, il);
  532. aMeshObject.Vertices := coords;
  533. aMeshObject.Normals := Normals;
  534. aMeshObject.TexCoords := TexCoords;
  535. fg := TFGVertexIndexList.CreateOwned(aMeshObject.FaceGroups);
  536. fg.materialName := materialName;
  537. TFGVertexIndexList(fg).VertexIndices := il;
  538. end;
  539. finally
  540. il.Free;
  541. end;
  542. finally
  543. coords.Free;
  544. Normals.Free;
  545. TexCoords.Free;
  546. end;
  547. end
  548. else
  549. Assert(false,
  550. 'Standardization with multiple facegroups not supported... yet.');
  551. end;
  552. if (mooVertexCache in options) and (aMeshObject.Mode = momFaceGroups) then
  553. begin
  554. for i := 0 to aMeshObject.FaceGroups.Count - 1 do
  555. begin
  556. fg := aMeshObject.FaceGroups[i];
  557. if fg.ClassType = TFGVertexIndexList then
  558. with TFGVertexIndexList(fg) do
  559. begin
  560. if Mode in [fgmmTriangles, fgmmFlatTriangles] then
  561. IncreaseCoherency(VertexIndices, 12);
  562. end;
  563. end;
  564. end;
  565. if mooSortByMaterials in options then
  566. aMeshObject.FaceGroups.SortByMaterial;
  567. end;
  568. procedure FacesSmooth(aMeshObj: TGLMeshObject;
  569. aWeldDistance: Single = 0.0000001; aThreshold: Single = 35.0;
  570. InvertNormals: boolean = false);
  571. Var
  572. i, J, k, L: Integer;
  573. WeldedVertex: TGLAffineVectorList;
  574. TmpIntegerList: TGLIntegerList;
  575. IndexMap: TStringList;
  576. n: TAffineVector;
  577. indicesMap: TGLIntegerList;
  578. Index: Integer;
  579. FaceList: TGLIntegerList;
  580. NormalList: TGLAffineVectorList;
  581. FaceNormalList: TGLAffineVectorList;
  582. FaceGroup: TGLFaceGroup;
  583. fg, FG1: TFGVertexIndexList;
  584. Threshold: Single;
  585. Angle: Single;
  586. ReferenceMap: TGLIntegerList;
  587. ID1, ID2: Integer;
  588. Index1, Index2, Index3: Integer;
  589. function FindReferenceIndex(aID: Integer): Integer;
  590. begin
  591. Result := ReferenceMap[aID];
  592. end;
  593. function iMin(a, b: Integer): Integer;
  594. begin
  595. if a < b then
  596. Result := a
  597. else
  598. Result := b;
  599. end;
  600. function iMax(a, b: Integer): Integer;
  601. begin
  602. if a > b then
  603. Result := a
  604. else
  605. Result := b;
  606. end;
  607. begin
  608. Threshold := aThreshold * Pi / 180.0;
  609. // build the vectices reference map
  610. ReferenceMap := TGLIntegerList.Create;
  611. WeldedVertex := TGLAffineVectorList.Create;
  612. WeldedVertex.Assign(aMeshObj.Vertices);
  613. indicesMap := TGLIntegerList.Create;
  614. // first of all, weld the very closed vertices
  615. WeldVertices(WeldedVertex, indicesMap, aWeldDistance);
  616. // then, rebuild the map list
  617. IndexMap := TStringList.Create;
  618. for i := 0 to WeldedVertex.Count - 1 do
  619. begin
  620. ReferenceMap.Assign(indicesMap);
  621. TmpIntegerList := TGLIntegerList.Create;
  622. Index := ReferenceMap.IndexOf(i);
  623. while Index >= 0 do
  624. begin
  625. TmpIntegerList.Add(Index);
  626. ReferenceMap[Index] := -99999;
  627. Index := ReferenceMap.IndexOf(i);
  628. end;
  629. IndexMap.AddObject(IntToStr(i), TmpIntegerList);
  630. end;
  631. ReferenceMap.Assign(indicesMap);
  632. // never used these, free them all
  633. WeldedVertex.Free;
  634. indicesMap.Free;
  635. // creates a TexPoint list for save face infomation, where s=facegroup index, t=face index
  636. FaceList := TGLIntegerList.Create;
  637. NormalList := TGLAffineVectorList.Create;
  638. FaceNormalList := TGLAffineVectorList.Create;
  639. // NormalIndex := TGLIntegerList.Create;
  640. for i := 0 to aMeshObj.FaceGroups.Count - 1 do
  641. begin
  642. FaceGroup := aMeshObj.FaceGroups[i];
  643. TmpIntegerList := TFGVertexIndexList(FaceGroup).VertexIndices;
  644. for J := 0 to (TmpIntegerList.Count div 3) - 1 do
  645. begin
  646. FaceList.Add(i);
  647. FaceList.Add(J);
  648. CalcPlaneNormal(aMeshObj.Vertices[TmpIntegerList[J * 3 + 0]],
  649. aMeshObj.Vertices[TmpIntegerList[J * 3 + 1]],
  650. aMeshObj.Vertices[TmpIntegerList[J * 3 + 2]], n);
  651. // add three normals for one trangle
  652. FaceNormalList.Add(n);
  653. NormalList.Add(n);
  654. NormalList.Add(n);
  655. NormalList.Add(n);
  656. end;
  657. end;
  658. // do smooth
  659. for i := 0 to (FaceList.Count div 2) - 1 do
  660. begin
  661. Index := FaceList[i * 2 + 0];
  662. Index1 := FaceList[i * 2 + 1];
  663. fg := TFGVertexIndexList(aMeshObj.FaceGroups[Index]);
  664. for J := 0 to 2 do
  665. begin
  666. for k := 0 to (FaceList.Count div 2) - 1 do
  667. begin
  668. Index2 := FaceList[k * 2 + 0];
  669. Index3 := FaceList[k * 2 + 1];
  670. FG1 := TFGVertexIndexList(aMeshObj.FaceGroups[Index2]);
  671. if i <> k then
  672. begin
  673. for L := 0 to 2 do
  674. begin
  675. // two face contain the same vertex
  676. ID1 := FindReferenceIndex(fg.VertexIndices[Index1 * 3 + J]);
  677. ID2 := FindReferenceIndex(FG1.VertexIndices[Index3 * 3 + L]);
  678. if ID1 = ID2 then
  679. begin
  680. Angle := VectorDotProduct(FaceNormalList[i], FaceNormalList[k]);
  681. if Angle > Threshold then
  682. NormalList[i * 3 + J] := VectorAdd(NormalList[i * 3 + J],
  683. FaceNormalList[k]);
  684. end;
  685. end;
  686. end;
  687. end;
  688. n := NormalList[i * 3 + J];
  689. NormalizeVector(n);
  690. NormalList[i * 3 + J] := n;
  691. end;
  692. end;
  693. for i := 0 to (FaceList.Count div 2) - 1 do
  694. begin
  695. Index := FaceList[i * 2 + 0];
  696. fg := TFGVertexIndexList(aMeshObj.FaceGroups[Index]);
  697. Index := FaceList[i * 2 + 1];
  698. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 0)]] :=
  699. NormalList[(i * 3 + 0)];
  700. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 1)]] :=
  701. NormalList[(i * 3 + 1)];
  702. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 2)]] :=
  703. NormalList[(i * 3 + 2)];
  704. if InvertNormals then
  705. begin
  706. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 0)]] :=
  707. VectorNegate(aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 0)]]);
  708. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 1)]] :=
  709. VectorNegate(aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 1)]]);
  710. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 2)]] :=
  711. VectorNegate(aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 2)]]);
  712. end;
  713. end;
  714. FaceList.Free;
  715. NormalList.Free;
  716. FaceNormalList.Free;
  717. ReferenceMap.Free;
  718. for i := 0 to IndexMap.Count - 1 do
  719. IndexMap.Objects[i].Free;
  720. IndexMap.Free;
  721. end;
  722. end.