LZScene

Форк
0
/
GLBumpMapping.pas 
463 строки · 13.9 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
   Some useful methods for setting up bump maps.
6

7
    History :  
8
       17/11/14 - PW - Removed function RGB that is included in GLCrossPlatform.pas
9
       10/11/12 - PW - Added CPP compatibility: changed vector arrays to records with arrays
10
       08/07/04 - LR - Replace Graphics by GLCrossPlatform for Linux
11
       30/03/04 - SG - Minor optimizations
12
       22/09/03 - SG - Partially fixed tangent space normal map creation,
13
                          Fixed normal blending coefficients
14
       18/09/03 - SG - Added methods for creating normal maps,
15
                          CreateTangentSpaceNormalMap is a little buggy
16
       28/07/03 - SG - Creation
17
    
18
}
19
unit GLBumpMapping;
20

21
interface
22

23
uses
24
  GLVectorGeometry, GLVectorLists, GLCrossPlatform, GLVectorTypes;
25

26
type
27
  TNormalMapSpace = (nmsObject, nmsTangent);
28

29
// Object space
30
procedure CalcObjectSpaceLightVectors(Light : TAffineVector;
31
                                      Vertices: TAffineVectorList;
32
                                      Colors: TVectorList);
33

34
// Tangent space
35
procedure SetupTangentSpace(Vertices, Normals, TexCoords,
36
                            Tangents, BiNormals : TAffineVectorList);
37
procedure CalcTangentSpaceLightVectors(Light : TAffineVector;
38
                                       Vertices, Normals,
39
                                       Tangents, BiNormals : TAffineVectorList;
40
                                       Colors: TVectorList);
41

42
function CreateObjectSpaceNormalMap(Width, Height : Integer;
43
                                    HiNormals,HiTexCoords : TAffineVectorList) : TGLBitmap;
44
function CreateTangentSpaceNormalMap(Width, Height : Integer;
45
                                     HiNormals, HiTexCoords,
46
                                     LoNormals, LoTexCoords,
47
                                     Tangents, BiNormals : TAffineVectorList) : TGLBitmap;
48

49
implementation
50

51
// CalcObjectSpaceLightVectors
52
//
53
procedure CalcObjectSpaceLightVectors(Light : TAffineVector;
54
                                      Vertices: TAffineVectorList;
55
                                      Colors: TVectorList);
56
var
57
  i   : Integer;
58
  vec : TAffineVector;
59
begin
60
  Colors.Count:=Vertices.Count;
61
  for i:=0 to Vertices.Count-1 do begin
62
    vec:=VectorNormalize(VectorSubtract(Light,Vertices[i]));
63
    Colors[i]:=VectorMake(VectorAdd(VectorScale(vec,0.5),0.5),1);
64
  end;
65
end;
66

67
// SetupTangentSpace
68
//
69
procedure SetupTangentSpace(Vertices, Normals, TexCoords,
70
                            Tangents, BiNormals : TAffineVectorList);
71
var
72
  i,j        : Integer;
73
  v,n,t      : TAffineMatrix;
74
  vt,tt      : TAffineVector;
75
  interp,dot : Single;
76

77
  procedure SortVertexData(sortidx : Integer);
78
  begin
79
    if t.X.V[sortidx]<t.Y.V[sortidx] then begin
80
      vt:=v.X;   tt:=t.X;
81
      v.X:=v.Y; t.X:=t.Y;
82
      v.Y:=vt;   t.Y:=tt;
83
    end;
84
    if t.V[0].V[sortidx]<t.V[2].V[sortidx] then begin
85
      vt:=v.V[0];   tt:=t.V[0];
86
      v.V[0]:=v.V[2]; t.V[0]:=t.V[2];
87
      v.V[2]:=vt;   t.V[2]:=tt;
88
    end;
89
    if t.V[1].V[sortidx]<t.V[2].V[sortidx] then begin
90
      vt:=v.V[1];   tt:=t.V[1];
91
      v.V[1]:=v.V[2]; t.V[1]:=t.V[2];
92
      v.V[2]:=vt;   t.V[2]:=tt;
93
    end;
94
  end;
95

96
begin
97
  for i:=0 to (Vertices.Count div 3)-1 do begin
98
    // Get triangle data
99
    for j:=0 to 2 do begin
100
      v.V[j]:=Vertices[3*i+j];
