GLBumpMapping.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLBumpMapping;
  5. (* Some useful methods for setting up bump maps. *)
  6. interface
  7. {$I GLScene.inc}
  8. uses
  9. System.UITypes,
  10. Vcl.Graphics,
  11. GLColor,
  12. GLVectorGeometry,
  13. GLVectorLists,
  14. GLVectorTypes;
  15. type
  16. TNormalMapSpace = (nmsObject, nmsTangent);
  17. procedure CalcObjectSpaceLightVectors(Light : TAffineVector;
  18. Vertices: TAffineVectorList;
  19. Colors: TVectorList);
  20. procedure SetupTangentSpace(Vertices, Normals, TexCoords,
  21. Tangents, BiNormals : TAffineVectorList);
  22. procedure CalcTangentSpaceLightVectors(Light : TAffineVector;
  23. Vertices, Normals,
  24. Tangents, BiNormals : TAffineVectorList;
  25. Colors: TVectorList);
  26. function CreateObjectSpaceNormalMap(Width, Height : Integer;
  27. HiNormals,HiTexCoords : TAffineVectorList) : TBitmap;
  28. function CreateTangentSpaceNormalMap(Width, Height : Integer;
  29. HiNormals, HiTexCoords,
  30. LoNormals, LoTexCoords,
  31. Tangents, BiNormals : TAffineVectorList) : TBitmap;
  32. //------------------------------------------------------------
  33. implementation
  34. //------------------------------------------------------------
  35. procedure CalcObjectSpaceLightVectors(Light: TAffineVector; Vertices: TAffineVectorList; Colors: TVectorList);
  36. var
  37. i: Integer;
  38. vec: TAffineVector;
  39. begin
  40. Colors.Count := Vertices.Count;
  41. for i := 0 to Vertices.Count - 1 do
  42. begin
  43. vec := VectorNormalize(VectorSubtract(Light, Vertices[i]));
  44. Colors[i] := VectorMake(VectorAdd(VectorScale(vec, 0.5), 0.5), 1);
  45. end;
  46. end;
  47. procedure SetupTangentSpace(Vertices, Normals, TexCoords, Tangents, BiNormals: TAffineVectorList);
  48. var
  49. i, j: Integer;
  50. v, n, t: TAffineMatrix;
  51. vt, tt: TAffineVector;
  52. interp, dot: Single;
  53. procedure SortVertexData(sortidx: Integer);
  54. begin
  55. if t.v[0].V[sortidx] < t.v[1].V[sortidx] then
  56. begin
  57. vt := v.v[0];
  58. tt := t.v[0];
  59. v.v[0] := v.v[1];
  60. t.v[0] := t.v[1];
  61. v.v[1] := vt;
  62. t.v[1] := tt;
  63. end;
  64. if t.v[0].V[sortidx] < t.v[2].V[sortidx] then
  65. begin
  66. vt := v.v[0];
  67. tt := t.v[0];
  68. v.v[0] := v.v[2];
  69. t.v[0] := t.v[2];
  70. v.v[2] := vt;
  71. t.v[2] := tt;
  72. end;
  73. if t.v[1].V[sortidx] < t.v[2].V[sortidx] then
  74. begin
  75. vt := v.v[1];
  76. tt := t.v[1];
  77. v.v[1] := v.v[2];
  78. t.v[1] := t.v[2];
  79. v.v[2] := vt;
  80. t.v[2] := tt;
  81. end;
  82. end;
  83. begin
  84. for i := 0 to (Vertices.Count div 3) - 1 do
  85. begin
  86. // Get triangle data
  87. for j := 0 to 2 do
  88. begin
  89. v.v[j] := Vertices[3 * i + j];
  90. n.v[j] := Normals[3 * i + j];
  91. t.v[j] := TexCoords[3 * i + j];
  92. end;
  93. for j := 0 to 2 do
  94. begin
  95. // Compute tangent
  96. SortVertexData(1);
  97. if (t.v[2].Y - t.v[0].Y) = 0 then
  98. interp := 1
  99. else
  100. interp := (t.v[1].Y - t.v[0].Y) / (t.v[2].Y - t.v[0].Y);
  101. vt := VectorLerp(v.v[0], v.v[2], interp);
  102. interp := t.v[0].X + (t.v[2].X - t.v[0].X) * interp;
  103. vt := VectorSubtract(vt, v.v[1]);
  104. if t.v[1].X < interp then
  105. vt := VectorNegate(vt);
  106. dot := VectorDotProduct(vt, n.v[j]);
  107. vt.X := vt.X - n.v[j].X * dot;
  108. vt.Y := vt.Y - n.v[j].Y * dot;
  109. vt.Z := vt.Z - n.v[j].Z * dot;
  110. Tangents.Add(VectorNormalize(vt));
  111. // Compute Bi-Normal
  112. SortVertexData(0);
  113. if (t.v[2].X - t.v[0].X) = 0 then
  114. interp := 1
  115. else
  116. interp := (t.v[1].X - t.v[0].X) / (t.v[2].X - t.v[0].X);
  117. vt := VectorLerp(v.v[0], v.v[2], interp);
  118. interp := t.v[0].Y + (t.v[2].Y - t.v[0].Y) * interp;
  119. vt := VectorSubtract(vt, v.v[1]);
  120. if t.v[1].Y < interp then
  121. vt := VectorNegate(vt);
  122. dot := VectorDotProduct(vt, n.v[j]);
  123. vt.X := vt.X - n.v[j].X * dot;
  124. vt.Y := vt.Y - n.v[j].Y * dot;
  125. vt.Z := vt.Z - n.v[j].Z * dot;
  126. BiNormals.Add(VectorNormalize(vt));
  127. end;
  128. end;
  129. end;
  130. procedure CalcTangentSpaceLightVectors(Light: TAffineVector;
  131. Vertices, Normals, Tangents, BiNormals: TAffineVectorList;
  132. Colors: TVectorList);
  133. var
  134. i: Integer;
  135. mat: TAffineMatrix;
  136. vec: TAffineVector;
  137. begin
  138. Colors.Count := Vertices.Count;
  139. for i := 0 to Vertices.Count - 1 do
  140. begin
  141. mat.v[0] := Tangents[i];
  142. mat.v[1] := BiNormals[i];
  143. mat.v[2] := Normals[i];
  144. TransposeMatrix(mat);
  145. vec := VectorNormalize(VectorTransform(VectorSubtract(Light, Vertices[i]), mat));
  146. vec.X := -vec.X;
  147. Colors[i] := VectorMake(VectorAdd(VectorScale(vec, 0.5), 0.5), 1);
  148. end;
  149. end;
  150. // ------------------------------------------------------------------------
  151. // Local functions used for creating normal maps
  152. // ------------------------------------------------------------------------
  153. function ConvertNormalToColor(normal: TAffineVector): TColor;
  154. var
  155. r, g, b: Byte;
  156. begin
  157. r := Round(255 * (normal.X * 0.5 + 0.5));
  158. g := Round(255 * (normal.Y * 0.5 + 0.5));
  159. b := Round(255 * (normal.Z * 0.5 + 0.5));
  160. Result := RGB2Color(r, g, b);
  161. end;
  162. procedure GetBlendCoeffs(X, Y, x1, y1, x2, y2, x3, y3: Integer; var f1, f2, f3: Single);
  163. var
  164. m1, m2, d1, d2, px, py: Single;
  165. begin
  166. if (x1 = X) and (x2 = x3) then
  167. f1 := 0
  168. else
  169. begin
  170. if x1 = X then
  171. begin
  172. m2 := (y3 - y2) / (x3 - x2);
  173. d2 := y2 - m2 * x2;
  174. px := X;
  175. py := m2 * px + d2;
  176. end
  177. else if x2 = x3 then
  178. begin
  179. m1 := (y1 - Y) / (x1 - X);
  180. d1 := y1 - m1 * x1;
  181. px := x2;
  182. py := m1 * px + d1;
  183. end
  184. else
  185. begin
  186. m1 := (y1 - Y) / (x1 - X);
  187. d1 := y1 - m1 * x1;
  188. m2 := (y3 - y2) / (x3 - x2);
  189. d2 := y2 - m2 * x2;
  190. px := (d1 - d2) / (m2 - m1);
  191. py := m2 * px + d2;
  192. end;
  193. f1 := sqrt((X - x1) * (X - x1) + (Y - y1) * (Y - y1)) /
  194. sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1));
  195. end;
  196. if (x2 = X) and (x1 = x3) then
  197. f2 := 0
  198. else
  199. begin
  200. if x2 = X then
  201. begin
  202. m2 := (y3 - y1) / (x3 - x1);
  203. d2 := y1 - m2 * x1;
  204. px := X;
  205. py := m2 * px + d2;
  206. end
  207. else if x3 = x1 then
  208. begin
  209. m1 := (y2 - Y) / (x2 - X);
  210. d1 := y2 - m1 * x2;
  211. px := x1;
  212. py := m1 * px + d1;
  213. end
  214. else
  215. begin
  216. m1 := (y2 - Y) / (x2 - X);
  217. d1 := y2 - m1 * x2;
  218. m2 := (y3 - y1) / (x3 - x1);
  219. d2 := y1 - m2 * x1;
  220. px := (d1 - d2) / (m2 - m1);
  221. py := m2 * px + d2;
  222. end;
  223. f2 := sqrt((X - x2) * (X - x2) + (Y - y2) * (Y - y2)) /
  224. sqrt((px - x2) * (px - x2) + (py - y2) * (py - y2));
  225. end;
  226. if (x3 = X) and (x1 = x2) then
  227. f3 := 0
  228. else
  229. begin
  230. if X = x3 then
  231. begin
  232. m2 := (y2 - y1) / (x2 - x1);
  233. d2 := y1 - m2 * x1;
  234. px := X;
  235. py := m2 * px + d2;
  236. end
  237. else if x2 = x1 then
  238. begin
  239. m1 := (y3 - Y) / (x3 - X);
  240. d1 := y3 - m1 * x3;
  241. px := x1;
  242. py := m1 * px + d1;
  243. end
  244. else
  245. begin
  246. m1 := (y3 - Y) / (x3 - X);
  247. d1 := y3 - m1 * x3;
  248. m2 := (y2 - y1) / (x2 - x1);
  249. d2 := y1 - m2 * x1;
  250. px := (d1 - d2) / (m2 - m1);
  251. py := m2 * px + d2;
  252. end;
  253. f3 := sqrt((X - x3) * (X - x3) + (Y - y3) * (Y - y3)) /
  254. sqrt((px - x3) * (px - x3) + (py - y3) * (py - y3));
  255. end;
  256. end;
  257. function BlendNormals(X, Y, x1, y1, x2, y2, x3, y3: Integer;
  258. n1, n2, n3: TAffineVector): TAffineVector;
  259. var
  260. f1, f2, f3: Single;
  261. begin
  262. GetBlendCoeffs(X, Y, x1, y1, x2, y2, x3, y3, f1, f2, f3);
  263. Result := VectorScale(n1, 1 - f1);
  264. AddVector(Result, VectorScale(n2, 1 - f2));
  265. AddVector(Result, VectorScale(n3, 1 - f3));
  266. end;
  267. procedure CalcObjectSpaceNormalMap(Width, Height: Integer;
  268. NormalMap, Normals, TexCoords: TAffineVectorList);
  269. var
  270. i, X, Y, xs, xe, x1, y1, x2, y2, x3, y3: Integer;
  271. n, n1, n2, n3: TAffineVector;
  272. begin
  273. for i := 0 to (TexCoords.Count div 3) - 1 do
  274. begin
  275. x1 := Round(TexCoords[3 * i].X * (Width - 1));
  276. y1 := Round((1 - TexCoords[3 * i].Y) * (Height - 1));
  277. x2 := Round(TexCoords[3 * i + 1].X * (Width - 1));
  278. y2 := Round((1 - TexCoords[3 * i + 1].Y) * (Height - 1));
  279. x3 := Round(TexCoords[3 * i + 2].X * (Width - 1));
  280. y3 := Round((1 - TexCoords[3 * i + 2].Y) * (Height - 1));
  281. n1 := Normals[3 * i];
  282. n2 := Normals[3 * i + 1];
  283. n3 := Normals[3 * i + 2];
  284. if y2 < y1 then
  285. begin
  286. X := x1;
  287. Y := y1;
  288. n := n1;
  289. x1 := x2;
  290. y1 := y2;
  291. n1 := n2;
  292. x2 := X;
  293. y2 := Y;
  294. n2 := n;
  295. end;
  296. if y3 < y1 then
  297. begin
  298. X := x1;
  299. Y := y1;
  300. n := n1;
  301. x1 := x3;
  302. y1 := y3;
  303. n1 := n3;
  304. x3 := X;
  305. y3 := Y;
  306. n3 := n;
  307. end;
  308. if y3 < y2 then
  309. begin
  310. X := x2;
  311. Y := y2;
  312. n := n2;
  313. x2 := x3;
  314. y2 := y3;
  315. n2 := n3;
  316. x3 := X;
  317. y3 := Y;
  318. n3 := n;
  319. end;
  320. if y1 < y2 then
  321. for Y := y1 to y2 do
  322. begin
  323. xs := Round(x1 + (x2 - x1) * ((Y - y1) / (y2 - y1)));
  324. xe := Round(x1 + (x3 - x1) * ((Y - y1) / (y3 - y1)));
  325. if xe < xs then
  326. begin
  327. X := xs;
  328. xs := xe;
  329. xe := X;
  330. end;
  331. for X := xs to xe do
  332. NormalMap[X + Y * Width] := BlendNormals(X, Y, x1, y1, x2, y2, x3, y3, n1, n2, n3);
  333. end;
  334. if y2 < y3 then
  335. for Y := y2 to y3 do
  336. begin
  337. xs := Round(x2 + (x3 - x2) * ((Y - y2) / (y3 - y2)));
  338. xe := Round(x1 + (x3 - x1) * ((Y - y1) / (y3 - y1)));
  339. if xe < xs then
  340. begin
  341. X := xs;
  342. xs := xe;
  343. xe := X;
  344. end;
  345. for X := xs to xe do
  346. NormalMap[X + Y * Width] := BlendNormals(X, Y, x1, y1, x2, y2, x3, y3, n1, n2, n3);
  347. end;
  348. end;
  349. end;
  350. function CreateObjectSpaceNormalMap(Width, Height: Integer;
  351. HiNormals, HiTexCoords: TAffineVectorList): TBitmap;
  352. var
  353. i: Integer;
  354. NormalMap: TAffineVectorList;
  355. begin
  356. NormalMap := TAffineVectorList.Create;
  357. NormalMap.AddNulls(Width * Height);
  358. CalcObjectSpaceNormalMap(Width, Height, NormalMap, HiNormals, HiTexCoords);
  359. // Creates the bitmap
  360. Result := TBitmap.Create;
  361. Result.Width := Width;
  362. Result.Height := Height;
  363. Result.PixelFormat := pf24bit;
  364. // Paint bitmap with normal map normals (X,Y,Z) -> (R,G,B)
  365. for i := 0 to NormalMap.Count - 1 do
  366. Result.Canvas.Pixels[i mod Width, i div Height] := ConvertNormalToColor(NormalMap[i]);
  367. NormalMap.Free;
  368. end;
  369. function CreateTangentSpaceNormalMap(Width, Height: Integer; HiNormals, HiTexCoords, LoNormals, LoTexCoords, Tangents,
  370. BiNormals: TAffineVectorList): TBitmap;
  371. function NormalToTangentSpace(normal: TAffineVector; X, Y, x1, y1, x2, y2, x3, y3: Integer; m1, m2, m3: TAffineMatrix)
  372. : TAffineVector;
  373. var
  374. n1, n2, n3: TAffineVector;
  375. begin
  376. n1 := VectorTransform(normal, m1);
  377. n2 := VectorTransform(normal, m2);
  378. n3 := VectorTransform(normal, m3);
  379. Result := BlendNormals(X, Y, x1, y1, x2, y2, x3, y3, n1, n2, n3);
  380. NormalizeVector(Result);
  381. end;
  382. var
  383. i, X, Y, xs, xe, x1, y1, x2, y2, x3, y3: Integer;
  384. NormalMap: TAffineVectorList;
  385. n: TAffineVector;
  386. m, m1, m2, m3: TAffineMatrix;
  387. begin
  388. NormalMap := TAffineVectorList.Create;
  389. NormalMap.AddNulls(Width * Height);
  390. CalcObjectSpaceNormalMap(Width, Height, NormalMap, HiNormals, HiTexCoords);
  391. // Transform the object space normals into tangent space
  392. for i := 0 to (LoTexCoords.Count div 3) - 1 do
  393. begin
  394. x1 := Round(LoTexCoords[3 * i].X * (Width - 1));
  395. y1 := Round((1 - LoTexCoords[3 * i].Y) * (Height - 1));
  396. x2 := Round(LoTexCoords[3 * i + 1].X * (Width - 1));
  397. y2 := Round((1 - LoTexCoords[3 * i + 1].Y) * (Height - 1));
  398. x3 := Round(LoTexCoords[3 * i + 2].X * (Width - 1));
  399. y3 := Round((1 - LoTexCoords[3 * i + 2].Y) * (Height - 1));
  400. m1.X := Tangents[3 * i];
  401. m1.Y := BiNormals[3 * i];
  402. m1.Z := LoNormals[3 * i];
  403. m2.X := Tangents[3 * i + 1];
  404. m2.Y := BiNormals[3 * i + 1];
  405. m2.Z := LoNormals[3 * i + 1];
  406. m3.X := Tangents[3 * i + 2];
  407. m3.Y := BiNormals[3 * i + 2];
  408. m3.Z := LoNormals[3 * i + 2];
  409. TransposeMatrix(m1);
  410. TransposeMatrix(m2);
  411. TransposeMatrix(m3);
  412. InvertMatrix(m1);
  413. InvertMatrix(m2);
  414. InvertMatrix(m3);
  415. if y2 < y1 then
  416. begin
  417. X := x1;
  418. Y := y1;
  419. m := m1;
  420. x1 := x2;
  421. y1 := y2;
  422. m1 := m2;
  423. x2 := X;
  424. y2 := Y;
  425. m2 := m;
  426. end;
  427. if y3 < y1 then
  428. begin
  429. X := x1;
  430. Y := y1;
  431. m := m1;
  432. x1 := x3;
  433. y1 := y3;
  434. m1 := m3;
  435. x3 := X;
  436. y3 := Y;
  437. m3 := m;
  438. end;
  439. if y3 < y2 then
  440. begin
  441. X := x2;
  442. Y := y2;
  443. m := m2;
  444. x2 := x3;
  445. y2 := y3;
  446. m2 := m3;
  447. x3 := X;
  448. y3 := Y;
  449. m3 := m;
  450. end;
  451. if y1 < y2 then
  452. for Y := y1 to y2 do
  453. begin
  454. xs := Round(x1 + (x2 - x1) * ((Y - y1) / (y2 - y1)));
  455. xe := Round(x1 + (x3 - x1) * ((Y - y1) / (y3 - y1)));
  456. if xe < xs then
  457. begin
  458. X := xs;
  459. xs := xe;
  460. xe := X;
  461. end;
  462. for X := xs to xe - 1 do
  463. begin
  464. n := NormalToTangentSpace(NormalMap[X + Y * Width], X, Y, x1, y1, x2, y2, x3, y3, m1, m2, m3);
  465. NormalizeVector(n);
  466. n.X := -n.X;
  467. NormalMap[X + Y * Width] := n;
  468. end;
  469. end;
  470. if y2 < y3 then
  471. for Y := y2 + 1 to y3 do
  472. begin
  473. xs := Round(x2 + (x3 - x2) * ((Y - y2) / (y3 - y2)));
  474. xe := Round(x1 + (x3 - x1) * ((Y - y1) / (y3 - y1)));
  475. if xe < xs then
  476. begin
  477. X := xs;
  478. xs := xe;
  479. xe := X;
  480. end;
  481. for X := xs to xe - 1 do
  482. begin
  483. n := NormalToTangentSpace(NormalMap[X + Y * Width], X, Y, x1, y1, x2, y2, x3, y3, m1, m2, m3);
  484. NormalizeVector(n);
  485. n.X := -n.X;
  486. NormalMap[X + Y * Width] := n;
  487. end;
  488. end;
  489. end;
  490. // Creates the bitmap
  491. Result := TBitmap.Create;
  492. Result.Width := Width;
  493. Result.Height := Height;
  494. Result.PixelFormat := pf24bit;
  495. // Paint bitmap with normal map normals (X,Y,Z) -> (R,G,B)
  496. for i := 0 to NormalMap.Count - 1 do
  497. Result.Canvas.Pixels[i mod Width, i div Height] := ConvertNormalToColor(NormalMap[i]);
  498. NormalMap.Free;
  499. end;
  500. end.