LZScene

Форк
0
/
GLMeshOptimizer.pas 
327 строк · 10.8 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
   Mesh optimization for GLScene.
6

7
	 History :  
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
11
	 
12
}
13
unit GLMeshOptimizer;
14

15
interface
16

17
uses
18
  Classes, Sysutils, GLVectorGeometry, GLVectorFileObjects;
19

20
type
21

22
   // TMeshOptimizerOptions
23
   //
24
   TMeshOptimizerOption = (mooStandardize, mooVertexCache, mooSortByMaterials,
25
                           mooMergeObjects);
26
   TMeshOptimizerOptions = set of TMeshOptimizerOption;
27

28
var
29
   vDefaultMeshOptimizerOptions : TMeshOptimizerOptions =
30
      [mooStandardize, mooVertexCache, mooSortByMaterials, mooMergeObjects];
31

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);
37

38

39
// ------------------------------------------------------------------
40
// ------------------------------------------------------------------
41
// ------------------------------------------------------------------
42
implementation
43
// ------------------------------------------------------------------
44
// ------------------------------------------------------------------
45
// ------------------------------------------------------------------
46

47
uses
48
  GLPersistentClasses, GLVectorLists, GLMeshUtils;
49

50
// OptimizeMesh (list, default options)
51
//
52
procedure OptimizeMesh(aList : TGLMeshObjectList);
53
begin
54
   OptimizeMesh(aList, vDefaultMeshOptimizerOptions);
55
end;
56

57
// OptimizeMesh (list, with options)
58
//
59
procedure OptimizeMesh(aList : TGLMeshObjectList; options : TMeshOptimizerOptions);
60
var
61
   i, k : Integer;
62
   mob, mo : TGLMeshObject;
63
   fg : TGLFaceGroup;
64
   fgvi : TFGVertexIndexList;
65
begin
66
   // optimize all mesh objects
67
   for i:=0 to aList.Count-1 do begin
68
      OptimizeMesh(aList[i], options);
69
   end;
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
74
            aList[i].Free;
75
      end;
76
   end;
77
   if (aList.Count>0) and (mooMergeObjects in options) then begin
78
      mob:=aList[0];
79
      Assert(mob.Mode=momFaceGroups);
80
      for i:=1 to aList.Count-1 do begin
81
         mo:=aList[i];
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
88
            fg:=mo.FaceGroups[0];
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);
94
         end;
95
      end;
96
      for i:=aList.Count-1 downto 1 do
97
         aList[i].Free;
98
   end;
99
end;
100

101
// OptimizeMesh (object, default options)
102
//
103
procedure OptimizeMesh(aMeshObject : TGLMeshObject);
104
begin
105
   OptimizeMesh(aMeshObject, vDefaultMeshOptimizerOptions);
106
end;
107

108
// OptimizeMesh (object, with options)
109
//
110
procedure OptimizeMesh(aMeshObject : TGLMeshObject; options : TMeshOptimizerOptions);
111
var
112
   i : Integer;
113
   fg : TGLFaceGroup;
114
   coords, texCoords, normals : TAffineVectorList;
115
   il : TIntegerList;
116
   materialName : String;
117
begin
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
124
               fg.Free;
125
         end;
126
      end;
127
   end;
128

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);
136
         try
137
            il:=BuildVectorCountOptimizedIndices(coords, normals, texCoords);
138
            try
139
               aMeshObject.Clear;
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;
150
               end;
151
            finally
152
               il.Free;
153
            end;
154
         finally
155
            coords.Free;
156
            normals.Free;
157
            texCoords.Free;
158
         end;
159
      end else Assert(False, 'Standardization with multiple facegroups not supported... yet.');
160
   end;
161

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);
168
         end;
169
      end;
170
   end;
171

172
   if mooSortByMaterials in options then
173
      aMeshObject.FaceGroups.SortByMaterial;
174
end;
175

176

177

178
procedure FacesSmooth(aMeshObj: TGLMeshObject; aWeldDistance: Single=0.0000001; aThreshold: Single=35.0; InvertNormals:boolean=false);
179
Var
180
  I, J, K, L: integer;
181
  WeldedVertex: TAffineVectorList;
182
  TmpIntegerList: TIntegerList;