101
      n.V[j]:=Normals[3*i+j];
102
      t.V[j]:=TexCoords[3*i+j];
103
    end;
104

105
    for j:=0 to 2 do begin
106
      // Compute tangent
107
      SortVertexData(1);
108

109
      if (t.V[2].V[1]-t.V[0].V[1]) = 0 then interp:=1
110
      else interp:=(t.V[1].V[1]-t.V[0].V[1])/(t.V[2].V[1]-t.V[0].V[1]);
111

112
      vt:=VectorLerp(v.V[0],v.V[2],interp);
113
      interp:=t.V[0].V[0]+(t.V[2].V[0]-t.V[0].V[0])*interp;
114
      vt:=VectorSubtract(vt,v.V[1]);
115
      if t.V[1].V[0]<interp then vt:=VectorNegate(vt);
116
      dot:=VectorDotProduct(vt,n.V[j]);
117
      vt.V[0]:=vt.V[0]-n.V[j].V[0]*dot;
118
      vt.V[1]:=vt.V[1]-n.V[j].V[1]*dot;
119
      vt.V[2]:=vt.V[2]-n.V[j].V[2]*dot;
120
      Tangents.Add(VectorNormalize(vt));
121

122
      // Compute Bi-Normal
123
      SortVertexData(0);
124

125
      if (t.V[2].V[0]-t.V[0].V[0]) = 0 then interp:=1
126
      else interp:=(t.V[1].V[0]-t.V[0].V[0])/(t.V[2].V[0]-t.V[0].V[0]);
127

128
      vt:=VectorLerp(v.V[0],v.V[2],interp);
129
      interp:=t.V[0].V[1]+(t.V[2].V[1]-t.V[0].V[1])*interp;
130
      vt:=VectorSubtract(vt,v.V[1]);
131
      if t.V[1].V[1]<interp then vt:=VectorNegate(vt);
132
      dot:=VectorDotProduct(vt,n.V[j]);
133
      vt.V[0]:=vt.V[0]-n.V[j].V[0]*dot;
134
      vt.V[1]:=vt.V[1]-n.V[j].V[1]*dot;
135
      vt.V[2]:=vt.V[2]-n.V[j].V[2]*dot;
136
      BiNormals.Add(VectorNormalize(vt));
137
    end;
138
  end;
139
end;
140

141
// CalcTangentSpaceLightVectors
142
//
143
procedure CalcTangentSpaceLightVectors(Light : TAffineVector;
144
                                       Vertices, Normals,
145
                                       Tangents, BiNormals : TAffineVectorList;
146
                                       Colors: TVectorList);
147
var
148
  i   : Integer;
149
  mat : TAffineMatrix;
150
  vec : TAffineVector;
151
begin
152
  Colors.Count:=Vertices.Count;
153
  for i:=0 to Vertices.Count-1 do begin
154
    mat.V[0]:=Tangents[i];
155
    mat.V[1]:=BiNormals[i];
156
    mat.V[2]:=Normals[i];
157
    TransposeMatrix(mat);
158
    vec:=VectorNormalize(VectorTransform(VectorSubtract(Light,Vertices[i]),mat));
159
    vec.V[0]:=-vec.V[0];
160
    Colors[i]:=VectorMake(VectorAdd(VectorScale(vec,0.5),0.5),1);
161
  end;
162
end;
163

164
// ------------------------------------------------------------------------
165
// Local functions used for creating normal maps
166
// ------------------------------------------------------------------------
167

168
function ConvertNormalToColor(normal : TAffineVector) : TDelphiColor;
169
var
170
  r,g,b : Byte;
171
begin
172
  r:=Round(255*(normal.X*0.5+0.5));
173
  g:=Round(255*(normal.Y*0.5+0.5));
174
  b:=Round(255*(normal.Z*0.5+0.5));
175
  Result:=RGB(r,g,b);
176
end;
177

178
procedure GetBlendCoeffs(x,y,x1,y1,x2,y2,x3,y3 : Integer; var f1,f2,f3 : single);
179
var
180
  m1,m2,d1,d2,
181
  px,py : single;
182
begin
183
  if (x1 = x) and (x2 = x3) then
184
    f1:=0
185
  else begin
186
    if x1 = x then begin
187
      m2:=(y3-y2)/(x3-x2);
188
      d2:=y2-m2*x2;
