GLMeshOptimizer.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLMeshOptimizer;
  5. (* Mesh optimization unit *)
  6. interface
  7. uses
  8. System.Classes,
  9. System.Sysutils,
  10. GLVectorTypes,
  11. GLVectorGeometry,
  12. GLVectorFileObjects;
  13. type
  14. TGLMeshOptimizerOption = (mooStandardize, mooVertexCache, mooSortByMaterials,
  15. mooMergeObjects);
  16. TGLMeshOptimizerOptions = set of TGLMeshOptimizerOption;
  17. var
  18. vDefaultMeshOptimizerOptions: TGLMeshOptimizerOptions = [mooStandardize,
  19. mooVertexCache, mooSortByMaterials, mooMergeObjects];
  20. (* Optimize Mesh (list, default options) *)
  21. procedure OptimizeMesh(aList: TGLMeshObjectList; options: TGLMeshOptimizerOptions); overload;
  22. procedure OptimizeMesh(aList: TGLMeshObjectList); overload;
  23. // OptimizeMesh (object, with options)
  24. procedure OptimizeMesh(aMeshObject: TMeshObject; options: TGLMeshOptimizerOptions); overload;
  25. // OptimizeMesh (object, default options)
  26. procedure OptimizeMesh(aMeshObject: TMeshObject); overload;
  27. procedure FacesSmooth(aMeshObj: TMeshObject;
  28. aWeldDistance: Single = 0.0000001; aThreshold: Single = 35.0;
  29. InvertNormals: boolean = false);
  30. // ------------------------------------------------------------------
  31. implementation
  32. // ------------------------------------------------------------------
  33. uses
  34. GLPersistentClasses,
  35. GLVectorLists,
  36. GLMeshUtils;
  37. procedure OptimizeMesh(aList: TGLMeshObjectList);
  38. begin
  39. OptimizeMesh(aList, vDefaultMeshOptimizerOptions);
  40. end;
  41. procedure OptimizeMesh(aList: TGLMeshObjectList;
  42. options: TGLMeshOptimizerOptions);
  43. var
  44. i, k: Integer;
  45. mob, mo: TMeshObject;
  46. fg: TGLFaceGroup;
  47. fgvi: TFGVertexIndexList;
  48. begin
  49. // optimize all mesh objects
  50. for i := 0 to aList.Count - 1 do
  51. begin
  52. OptimizeMesh(aList[i], options);
  53. end;
  54. if (mooStandardize in options) then
  55. begin
  56. // drop mesh objects that have become empty
  57. for i := aList.Count - 1 downto 0 do
  58. begin
  59. if (aList[i].Mode = momFaceGroups) and (aList[i].FaceGroups.Count = 0)
  60. then
  61. aList[i].Free;
  62. end;
  63. end;
  64. if (aList.Count > 0) and (mooMergeObjects in options) then
  65. begin
  66. mob := aList[0];
  67. Assert(mob.Mode = momFaceGroups);
  68. for i := 1 to aList.Count - 1 do
  69. begin
  70. mo := aList[i];
  71. Assert(mo.Mode = momFaceGroups);
  72. k := mob.Vertices.Count;
  73. mob.Vertices.Add(mo.Vertices);
  74. mob.Normals.Add(mo.Normals);
  75. mob.TexCoords.Add(mo.TexCoords);
  76. while mo.FaceGroups.Count > 0 do
  77. begin
  78. fg := mo.FaceGroups[0];
  79. fgvi := (fg as TFGVertexIndexList);
  80. fgvi.Owner := mob.FaceGroups;
  81. mob.FaceGroups.Add(fgvi);
  82. mo.FaceGroups.Delete(0);
  83. fgvi.VertexIndices.Offset(k);
  84. end;
  85. end;
  86. for i := aList.Count - 1 downto 1 do
  87. aList[i].Free;
  88. end;
  89. end;
  90. procedure OptimizeMesh(aMeshObject: TMeshObject);
  91. begin
  92. OptimizeMesh(aMeshObject, vDefaultMeshOptimizerOptions);
  93. end;
  94. procedure OptimizeMesh(aMeshObject: TMeshObject;
  95. options: TGLMeshOptimizerOptions);
  96. var
  97. i: Integer;
  98. fg: TGLFaceGroup;
  99. coords, TexCoords, Normals: TAffineVectorList;
  100. il: TIntegerList;
  101. materialName: String;
  102. begin
  103. if (mooMergeObjects in options) then
  104. begin
  105. if aMeshObject.Mode = momFaceGroups then
  106. begin
  107. // remove empty facegroups
  108. for i := aMeshObject.FaceGroups.Count - 1 downto 0 do
  109. begin
  110. fg := aMeshObject.FaceGroups[i];
  111. if fg.TriangleCount = 0 then
  112. fg.Free;
  113. end;
  114. end;
  115. end;
  116. if (mooStandardize in options) then
  117. begin
  118. if (aMeshObject.Mode <> momFaceGroups) or (aMeshObject.FaceGroups.Count <= 1)
  119. then
  120. begin
  121. if aMeshObject.FaceGroups.Count = 1 then
  122. materialName := aMeshObject.FaceGroups[0].materialName;
  123. TexCoords := TAffineVectorList.Create;
  124. Normals := TAffineVectorList.Create;
  125. coords := aMeshObject.ExtractTriangles(TexCoords, Normals);
  126. try
  127. il := BuildVectorCountOptimizedIndices(coords, Normals, TexCoords);
  128. try
  129. aMeshObject.Clear;
  130. if il.Count > 0 then
  131. begin
  132. RemapReferences(Normals, il);
  133. RemapReferences(TexCoords, il);
  134. RemapAndCleanupReferences(coords, il);
  135. aMeshObject.Vertices := coords;
  136. aMeshObject.Normals := Normals;
  137. aMeshObject.TexCoords := TexCoords;
  138. fg := TFGVertexIndexList.CreateOwned(aMeshObject.FaceGroups);
  139. fg.materialName := materialName;
  140. TFGVertexIndexList(fg).VertexIndices := il;
  141. end;
  142. finally
  143. il.Free;
  144. end;
  145. finally
  146. coords.Free;
  147. Normals.Free;
  148. TexCoords.Free;
  149. end;
  150. end
  151. else
  152. Assert(false,
  153. 'Standardization with multiple facegroups not supported... yet.');
  154. end;
  155. if (mooVertexCache in options) and (aMeshObject.Mode = momFaceGroups) then
  156. begin
  157. for i := 0 to aMeshObject.FaceGroups.Count - 1 do
  158. begin
  159. fg := aMeshObject.FaceGroups[i];
  160. if fg.ClassType = TFGVertexIndexList then
  161. with TFGVertexIndexList(fg) do
  162. begin
  163. if Mode in [fgmmTriangles, fgmmFlatTriangles] then
  164. IncreaseCoherency(VertexIndices, 12);
  165. end;
  166. end;
  167. end;
  168. if mooSortByMaterials in options then
  169. aMeshObject.FaceGroups.SortByMaterial;
  170. end;
  171. procedure FacesSmooth(aMeshObj: TMeshObject;
  172. aWeldDistance: Single = 0.0000001; aThreshold: Single = 35.0;
  173. InvertNormals: boolean = false);
  174. Var
  175. i, J, k, L: Integer;
  176. WeldedVertex: TAffineVectorList;
  177. TmpIntegerList: TIntegerList;
  178. IndexMap: TStringList;
  179. n: TAffineVector;
  180. indicesMap: TIntegerList;
  181. Index: Integer;
  182. FaceList: TIntegerList;
  183. NormalList: TAffineVectorList;
  184. FaceNormalList: TAffineVectorList;
  185. FaceGroup: TGLFaceGroup;
  186. fg, FG1: TFGVertexIndexList;
  187. Threshold: Single;
  188. Angle: Single;
  189. ReferenceMap: TIntegerList;
  190. ID1, ID2: Integer;
  191. Index1, Index2, Index3: Integer;
  192. function FindReferenceIndex(aID: Integer): Integer;
  193. begin
  194. Result := ReferenceMap[aID];
  195. end;
  196. function iMin(a, b: Integer): Integer;
  197. begin
  198. if a < b then
  199. Result := a
  200. else
  201. Result := b;
  202. end;
  203. function iMax(a, b: Integer): Integer;
  204. begin
  205. if a > b then
  206. Result := a
  207. else
  208. Result := b;
  209. end;
  210. begin
  211. Threshold := aThreshold * Pi / 180.0;
  212. // build the vectices reference map
  213. ReferenceMap := TIntegerList.Create;
  214. WeldedVertex := TAffineVectorList.Create;
  215. WeldedVertex.Assign(aMeshObj.Vertices);
  216. indicesMap := TIntegerList.Create;
  217. // first of all, weld the very closed vertices
  218. WeldVertices(WeldedVertex, indicesMap, aWeldDistance);
  219. // then, rebuild the map list
  220. IndexMap := TStringList.Create;
  221. for i := 0 to WeldedVertex.Count - 1 do
  222. begin
  223. ReferenceMap.Assign(indicesMap);
  224. TmpIntegerList := TIntegerList.Create;
  225. Index := ReferenceMap.IndexOf(i);
  226. while Index >= 0 do
  227. begin
  228. TmpIntegerList.Add(Index);
  229. ReferenceMap[Index] := -99999;
  230. Index := ReferenceMap.IndexOf(i);
  231. end;
  232. IndexMap.AddObject(IntToStr(i), TmpIntegerList);
  233. end;
  234. ReferenceMap.Assign(indicesMap);
  235. // never used these, free them all
  236. WeldedVertex.Free;
  237. indicesMap.Free;
  238. // creates a TexPoint list for save face infomation, where s=facegroup index, t=face index
  239. FaceList := TIntegerList.Create;
  240. NormalList := TAffineVectorList.Create;
  241. FaceNormalList := TAffineVectorList.Create;
  242. // NormalIndex := TIntegerList.Create;
  243. for i := 0 to aMeshObj.FaceGroups.Count - 1 do
  244. begin
  245. FaceGroup := aMeshObj.FaceGroups[i];
  246. TmpIntegerList := TFGVertexIndexList(FaceGroup).VertexIndices;
  247. for J := 0 to (TmpIntegerList.Count div 3) - 1 do
  248. begin
  249. FaceList.Add(i);
  250. FaceList.Add(J);
  251. CalcPlaneNormal(aMeshObj.Vertices[TmpIntegerList[J * 3 + 0]],
  252. aMeshObj.Vertices[TmpIntegerList[J * 3 + 1]],
  253. aMeshObj.Vertices[TmpIntegerList[J * 3 + 2]], n);
  254. // add three normals for one trangle
  255. FaceNormalList.Add(n);
  256. NormalList.Add(n);
  257. NormalList.Add(n);
  258. NormalList.Add(n);
  259. end;
  260. end;
  261. // do smooth
  262. for i := 0 to (FaceList.Count div 2) - 1 do
  263. begin
  264. Index := FaceList[i * 2 + 0];
  265. Index1 := FaceList[i * 2 + 1];
  266. fg := TFGVertexIndexList(aMeshObj.FaceGroups[Index]);
  267. for J := 0 to 2 do
  268. begin
  269. for k := 0 to (FaceList.Count div 2) - 1 do
  270. begin
  271. Index2 := FaceList[k * 2 + 0];
  272. Index3 := FaceList[k * 2 + 1];
  273. FG1 := TFGVertexIndexList(aMeshObj.FaceGroups[Index2]);
  274. if i <> k then
  275. begin
  276. for L := 0 to 2 do
  277. begin
  278. // two face contain the same vertex
  279. ID1 := FindReferenceIndex(fg.VertexIndices[Index1 * 3 + J]);
  280. ID2 := FindReferenceIndex(FG1.VertexIndices[Index3 * 3 + L]);
  281. if ID1 = ID2 then
  282. begin
  283. Angle := VectorDotProduct(FaceNormalList[i], FaceNormalList[k]);
  284. if Angle > Threshold then
  285. NormalList[i * 3 + J] := VectorAdd(NormalList[i * 3 + J],
  286. FaceNormalList[k]);
  287. end;
  288. end;
  289. end;
  290. end;
  291. n := NormalList[i * 3 + J];
  292. NormalizeVector(n);
  293. NormalList[i * 3 + J] := n;
  294. end;
  295. end;
  296. for i := 0 to (FaceList.Count div 2) - 1 do
  297. begin
  298. Index := FaceList[i * 2 + 0];
  299. fg := TFGVertexIndexList(aMeshObj.FaceGroups[Index]);
  300. Index := FaceList[i * 2 + 1];
  301. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 0)]] :=
  302. NormalList[(i * 3 + 0)];
  303. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 1)]] :=
  304. NormalList[(i * 3 + 1)];
  305. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 2)]] :=
  306. NormalList[(i * 3 + 2)];
  307. if InvertNormals then
  308. begin
  309. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 0)]] :=
  310. VectorNegate(aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 0)]]);
  311. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 1)]] :=
  312. VectorNegate(aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 1)]]);
  313. aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 2)]] :=
  314. VectorNegate(aMeshObj.Normals[fg.VertexIndices[(Index * 3 + 2)]]);
  315. end;
  316. end;
  317. FaceList.Free;
  318. NormalList.Free;
  319. FaceNormalList.Free;
  320. ReferenceMap.Free;
  321. for i := 0 to IndexMap.Count - 1 do
  322. IndexMap.Objects[i].Free;
  323. IndexMap.Free;
  324. end;
  325. end.