183
  IndexMap: TStringList;
184
  n: TAffineVector;
185
  indicesMap : TIntegerList;
186
  Index: Integer;
187
  FaceList: TIntegerList;
188
  NormalList: TAffineVectorList;
189
  FaceNormalList: TAffineVectorList;
190
  FaceGroup: TGLFaceGroup;
191
  FG, FG1: TFGVertexIndexList;
192
  Threshold: Single;
193
  Angle: Single;
194
  ReferenceMap: TIntegerList;
195
  ID1, ID2: Integer;
196
  Index1, Index2, Index3: Integer;
197

198
  function FindReferenceIndex(aID: Integer): Integer;
199
  begin
200
    Result := ReferenceMap[aID];
201
  end;
202
  function iMin(a, b: Integer): Integer;
203
  begin
204
    if a<b then
205
      Result := a
206
    else
207
      Result := b;
208
  end;
209
  function iMax(a, b: Integer): Integer;
210
  begin
211
    if a>b then
212
      Result := a
213
    else
214
      Result := b;
215
  end;
216
begin
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
228
  begin
229
    ReferenceMap.Assign(indicesMap);
230
    TmpIntegerList := TIntegerList.Create;
231
    Index := ReferenceMap.IndexOf(I);
232
    while Index>=0 do
233
    begin
234
      TmpIntegerList.Add(Index);
235
      ReferenceMap[Index] := -99999;
236
      Index := ReferenceMap.IndexOf(I);
237
    end;
238
    IndexMap.AddObject(IntToStr(I), TmpIntegerList);
239
  end;
240
  ReferenceMap.Assign(indicesMap);
241
  //never used these, free them all
242
  WeldedVertex.free;
243
  indicesMap.free;
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
250
  begin
251
    FaceGroup := aMeshObj.FaceGroups[I];
252
    TmpIntegerList := TFGVertexIndexList(FaceGroup).VertexIndices;
253
    for J:=0 to (TmpIntegerList.Count div 3)-1 do
254
    begin
255
      FaceList.Add(I);
256
      FaceList.Add(J);
257
      CalcPlaneNormal(aMeshObj.Vertices[TmpIntegerList[J * 3 + 0]],
258
        aMeshObj.Vertices[TmpIntegerList[J * 3 + 1]],
259
        aMeshObj.Vertices[TmpIntegerList[J * 3 + 2]],
260
        n);
261
      //add three normals for one trangle
262
      FaceNormalList.Add(n);
263
      NormalList.Add(n);
264
      NormalList.Add(n);
265
      NormalList.Add(n);
266
    end;
267
  end;
268
  //do smooth
269
  for I:=0 to (FaceList.Count div 2)-1 do
270
  begin
271
    Index := FaceList[I*2+0];
272
    Index1 := FaceList[I*2+1];
273
    FG := TFGVertexIndexList(aMeshObj.FaceGroups[Index]);
274
    for J:=0 to 2 do
275
    begin
276
      for K:=0 to (FaceList.Count div 2)-1 do
277
      begin
278
        Index2 := FaceList[K*2+0];
279
        Index3 := FaceList[K*2+1];
280
        FG1 := TFGVertexIndexList(aMeshObj.FaceGroups[Index2]);
281
        if I<>K then
282
        begin
283
          for L:=0 to 2 do
284
          begin
285
            //two face contain the same vertex
286
            ID1 := FindReferenceIndex(FG.VertexIndices[Index1*3+J]);
287
            ID2 := FindReferenceIndex(FG1.VertexIndices[Index3*3+L]);
288
            if ID1=ID2 then
289
            begin
290
              Angle := VectorDotProduct(FaceNormalList[I],FaceNormalList[K]);
291
              if angle>Threshold then
292
                NormalList[I*3+J] := VectorAdd(NormalList[I*3+J],FaceNormalList[K]);
293
            end;
294
          end;
295
        end;
296
      end;
297
      n := NormalList[I*3+J];
298
      NormalizeVector(n);
299
      NormalList[I*3+J] := n;
300
    end;
301
  end;
302
  for I:=0 to (FaceList.Count div 2)-1 do
303
  begin
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
311
    begin
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)]]);
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

326

327
end.
328

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.