189
      px:=x;
190
      py:=m2*px+d2;
191
    end else if x2 = x3 then begin
192
      m1:=(y1-y)/(x1-x);
193
      d1:=y1-m1*x1;
194
      px:=x2;
195
      py:=m1*px+d1;
196
    end else begin
197
      m1:=(y1-y)/(x1-x);
198
      d1:=y1-m1*x1;
199
      m2:=(y3-y2)/(x3-x2);
200
      d2:=y2-m2*x2;
201
      px:=(d1-d2)/(m2-m1);
202
      py:=m2*px+d2;
203
    end;
204
    f1:=sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1))
205
        /sqrt((px-x1)*(px-x1)+(py-y1)*(py-y1));
206
  end;
207

208
  if (x2 = x) and (x1 = x3) then
209
    f2:=0
210
  else begin
211
    if x2 = x then begin
212
      m2:=(y3-y1)/(x3-x1);
213
      d2:=y1-m2*x1;
214
      px:=x;
215
      py:=m2*px+d2;
216
    end else if x3 = x1 then begin
217
      m1:=(y2-y)/(x2-x);
218
      d1:=y2-m1*x2;
219
      px:=x1;
220
      py:=m1*px+d1;
221
    end else begin
222
      m1:=(y2-y)/(x2-x);
223
      d1:=y2-m1*x2;
224
      m2:=(y3-y1)/(x3-x1);
225
      d2:=y1-m2*x1;
226
      px:=(d1-d2)/(m2-m1);
227
      py:=m2*px+d2;
228
    end;
229
    f2:=sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2))
230
        /sqrt((px-x2)*(px-x2)+(py-y2)*(py-y2));
231
  end;
232

233
  if (x3 = x) and (x1 = x2) then
234
    f3:=0
235
  else begin
236
    if x = x3 then begin
237
      m2:=(y2-y1)/(x2-x1);
238
      d2:=y1-m2*x1;
239
      px:=x;
240
      py:=m2*px+d2;
241
    end else if x2 = x1 then begin
242
      m1:=(y3-y)/(x3-x);
243
      d1:=y3-m1*x3;
244
      px:=x1;
245
      py:=m1*px+d1;
246
    end else begin
247
      m1:=(y3-y)/(x3-x);
248
      d1:=y3-m1*x3;
249
      m2:=(y2-y1)/(x2-x1);
250
      d2:=y1-m2*x1;
251
      px:=(d1-d2)/(m2-m1);
252
      py:=m2*px+d2;
253
    end;
254
    f3:=sqrt((x-x3)*(x-x3)+(y-y3)*(y-y3))
255
        /sqrt((px-x3)*(px-x3)+(py-y3)*(py-y3));
256
  end;
257

258
end;
259

260
function BlendNormals(x,y,x1,y1,x2,y2,x3,y3 : Integer;
261
                      n1,n2,n3 : TAffineVector) : TAffineVector;
262
var
263
  f1,f2,f3 : single;
264
begin
265
  GetBlendCoeffs(x,y,x1,y1,x2,y2,x3,y3,f1,f2,f3);
266
  Result:=VectorScale(n1,1-f1);
267
  AddVector(Result,VectorScale(n2,1-f2));
268
  AddVector(Result,VectorScale(n3,1-f3));
269
end;
270

271
procedure CalcObjectSpaceNormalMap(Width, Height : Integer;
272
                                   NormalMap, Normals, TexCoords : TAffineVectorList);
273
var
274
  i,x,y,xs,xe,
275
  x1,y1,x2,y2,x3,y3 : integer;
276
  n,n1,n2,n3 : TAffineVector;
277
begin
278
  for i:=0 to (TexCoords.Count div 3) - 1 do begin
279
    x1:=Round(TexCoords[3*i].V[0]*(Width-1));
280
    y1:=Round((1-TexCoords[3*i].V[1])*(Height-1));
281
    x2:=Round(TexCoords[3*i+1].V[0]*(Width-1));
282
    y2:=Round((1-TexCoords[3*i+1].V[1])*(Height-1));
283
    x3:=Round(TexCoords[3*i+2].V[0]*(Width-1));
284
    y3:=Round((1-TexCoords[3*i+2].V[1])*(Height-1));
285
    n1:=Normals[3*i];
286
    n2:=Normals[3*i+1];
287
    n3:=Normals[3*i+2];
