2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Some useful methods for setting up bump maps.
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
24
GLVectorGeometry, GLVectorLists, GLCrossPlatform, GLVectorTypes;
27
TNormalMapSpace = (nmsObject, nmsTangent);
30
procedure CalcObjectSpaceLightVectors(Light : TAffineVector;
31
Vertices: TAffineVectorList;
35
procedure SetupTangentSpace(Vertices, Normals, TexCoords,
36
Tangents, BiNormals : TAffineVectorList);
37
procedure CalcTangentSpaceLightVectors(Light : TAffineVector;
39
Tangents, BiNormals : TAffineVectorList;
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;
51
// CalcObjectSpaceLightVectors
53
procedure CalcObjectSpaceLightVectors(Light : TAffineVector;
54
Vertices: TAffineVectorList;
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);
69
procedure SetupTangentSpace(Vertices, Normals, TexCoords,
70
Tangents, BiNormals : TAffineVectorList);
73
v,n,t : TAffineMatrix;
74
vt,tt : TAffineVector;
77
procedure SortVertexData(sortidx : Integer);
79
if t.X.V[sortidx]<t.Y.V[sortidx] then begin
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;
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;
97
for i:=0 to (Vertices.Count div 3)-1 do begin
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];
105
for j:=0 to 2 do begin
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]);
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));
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]);
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));
141
// CalcTangentSpaceLightVectors
143
procedure CalcTangentSpaceLightVectors(Light : TAffineVector;
145
Tangents, BiNormals : TAffineVectorList;
146
Colors: TVectorList);
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));
160
Colors[i]:=VectorMake(VectorAdd(VectorScale(vec,0.5),0.5),1);
164
// ------------------------------------------------------------------------
165
// Local functions used for creating normal maps
166
// ------------------------------------------------------------------------
168
function ConvertNormalToColor(normal : TAffineVector) : TDelphiColor;
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));
178
procedure GetBlendCoeffs(x,y,x1,y1,x2,y2,x3,y3 : Integer; var f1,f2,f3 : single);
183
if (x1 = x) and (x2 = x3) then
191
end else if x2 = x3 then begin
204
f1:=sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1))
205
/sqrt((px-x1)*(px-x1)+(py-y1)*(py-y1));
208
if (x2 = x) and (x1 = x3) then
216
end else if x3 = x1 then begin
229
f2:=sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2))
230
/sqrt((px-x2)*(px-x2)+(py-y2)*(py-y2));
233
if (x3 = x) and (x1 = x2) then
241
end else if x2 = x1 then begin
254
f3:=sqrt((x-x3)*(x-x3)+(y-y3)*(y-y3))
255
/sqrt((px-x3)*(px-x3)+(py-y3)*(py-y3));
260
function BlendNormals(x,y,x1,y1,x2,y2,x3,y3 : Integer;
261
n1,n2,n3 : TAffineVector) : TAffineVector;
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));
271
procedure CalcObjectSpaceNormalMap(Width, Height : Integer;
272
NormalMap, Normals, TexCoords : TAffineVectorList);
275
x1,y1,x2,y2,x3,y3 : integer;
276
n,n1,n2,n3 : TAffineVector;
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));
291
x1:=x2; y1:=y2; n1:=n2;
296
x1:=x3; y1:=y3; n1:=n3;
301
x2:=x3; y2:=y3; n2:=n3;
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)));
310
x:=xs; xs:=xe; xe:=x;
313
NormalMap[x+y*Width]:=BlendNormals(x,y,x1,y1,x2,y2,x3,y3,n1,n2,n3);
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)));
320
x:=xs; xs:=xe; xe:=x;
323
NormalMap[x+y*Width]:=BlendNormals(x,y,x1,y1,x2,y2,x3,y3,n1,n2,n3);
328
// CreateObjectSpaceNormalMap
330
function CreateObjectSpaceNormalMap(Width, Height : Integer;
331
HiNormals,HiTexCoords : TAffineVectorList) : TGLBitmap;
334
NormalMap : TAffineVectorList;
336
NormalMap:=TAffineVectorList.Create;
337
NormalMap.AddNulls(Width*Height);
339
CalcObjectSpaceNormalMap(Width,Height,NormalMap,HiNormals,HiTexCoords);
342
Result:=TGLBitmap.Create;
344
Result.Height:=Height;
345
Result.PixelFormat:=glpf24bit;
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]);
354
// CreateTangentSpaceNormalMap
356
function CreateTangentSpaceNormalMap(Width, Height : Integer;
357
HiNormals, HiTexCoords,
358
LoNormals, LoTexCoords,
359
Tangents, BiNormals : TAffineVectorList) : TGLBitmap;
361
function NormalToTangentSpace(Normal : TAffineVector;
362
x,y,x1,y1,x2,y2,x3,y3 : Integer;
363
m1,m2,m3 : TAffineMatrix) : TAffineVector;
365
n1,n2,n3 : TAffineVector;
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);
376
x1,y1,x2,y2,x3,y3 : integer;
377
NormalMap : TAffineVectorList;
379
m,m1,m2,m3 : TAffineMatrix;
381
NormalMap:=TAffineVectorList.Create;
382
NormalMap.AddNulls(Width*Height);
384
CalcObjectSpaceNormalMap(Width,Height,NormalMap,HiNormals,HiTexCoords);
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));
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];
406
x1:=x2; y1:=y2; m1:=m2;
411
x1:=x3; y1:=y3; m1:=m3;
416
x2:=x3; y2:=y3; m2:=m3;
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)));
425
x:=xs; xs:=xe; xe:=x;
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);
431
NormalMap[x+y*Width]:=n;
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)));
439
x:=xs; xs:=xe; xe:=x;
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);
445
NormalMap[x+y*Width]:=n;
451
Result:=TGLBitmap.Create;
453
Result.Height:=Height;
454
Result.PixelFormat:=glpf24bit;
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]);