2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Mesh optimization for GLScene.
8
27/11/07 - mrqzzz - added FacesSmooth InvertNormals parameter. Now smoothes correctly.
9
21/08/03 - EG - Added basic mooStandardize support
10
03/06/03 - EG - Creation
18
Classes, Sysutils, GLVectorGeometry, GLVectorFileObjects;
22
// TMeshOptimizerOptions
24
TMeshOptimizerOption = (mooStandardize, mooVertexCache, mooSortByMaterials,
26
TMeshOptimizerOptions = set of TMeshOptimizerOption;
29
vDefaultMeshOptimizerOptions : TMeshOptimizerOptions =
30
[mooStandardize, mooVertexCache, mooSortByMaterials, mooMergeObjects];
32
procedure OptimizeMesh(aList : TGLMeshObjectList; options : TMeshOptimizerOptions); overload;
33
procedure OptimizeMesh(aList : TGLMeshObjectList); overload;
34
procedure OptimizeMesh(aMeshObject : TGLMeshObject; options : TMeshOptimizerOptions); overload;
35
procedure OptimizeMesh(aMeshObject : TGLMeshObject); overload;
36
procedure FacesSmooth(aMeshObj: TGLMeshObject; aWeldDistance: Single=0.0000001; aThreshold: Single=35.0; InvertNormals:boolean=false);
39
// ------------------------------------------------------------------
40
// ------------------------------------------------------------------
41
// ------------------------------------------------------------------
43
// ------------------------------------------------------------------
44
// ------------------------------------------------------------------
45
// ------------------------------------------------------------------
48
GLPersistentClasses, GLVectorLists, GLMeshUtils;
50
// OptimizeMesh (list, default options)
52
procedure OptimizeMesh(aList : TGLMeshObjectList);
54
OptimizeMesh(aList, vDefaultMeshOptimizerOptions);
57
// OptimizeMesh (list, with options)
59
procedure OptimizeMesh(aList : TGLMeshObjectList; options : TMeshOptimizerOptions);
62
mob, mo : TGLMeshObject;
64
fgvi : TFGVertexIndexList;
66
// optimize all mesh objects
67
for i:=0 to aList.Count-1 do begin
68
OptimizeMesh(aList[i], options);
70
if (mooStandardize in options) then begin
71
// drop mesh objects that have become empty
72
for i:=aList.Count-1 downto 0 do begin
73
if (aList[i].Mode=momFaceGroups) and (aList[i].FaceGroups.Count=0) then
77
if (aList.Count>0) and (mooMergeObjects in options) then begin
79
Assert(mob.Mode=momFaceGroups);
80
for i:=1 to aList.Count-1 do begin
82
Assert(mo.Mode=momFaceGroups);
83
k:=mob.Vertices.Count;
84
mob.Vertices.Add(mo.Vertices);
85
mob.Normals.Add(mo.Normals);
86
mob.TexCoords.Add(mo.TexCoords);
87
while mo.FaceGroups.Count>0 do begin
89
fgvi:=(fg as TFGVertexIndexList);
90
fgvi.Owner:=mob.FaceGroups;
91
mob.FaceGroups.Add(fgvi);
92
mo.FaceGroups.Delete(0);
93
fgvi.VertexIndices.Offset(k);
96
for i:=aList.Count-1 downto 1 do
101
// OptimizeMesh (object, default options)
103
procedure OptimizeMesh(aMeshObject : TGLMeshObject);
105
OptimizeMesh(aMeshObject, vDefaultMeshOptimizerOptions);
108
// OptimizeMesh (object, with options)
110
procedure OptimizeMesh(aMeshObject : TGLMeshObject; options : TMeshOptimizerOptions);
114
coords, texCoords, normals : TAffineVectorList;
116
materialName : String;
118
if (mooMergeObjects in options) then begin
119
if aMeshObject.Mode=momFaceGroups then begin
120
// remove empty facegroups
121
for i:=aMeshObject.FaceGroups.Count-1 downto 0 do begin
122
fg:=aMeshObject.FaceGroups[i];
123
if fg.TriangleCount=0 then
129
if (mooStandardize in options) then begin
130
if (aMeshObject.Mode<>momFaceGroups) or (aMeshObject.FaceGroups.Count<=1) then begin
131
if aMeshObject.FaceGroups.Count=1 then
132
materialName:=aMeshObject.FaceGroups[0].MaterialName;
133
texCoords:=TAffineVectorList.Create;
134
normals:=TAffineVectorList.Create;
135
coords:=aMeshObject.ExtractTriangles(texCoords, normals);
137
il:=BuildVectorCountOptimizedIndices(coords, normals, texCoords);
140
if il.Count>0 then begin
141
RemapReferences(normals, il);
142
RemapReferences(texCoords, il);
143
RemapAndCleanupReferences(coords, il);
144
aMeshObject.Vertices:=coords;
145
aMeshObject.Normals:=normals;
146
aMeshObject.TexCoords:=texCoords;
147
fg:=TFGVertexIndexList.CreateOwned(aMeshObject.FaceGroups);
148
fg.MaterialName:=materialName;
149
TFGVertexIndexList(fg).VertexIndices:=il;
159
end else Assert(False, 'Standardization with multiple facegroups not supported... yet.');
162
if (mooVertexCache in options) and (aMeshObject.Mode=momFaceGroups) then begin
163
for i:=0 to aMeshObject.FaceGroups.Count-1 do begin
164
fg:=aMeshObject.FaceGroups[i];
165
if fg.ClassType=TFGVertexIndexList then with TFGVertexIndexList(fg) do begin
166
if Mode in [fgmmTriangles, fgmmFlatTriangles] then
167
IncreaseCoherency(VertexIndices, 12);
172
if mooSortByMaterials in options then
173
aMeshObject.FaceGroups.SortByMaterial;
178
procedure FacesSmooth(aMeshObj: TGLMeshObject; aWeldDistance: Single=0.0000001; aThreshold: Single=35.0; InvertNormals:boolean=false);
181
WeldedVertex: TAffineVectorList;
182
TmpIntegerList: TIntegerList;
183
IndexMap: TStringList;
185
indicesMap : TIntegerList;
187
FaceList: TIntegerList;
188
NormalList: TAffineVectorList;
189
FaceNormalList: TAffineVectorList;
190
FaceGroup: TGLFaceGroup;
191
FG, FG1: TFGVertexIndexList;
194
ReferenceMap: TIntegerList;
196
Index1, Index2, Index3: Integer;
198
function FindReferenceIndex(aID: Integer): Integer;
200
Result := ReferenceMap[aID];
202
function iMin(a, b: Integer): Integer;
209
function iMax(a, b: Integer): Integer;
217
Threshold := aThreshold * Pi/180.0;
218
//build the vectices reference map
219
ReferenceMap := TIntegerList.Create;
220
WeldedVertex := TAffineVectorList.Create;
221
WeldedVertex.Assign(aMeshObj.Vertices);
222
indicesMap := TIntegerList.Create;
223
//first of all, weld the very closed vertices
224
WeldVertices(WeldedVertex, indicesMap, aWeldDistance);
225
//then, rebuild the map list
226
IndexMap := TStringList.Create;
227
for I:=0 to WeldedVertex.Count-1 do
229
ReferenceMap.Assign(indicesMap);
230
TmpIntegerList := TIntegerList.Create;
231
Index := ReferenceMap.IndexOf(I);
234
TmpIntegerList.Add(Index);
235
ReferenceMap[Index] := -99999;
236
Index := ReferenceMap.IndexOf(I);
238
IndexMap.AddObject(IntToStr(I), TmpIntegerList);
240
ReferenceMap.Assign(indicesMap);
241
//never used these, free them all
244
//create a TexPoint list for save face infomation, where s=facegroup index, t=face index
245
FaceList := TIntegerList.Create;
246
NormalList := TAffineVectorList.Create;
247
FaceNormalList := TAffineVectorList.Create;
248
//NormalIndex := TIntegerList.Create;
249
for I:=0 to aMeshObj.FaceGroups.Count-1 do
251
FaceGroup := aMeshObj.FaceGroups[I];
252
TmpIntegerList := TFGVertexIndexList(FaceGroup).VertexIndices;
253
for J:=0 to (TmpIntegerList.Count div 3)-1 do
257
CalcPlaneNormal(aMeshObj.Vertices[TmpIntegerList[J * 3 + 0]],
258
aMeshObj.Vertices[TmpIntegerList[J * 3 + 1]],
259
aMeshObj.Vertices[TmpIntegerList[J * 3 + 2]],
261
//add three normals for one trangle
262
FaceNormalList.Add(n);
269
for I:=0 to (FaceList.Count div 2)-1 do
271
Index := FaceList[I*2+0];
272
Index1 := FaceList[I*2+1];
273
FG := TFGVertexIndexList(aMeshObj.FaceGroups[Index]);
276
for K:=0 to (FaceList.Count div 2)-1 do
278
Index2 := FaceList[K*2+0];
279
Index3 := FaceList[K*2+1];
280
FG1 := TFGVertexIndexList(aMeshObj.FaceGroups[Index2]);
285
//two face contain the same vertex
286
ID1 := FindReferenceIndex(FG.VertexIndices[Index1*3+J]);
287
ID2 := FindReferenceIndex(FG1.VertexIndices[Index3*3+L]);
290
Angle := VectorDotProduct(FaceNormalList[I],FaceNormalList[K]);
291
if angle>Threshold then
292
NormalList[I*3+J] := VectorAdd(NormalList[I*3+J],FaceNormalList[K]);
297
n := NormalList[I*3+J];
299
NormalList[I*3+J] := n;
302
for I:=0 to (FaceList.Count div 2)-1 do
304
Index := FaceList[I*2+0];
305
FG := TFGVertexIndexList(aMeshObj.FaceGroups[Index]);
306
Index := FaceList[I*2+1];
307
aMeshObj.Normals[FG.VertexIndices[(Index*3+0)]] := NormalList[(I*3+0)];
308
aMeshObj.Normals[FG.VertexIndices[(Index*3+1)]] := NormalList[(I*3+1)];
309
aMeshObj.Normals[FG.VertexIndices[(Index*3+2)]] := NormalList[(I*3+2)];
310
if InvertNormals then
312
aMeshObj.Normals[FG.VertexIndices[(Index*3+0)]] := VectorNegate(aMeshObj.Normals[FG.VertexIndices[(Index*3+0)]]);
313
aMeshObj.Normals[FG.VertexIndices[(Index*3+1)]] := VectorNegate(aMeshObj.Normals[FG.VertexIndices[(Index*3+1)]]);
314
aMeshObj.Normals[FG.VertexIndices[(Index*3+2)]] := VectorNegate(aMeshObj.Normals[FG.VertexIndices[(Index*3+2)]]);
321
for I:=0 to IndexMap.Count-1 do
322
IndexMap.Objects[I].free;