288

289
    if y2<y1 then begin
290
      x:=x1;  y:=y1;  n:=n1;
291
      x1:=x2; y1:=y2; n1:=n2;
292
      x2:=x;  y2:=y;  n2:=n;
293
    end;
294
    if y3<y1 then begin
295
      x:=x1;  y:=y1;  n:=n1;
296
      x1:=x3; y1:=y3; n1:=n3;
297
      x3:=x;  y3:=y;  n3:=n;
298
    end;
299
    if y3<y2 then begin
300
      x:=x2;  y:=y2;  n:=n2;
301
      x2:=x3; y2:=y3; n2:=n3;
302
      x3:=x;  y3:=y;  n3:=n;
303
    end;
304

305
    if y1<y2 then
306
      for y:=y1 to y2 do begin
307
        xs:=Round(x1+(x2-x1)*((y-y1)/(y2-y1)));
308
        xe:=Round(x1+(x3-x1)*((y-y1)/(y3-y1)));
309
        if xe<xs then begin
310
          x:=xs; xs:=xe; xe:=x;
311
        end;
312
        for x:=xs to xe do
313
          NormalMap[x+y*Width]:=BlendNormals(x,y,x1,y1,x2,y2,x3,y3,n1,n2,n3);
314
      end;
315
    if y2<y3 then
316
      for y:=y2 to y3 do begin
317
        xs:=Round(x2+(x3-x2)*((y-y2)/(y3-y2)));
318
        xe:=Round(x1+(x3-x1)*((y-y1)/(y3-y1)));
319
        if xe<xs then begin
320
          x:=xs; xs:=xe; xe:=x;
321
        end;
322
        for x:=xs to xe do
323
          NormalMap[x+y*Width]:=BlendNormals(x,y,x1,y1,x2,y2,x3,y3,n1,n2,n3);
324
      end;
325
  end;
326
end;
327

328
// CreateObjectSpaceNormalMap
329
//
330
function CreateObjectSpaceNormalMap(Width, Height : Integer;
331
                                    HiNormals,HiTexCoords : TAffineVectorList) : TGLBitmap;
332
var
333
  i : integer;
334
  NormalMap : TAffineVectorList;
335
begin
336
  NormalMap:=TAffineVectorList.Create;
337
  NormalMap.AddNulls(Width*Height);
338

339
  CalcObjectSpaceNormalMap(Width,Height,NormalMap,HiNormals,HiTexCoords);
340

341
  // Create the bitmap
342
  Result:=TGLBitmap.Create;
343
  Result.Width:=Width;
344
  Result.Height:=Height;
345
  Result.PixelFormat:=glpf24bit;
346

347
  // Paint bitmap with normal map normals (X,Y,Z) -> (R,G,B)
348
  for i:=0 to NormalMap.Count-1 do
349
    Result.Canvas.Pixels[i mod Width, i div Height]:=ConvertNormalToColor(NormalMap[i]);
350

351
  NormalMap.Free;
352
end;
353

354
// CreateTangentSpaceNormalMap
355
//
356
function CreateTangentSpaceNormalMap(Width, Height : Integer;
357
                                     HiNormals, HiTexCoords,
358
                                     LoNormals, LoTexCoords,
359
                                     Tangents, BiNormals : TAffineVectorList) : TGLBitmap;
360

361
  function NormalToTangentSpace(Normal : TAffineVector;
362
                                x,y,x1,y1,x2,y2,x3,y3 : Integer;
363
                                m1,m2,m3 : TAffineMatrix) : TAffineVector;
364
  var
365
    n1,n2,n3 : TAffineVector;
366
  begin
367
    n1:=VectorTransform(Normal,m1);
368
    n2:=VectorTransform(Normal,m2);
369
    n3:=VectorTransform(Normal,m3);
370
    Result:=BlendNormals(x,y,x1,y1,x2,y2,x3,y3,n1,n2,n3);
371
    NormalizeVector(Result);
372
  end;
373

374
var
375
  i,x,y,xs,xe,
376
  x1,y1,x2,y2,x3,y3 : integer;
377
  NormalMap : TAffineVectorList;
378
  n : TAffineVector;
379
  m,m1,m2,m3 : TAffineMatrix;
380
begin
381
  NormalMap:=TAffineVectorList.Create;
382
  NormalMap.AddNulls(Width*Height);
