GXS.BumpMapping.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.BumpMapping;
  5. (* Some useful methods for setting up bump maps *)
  6. interface
  7. uses
  8. System.UITypes,
  9. FMX.Graphics,
  10. GXS.Color,
  11. Stage.VectorGeometry,
  12. GXS.VectorLists,
  13. Stage.VectorTypes;
  14. type
  15. TNormalMapSpace = (nmsObject, nmsTangent);
  16. procedure CalcObjectSpaceLightVectors(Light : TAffineVector;
  17. Vertices: TgxAffineVectorList;
  18. Colors: TgxVectorList);
  19. procedure SetupTangentSpace(Vertices, Normals, TexCoords,
  20. Tangents, BiNormals : TgxAffineVectorList);
  21. procedure CalcTangentSpaceLightVectors(Light : TAffineVector;
  22. Vertices, Normals,
  23. Tangents, BiNormals : TgxAffineVectorList;
  24. Colors: TgxVectorList);
  25. function CreateObjectSpaceNormalMap(Width, Height : Integer;
  26. HiNormals,HiTexCoords : TgxAffineVectorList) : TBitmap;
  27. function CreateTangentSpaceNormalMap(Width, Height : Integer;
  28. HiNormals, HiTexCoords,
  29. LoNormals, LoTexCoords,
  30. Tangents, BiNormals : TgxAffineVectorList) : TBitmap;
  31. //------------------------------------------------------------
  32. implementation
  33. //------------------------------------------------------------
  34. procedure CalcObjectSpaceLightVectors(Light: TAffineVector;
  35. Vertices: TgxAffineVectorList; Colors: TgxVectorList);
  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: TgxAffineVectorList);
  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.X.v[sortidx] < t.Y.v[sortidx] then
  56. begin
  57. vt := v.X;
  58. tt := t.X;
  59. v.X := v.Y;
  60. t.X := t.Y;
  61. v.Y := vt;
  62. t.Y := tt;
  63. end;
  64. if t.X.v[sortidx] < t.Z.v[sortidx] then
  65. begin
  66. vt := v.X;
  67. tt := t.X;
  68. v.X := v.Z;
  69. t.X := t.Z;
  70. v.Z := vt;
  71. t.Z := tt;
  72. end;
  73. if t.Y.v[sortidx] < t.Z.v[sortidx] then
  74. begin
  75. vt := v.Y;
  76. tt := t.Y;
  77. v.Y := v.Z;
  78. t.Y := t.Z;
  79. v.Z := vt;
  80. t.Z := 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.Z.Y - t.X.Y) = 0 then
  98. interp := 1
  99. else
  100. interp := (t.Y.Y - t.X.Y) / (t.Z.Y - t.X.Y);
  101. vt := VectorLerp(v.X, v.Z, interp);
  102. interp := t.X.X + (t.Z.X - t.X.X) * interp;
  103. vt := VectorSubtract(vt, v.Y);
  104. if t.Y.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.Z.X - t.X.X) = 0 then
  114. interp := 1
  115. else
  116. interp := (t.Y.X - t.X.X) / (t.Z.X - t.X.X);
  117. vt := VectorLerp(v.X, v.Z, interp);
  118. interp := t.X.Y + (t.Z.Y - t.X.Y) * interp;
  119. vt := VectorSubtract(vt, v.Y);
  120. if t.Y.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: TgxAffineVectorList;
  132. Colors: TgxVectorList);
  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.X := Tangents[i];
  142. mat.Y := BiNormals[i];
  143. mat.Z := 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: TgxAffineVectorList);
  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: TgxAffineVectorList): TBitmap;
  352. var
  353. i: Integer;
  354. NormalMap: TgxAffineVectorList;
  355. begin
  356. NormalMap := TgxAffineVectorList.Create;
  357. NormalMap.AddNulls(Width * Height);
  358. CalcObjectSpaceNormalMap(Width, Height, NormalMap, HiNormals, HiTexCoords);
  359. // Creates the bitmap
  360. Result := TBitmap.Create;
  361. { TODO : E2129 Cannot assign to a read-only property }
  362. (* Result.Image.Width := Width;
  363. Result.Image.Height := Height;
  364. Result.PixelFormat := TPixelFormat.RGBA; *)
  365. // Paint bitmap with normal map normals (X,Y,Z) -> (R,G,B)
  366. for i := 0 to NormalMap.Count - 1 do
  367. { TODO : E2003 Undeclared identifier: 'Pixels' }
  368. (*
  369. Result.Canvas.Pixels[i mod Width, i div Height]:=
  370. ConvertNormalToColor(NormalMap[i]);
  371. *)
  372. NormalMap.Free;
  373. end;
  374. function CreateTangentSpaceNormalMap(Width, Height: Integer;
  375. HiNormals, HiTexCoords, LoNormals, LoTexCoords, Tangents,
  376. BiNormals: TgxAffineVectorList): TBitmap;
  377. function NormalToTangentSpace(normal: TAffineVector;
  378. X, Y, x1, y1, x2, y2, x3, y3: Integer; m1, m2, m3: TAffineMatrix)
  379. : TAffineVector;
  380. var
  381. n1, n2, n3: TAffineVector;
  382. begin
  383. n1 := VectorTransform(normal, m1);
  384. n2 := VectorTransform(normal, m2);
  385. n3 := VectorTransform(normal, m3);
  386. Result := BlendNormals(X, Y, x1, y1, x2, y2, x3, y3, n1, n2, n3);
  387. NormalizeVector(Result);
  388. end;
  389. var
  390. i, X, Y, xs, xe, x1, y1, x2, y2, x3, y3: Integer;
  391. NormalMap: TgxAffineVectorList;
  392. n: TAffineVector;
  393. m, m1, m2, m3: TAffineMatrix;
  394. begin
  395. NormalMap := TgxAffineVectorList.Create;
  396. NormalMap.AddNulls(Width * Height);
  397. CalcObjectSpaceNormalMap(Width, Height, NormalMap, HiNormals, HiTexCoords);
  398. // Transform the object space normals into tangent space
  399. for i := 0 to (LoTexCoords.Count div 3) - 1 do
  400. begin
  401. x1 := Round(LoTexCoords[3 * i].X * (Width - 1));
  402. y1 := Round((1 - LoTexCoords[3 * i].Y) * (Height - 1));
  403. x2 := Round(LoTexCoords[3 * i + 1].X * (Width - 1));
  404. y2 := Round((1 - LoTexCoords[3 * i + 1].Y) * (Height - 1));
  405. x3 := Round(LoTexCoords[3 * i + 2].X * (Width - 1));
  406. y3 := Round((1 - LoTexCoords[3 * i + 2].Y) * (Height - 1));
  407. m1.X := Tangents[3 * i];
  408. m1.Y := BiNormals[3 * i];
  409. m1.Z := LoNormals[3 * i];
  410. m2.X := Tangents[3 * i + 1];
  411. m2.Y := BiNormals[3 * i + 1];
  412. m2.Z := LoNormals[3 * i + 1];
  413. m3.X := Tangents[3 * i + 2];
  414. m3.Y := BiNormals[3 * i + 2];
  415. m3.Z := LoNormals[3 * i + 2];
  416. TransposeMatrix(m1);
  417. TransposeMatrix(m2);
  418. TransposeMatrix(m3);
  419. InvertMatrix(m1);
  420. InvertMatrix(m2);
  421. InvertMatrix(m3);
  422. if y2 < y1 then
  423. begin
  424. X := x1;
  425. Y := y1;
  426. m := m1;
  427. x1 := x2;
  428. y1 := y2;
  429. m1 := m2;
  430. x2 := X;
  431. y2 := Y;
  432. m2 := m;
  433. end;
  434. if y3 < y1 then
  435. begin
  436. X := x1;
  437. Y := y1;
  438. m := m1;
  439. x1 := x3;
  440. y1 := y3;
  441. m1 := m3;
  442. x3 := X;
  443. y3 := Y;
  444. m3 := m;
  445. end;
  446. if y3 < y2 then
  447. begin
  448. X := x2;
  449. Y := y2;
  450. m := m2;
  451. x2 := x3;
  452. y2 := y3;
  453. m2 := m3;
  454. x3 := X;
  455. y3 := Y;
  456. m3 := m;
  457. end;
  458. if y1 < y2 then
  459. for Y := y1 to y2 do
  460. begin
  461. xs := Round(x1 + (x2 - x1) * ((Y - y1) / (y2 - y1)));
  462. xe := Round(x1 + (x3 - x1) * ((Y - y1) / (y3 - y1)));
  463. if xe < xs then
  464. begin
  465. X := xs;
  466. xs := xe;
  467. xe := X;
  468. end;
  469. for X := xs to xe - 1 do
  470. begin
  471. n := NormalToTangentSpace(NormalMap[X + Y * Width], X, Y, x1, y1, x2, y2, x3, y3, m1, m2, m3);
  472. NormalizeVector(n);
  473. n.X := -n.X;
  474. NormalMap[X + Y * Width] := n;
  475. end;
  476. end;
  477. if y2 < y3 then
  478. for Y := y2 + 1 to y3 do
  479. begin
  480. xs := Round(x2 + (x3 - x2) * ((Y - y2) / (y3 - y2)));
  481. xe := Round(x1 + (x3 - x1) * ((Y - y1) / (y3 - y1)));
  482. if xe < xs then
  483. begin
  484. X := xs;
  485. xs := xe;
  486. xe := X;
  487. end;
  488. for X := xs to xe - 1 do
  489. begin
  490. n := NormalToTangentSpace(NormalMap[X + Y * Width], X, Y, x1, y1, x2, y2, x3, y3, m1, m2, m3);
  491. NormalizeVector(n);
  492. n.X := -n.X;
  493. NormalMap[X + Y * Width] := n;
  494. end;
  495. end;
  496. end;
  497. // Create the bitmap
  498. Result := TBitmap.Create;
  499. Result.Width := Width;
  500. Result.Height := Height;
  501. { TODO : E2129 Cannot assign to a read-only property }
  502. (* Result.PixelFormat:=glpf24bit; *)
  503. // Paint bitmap with normal map normals (X,Y,Z) -> (R,G,B)
  504. for i := 0 to NormalMap.Count - 1 do
  505. { TODO : E2003 Undeclared identifier: 'Pixels' }
  506. (*
  507. Result.Canvas.Pixels[i mod Width, i div Height]:=ConvertNormalToColor(NormalMap[i]);
  508. *)
  509. NormalMap.Free;
  510. end;
  511. end.