383

384
  CalcObjectSpaceNormalMap(Width,Height,NormalMap,HiNormals,HiTexCoords);
385

386
  // Transform the object space normals into tangent space
387
  for i:=0 to (LoTexCoords.Count div 3) - 1 do begin
388
    x1:=Round(LoTexCoords[3*i].V[0]*(Width-1));
389
    y1:=Round((1-LoTexCoords[3*i].V[1])*(Height-1));
390
    x2:=Round(LoTexCoords[3*i+1].V[0]*(Width-1));
391
    y2:=Round((1-LoTexCoords[3*i+1].V[1])*(Height-1));
392
    x3:=Round(LoTexCoords[3*i+2].V[0]*(Width-1));
393
    y3:=Round((1-LoTexCoords[3*i+2].V[1])*(Height-1));
394

395
    m1.V[0]:=Tangents[3*i];   m1.V[1]:=BiNormals[3*i];   m1.V[2]:=LoNormals[3*i];
396
    m2.V[0]:=Tangents[3*i+1]; m2.V[1]:=BiNormals[3*i+1]; m2.V[2]:=LoNormals[3*i+1];
397
    m3.V[0]:=Tangents[3*i+2]; m3.V[1]:=BiNormals[3*i+2]; m3.V[2]:=LoNormals[3*i+2];
398
    TransposeMatrix(m1);
399
    TransposeMatrix(m2);
400
    TransposeMatrix(m3);
401
    InvertMatrix(m1);
402
    InvertMatrix(m2);
403
    InvertMatrix(m3);
404
    if y2<y1 then begin
405
      x:=x1;  y:=y1;  m:=m1;
406
      x1:=x2; y1:=y2; m1:=m2;
407
      x2:=x;  y2:=y;  m2:=m;
408
    end;
409
    if y3<y1 then begin
410
      x:=x1;  y:=y1;  m:=m1;
411
      x1:=x3; y1:=y3; m1:=m3;
412
      x3:=x;  y3:=y;  m3:=m;
413
    end;
414
    if y3<y2 then begin
415
      x:=x2;  y:=y2;  m:=m2;
416
      x2:=x3; y2:=y3; m2:=m3;
417
      x3:=x;  y3:=y;  m3:=m;
418
    end;
419

420
    if y1<y2 then
421
      for y:=y1 to y2 do begin
422
        xs:=Round(x1+(x2-x1)*((y-y1)/(y2-y1)));
423
        xe:=Round(x1+(x3-x1)*((y-y1)/(y3-y1)));
424
        if xe<xs then begin
425
          x:=xs; xs:=xe; xe:=x;
426
        end;
427
        for x:=xs to xe-1 do begin
428
          n:=NormalToTangentSpace(NormalMap[x+y*Width],x,y,x1,y1,x2,y2,x3,y3,m1,m2,m3);
429
          NormalizeVector(n);
430
          n.V[0]:=-n.V[0];
431
          NormalMap[x+y*Width]:=n;
432
        end;
433
      end;
434
    if y2<y3 then
435
      for y:=y2+1 to y3 do begin
436
        xs:=Round(x2+(x3-x2)*((y-y2)/(y3-y2)));
437
        xe:=Round(x1+(x3-x1)*((y-y1)/(y3-y1)));
438
        if xe<xs then begin
439
          x:=xs; xs:=xe; xe:=x;
440
        end;
441
        for x:=xs to xe-1 do begin
442
          n:=NormalToTangentSpace(NormalMap[x+y*Width],x,y,x1,y1,x2,y2,x3,y3,m1,m2,m3);
443
          NormalizeVector(n);
444
          n.V[0]:=-n.V[0];
445
          NormalMap[x+y*Width]:=n;
446
        end;
447
      end;
448
  end;
449

450
  // Create the bitmap
451
  Result:=TGLBitmap.Create;
452
  Result.Width:=Width;
453
  Result.Height:=Height;
454
  Result.PixelFormat:=glpf24bit;
455

456
  // Paint bitmap with normal map normals (X,Y,Z) -> (R,G,B)
457
  for i:=0 to NormalMap.Count-1 do
458
    Result.Canvas.Pixels[i mod Width, i div Height]:=ConvertNormalToColor(NormalMap[i]);
459

460
  NormalMap.Free;
461
end;
462

463
end.
464

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

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

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

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