fGrassD.pas 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. unit fGrassD;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. Winapi.Messages,
  6. Winapi.OpenGL,
  7. System.SysUtils,
  8. System.Variants,
  9. System.Classes,
  10. Vcl.Graphics,
  11. Vcl.Controls,
  12. Vcl.Forms,
  13. Vcl.Dialogs,
  14. Vcl.StdCtrls,
  15. Vcl.Imaging.Jpeg,
  16. Vcl.ComCtrls,
  17. Vcl.ExtCtrls,
  18. GLS.Scene,
  19. GLS.Objects,
  20. GLS.Cadencer,
  21. GLS.SceneViewer,
  22. GLS.Navigator,
  23. Stage.VectorGeometry,
  24. GLS.Texture,
  25. GLS.HeightData,
  26. GLS.TerrainRenderer,
  27. GLS.AsyncTimer,
  28. GLS.Material,
  29. GLS.Coordinates,
  30. GLS.XCollection,
  31. GLS.BaseClasses,
  32. GLS.RenderContextInfo,
  33. Stage.TextureFormat,
  34. Stage.Keyboard,
  35. Stage.Utils
  36. ;
  37. type
  38. TFormGrass = class(TForm)
  39. GLScene: TGLScene;
  40. GLSceneViewer: TGLSceneViewer;
  41. GLCadencer: TGLCadencer;
  42. Camera: TGLCamera;
  43. GLNavigator: TGLNavigator;
  44. GLUserInterface: TGLUserInterface;
  45. Wind1: TGLDummyCube;
  46. DirectOpenGL: TGLDirectOpenGL;
  47. Terrain: TGLTerrainRenderer;
  48. GLBitmapHDS: TGLBitmapHDS;
  49. GLAsyncTimer: TGLAsyncTimer;
  50. MatLib: TGLMaterialLibrary;
  51. Wind2: TGLDummyCube;
  52. Wind3: TGLDummyCube;
  53. Panel: TPanel;
  54. Leafbar: TTrackBar;
  55. AnimateBox: TCheckBox;
  56. LeafLabel: TLabel;
  57. NodeCountLabel: TLabel;
  58. NodeCountBar: TTrackBar;
  59. NodeHLabel: TLabel;
  60. NodeHBar: TTrackBar;
  61. NodeAngleLabel: TLabel;
  62. NodeAngleBar: TTrackBar;
  63. Label1: TLabel;
  64. WindRangeBar: TTrackBar;
  65. WindRangeLabel: TLabel;
  66. WindPowerLabel: TLabel;
  67. WindPowerBar: TTrackBar;
  68. procedure FormCreate(Sender: TObject);
  69. procedure GLCadencerProgress(Sender: TObject; const deltaTime,
  70. newTime: Double);
  71. procedure DirectOpenGLRender(Sender: TObject;
  72. var rci: TGLRenderContextInfo);
  73. procedure AsyncTimer1Timer(Sender: TObject);
  74. procedure LeafbarChange(Sender: TObject);
  75. procedure GLSceneViewerClick(Sender: TObject);
  76. private
  77. Path: TFileName;
  78. procedure MakeGrass;
  79. procedure UpdateGrass;
  80. end;
  81. TLine = record
  82. pos: TAffineVector;
  83. org: TAffineVector;
  84. end;
  85. TLines = record
  86. n: array of TLine;
  87. dir: TAffineVector;
  88. end;
  89. var
  90. FormGrass: TFormGrass;
  91. org: TAffineVector;
  92. Lines: array of TLines;
  93. WindPower: single = 2;
  94. WindRange: single = 20;
  95. NodeCount: integer = 3;
  96. NodeH: single = 1;
  97. NodeAngle: single = 1;
  98. // Size: integer=40;
  99. LeafNum: integer = 1000;
  100. S: single = 0.3;
  101. //===================================
  102. implementation
  103. //===================================
  104. {$R *.dfm}
  105. procedure TFormGrass.FormCreate(Sender: TObject);
  106. begin
  107. Path := GetCurrentAssetPath();
  108. SetCurrentDir(Path + '\texture');
  109. GLBitmapHDS.Picture.LoadFromFile('terrain.bmp');
  110. MatLib.AddTextureMaterial('grass', 'grass.bmp');
  111. Terrain.Material.Texture.Image.LoadFromFile('clover.jpg');
  112. UpdateGrass;
  113. Label1.Caption:='Click on viewer to'#13#10'toggle mouse look +'#13#10'(W,S,A,D)';
  114. end;
  115. procedure TFormGrass.MakeGrass;
  116. var
  117. n, l: integer;
  118. opos, ndir: TAffineVector;
  119. h, xx, yy: single;
  120. new: boolean;
  121. begin
  122. if Length(Lines) = LeafNum then
  123. new := False
  124. else
  125. new := True;
  126. SetLength(Lines, LeafNum);
  127. for l := 0 to LeafNum - 1 do
  128. begin
  129. SetLength(Lines[l].n, NodeCount);
  130. Lines[l].dir := AffineVectorMake(1, 0, 0);
  131. Lines[l].dir := VectorRotateAroundY(Lines[l].dir, l / LeafNum * pi * 2);
  132. Lines[l].dir := VectorNormalize(Lines[l].dir);
  133. ndir := VectorRotateAroundY(Lines[l].dir, pi / 2);
  134. if new then
  135. begin
  136. xx := Random * 40 - 20;
  137. yy := Random * 40 - 20;
  138. end
  139. else
  140. begin
  141. xx := Lines[l].n[0].pos.V[0];
  142. yy := Lines[l].n[0].pos.V[2];
  143. end;
  144. h := Terrain.InterpolatedHeight(VectorMake(xx + 26, 0, yy - 26));
  145. opos := AffineVectorMake(xx, h + 0.1, yy);
  146. for n := 0 to Length(Lines[l].n) - 1 do
  147. begin
  148. Lines[l].n[n].pos := opos;
  149. Lines[l].n[n].org := opos;
  150. Lines[l].n[n].org.V[0] := opos.V[0] + (n / Length(Lines[l].n)) *
  151. ndir.V[0] * NodeAngle;
  152. Lines[l].n[n].org.V[1] := opos.V[1] + NodeH;
  153. Lines[l].n[n].org.V[2] := opos.V[2] + (n / Length(Lines[l].n)) *
  154. ndir.V[2] * NodeAngle;
  155. opos := Lines[l].n[n].org;
  156. end;
  157. end;
  158. end;
  159. procedure TFormGrass.UpdateGrass;
  160. begin
  161. with FormGrass do
  162. begin
  163. LeafNum := Leafbar.Position;
  164. NodeCount := NodeCountBar.Position;
  165. NodeH := NodeHBar.Position / 10;
  166. NodeAngle := NodeAngleBar.Position / 90 * pi * NodeCount;
  167. WindRange := WindRangeBar.Position / 10;
  168. WindPower := WindPowerBar.Position / 10;
  169. LeafLabel.Caption := 'Leaf count: ' + IntToStr(LeafNum);
  170. NodeCountLabel.Caption := 'Node count: ' + IntToStr(NodeCount);
  171. NodeHLabel.Caption := 'Node height: ' + Format('%f', [NodeH]);
  172. NodeAngleLabel.Caption := 'Node angle: ' + IntToStr(NodeAngleBar.Position);
  173. WindRangeLabel.Caption := 'Wind range: ' + Format('%f', [WindRange]);
  174. WindPowerLabel.Caption := 'Wind power: ' + Format('%f', [WindPower]);
  175. MakeGrass;
  176. end;
  177. end;
  178. procedure TFormGrass.GLCadencerProgress(Sender: TObject; const deltaTime,
  179. newTime: Double);
  180. var
  181. speed: double;
  182. begin
  183. GLUserInterface.MouseUpdate;
  184. GLUserInterface.MouseLook;
  185. speed := 20 * deltaTime;
  186. if IsKeyDown('W') then
  187. Camera.Move(speed);
  188. if IsKeyDown('S') then
  189. Camera.Move(-speed);
  190. if IsKeyDown('A') then
  191. Camera.Slide(-speed);
  192. if IsKeyDown('D') then
  193. Camera.Slide(speed);
  194. if AnimateBox.Checked then
  195. begin
  196. Wind1.Position.X := sin(newTime * 4) * 10;
  197. Wind1.Position.Z := cos(newTime) * 10;
  198. Wind2.Position.X := sin(newTime) * 10;
  199. Wind2.Position.Z := cos(newTime * 4) * 10;
  200. Wind3.Position.X := sin(newTime * 2) * 20;
  201. Wind3.Position.Z := cos(newTime * 2) * 20;
  202. Wind1.Position.Y := 2 + Terrain.InterpolatedHeight
  203. (VectorMake(Wind1.Position.X + 26, 0, Wind1.Position.Z - 26));
  204. Wind2.Position.Y := 2 + Terrain.InterpolatedHeight
  205. (VectorMake(Wind2.Position.X + 26, 0, Wind2.Position.Z - 26));
  206. Wind3.Position.Y := 2 + Terrain.InterpolatedHeight
  207. (VectorMake(Wind3.Position.X + 26, 0, Wind3.Position.Z - 26));
  208. end;
  209. end;
  210. procedure TFormGrass.DirectOpenGLRender(Sender: TObject;
  211. var rci: TGLRenderContextInfo);
  212. var
  213. i, n, ln, w: integer;
  214. v, pos, new, w1, w2, tmp: TAffineVector;
  215. d, ws1, ws2: single;
  216. Wind: TGLDummyCube;
  217. begin
  218. glDisable(GL_CULL_FACE);
  219. glColor3f(1, 1, 1);
  220. glLineWidth(1);
  221. MatLib.ApplyMaterial('grass', rci);
  222. glBegin(GL_TRIANGLES);
  223. for i := 0 to Length(Lines) - 1 do
  224. begin
  225. ws2 := NodeCount * 0.05 + 0.05;
  226. ws1 := ws2 + 0.05;
  227. for n := 0 to Length(Lines[i].n) - 1 do
  228. begin
  229. tmp := AffineVectorMake(0, 0, 0);
  230. for w := 1 to 3 do
  231. begin
  232. if w = 1 then
  233. Wind := Wind1
  234. else if w = 2 then
  235. Wind := Wind2
  236. else
  237. Wind := Wind3;
  238. V := VectorSubtract(Lines[i].n[n].org, Wind.Position.AsAffineVector);
  239. d := VectorLength(V);
  240. if d > WindRange then
  241. new := Lines[i].n[n].org
  242. else
  243. begin
  244. NormalizeVector(V);
  245. ScaleVector(V, (1 - d / WindRange) * WindPower);
  246. new := VectorAdd(Lines[i].n[n].org, V);
  247. end;
  248. tmp := VectorAdd(tmp, new);
  249. end;
  250. ScaleVector(tmp, 1 / 3);
  251. new := tmp;
  252. d := VectorDistance(Lines[i].n[n].pos, new);
  253. if d > NodeH then
  254. new.V[1] := new.V[1] - (d - NodeH);
  255. if new.V[1] < Lines[i].n[n].pos.V[1] then
  256. new.V[1] := Lines[i].n[n].pos.V[1];
  257. d := VectorDistance(Lines[i].n[n].pos, new);
  258. if d > NodeH then
  259. begin
  260. V := VectorSubtract(new, Lines[i].n[n].pos);
  261. NormalizeVector(V);
  262. ScaleVector(V, NodeH);
  263. new := VectorAdd(Lines[i].n[n].pos, V);
  264. end;
  265. if n < Length(Lines[i].n) - 1 then
  266. begin
  267. V := VectorSubtract(new, Lines[i].n[n + 1].pos);
  268. Lines[i].n[n + 1].pos := new;
  269. Lines[i].n[n + 1].org := VectorAdd(Lines[i].n[n + 1].org, V);
  270. end;
  271. ln := Length(Lines[i].n);
  272. pos := Lines[i].n[n].pos;
  273. w1.V[0] := ws1 * Lines[i].dir.V[0];
  274. w1.V[1] := ws1 * Lines[i].dir.V[1];
  275. w1.V[2] := ws1 * Lines[i].dir.V[2];
  276. w2.V[0] := ws2 * Lines[i].dir.V[0];
  277. w2.V[1] := ws2 * Lines[i].dir.V[1];
  278. w2.V[2] := ws2 * Lines[i].dir.V[2];
  279. if n < ln - 1 then
  280. begin
  281. glTexCoord2f(0, n / ln);
  282. glVertex3f(pos.V[0] - w1.V[0], pos.V[1] - w1.V[1], pos.V[2] - w1.V[2]);
  283. glTexCoord2f(0, (n + 1) / ln);
  284. glVertex3f(new.V[0] - w2.V[0], new.V[1] - w2.V[1], new.V[2] - w2.V[2]);
  285. glTexCoord2f(1, n / ln);
  286. glVertex3f(pos.V[0] + w1.V[0], pos.V[1] + w1.V[1], pos.V[2] + w1.V[2]);
  287. glTexCoord2f(1, n / ln);
  288. glVertex3f(pos.V[0] + w1.V[0], pos.V[1] + w1.V[1], pos.V[2] + w1.V[2]);
  289. glTexCoord2f(0, (n + 1) / ln);
  290. glVertex3f(new.V[0] - w2.V[0], new.V[1] - w2.V[1], new.V[2] - w2.V[2]);
  291. glTexCoord2f(1, (n + 1) / ln);
  292. glVertex3f(new.V[0] + w2.V[0], new.V[1] + w2.V[1], new.V[2] + w2.V[2]);
  293. end
  294. else
  295. begin
  296. glTexCoord2f(0, n / ln);
  297. glVertex3f(pos.V[0] - w1.V[0], pos.V[1] - w1.V[1], pos.V[2] - w1.V[2]);
  298. glTexCoord2f(0.5, n / ln);
  299. glVertex3f(new.V[0], new.V[1], new.V[2]);
  300. glTexCoord2f(1, (n + 1) / ln);
  301. glVertex3f(pos.V[0] + w1.V[0], pos.V[1] + w1.V[1], pos.V[2] + w1.V[2]);
  302. end;
  303. ws1 := ws1 - 0.05;
  304. ws2 := ws2 - 0.05;
  305. end;
  306. end;
  307. glEnd;
  308. MatLib.UnApplyMaterial(rci);
  309. glEnable(GL_CULL_FACE);
  310. end;
  311. procedure TFormGrass.AsyncTimer1Timer(Sender: TObject);
  312. begin
  313. Caption:=Format('Grass with '+'%d faces at %f FPS', [(2*(NodeCount-1)+1)*LeafNum, GLSceneViewer.FramesPerSecond]);
  314. GLSceneViewer.ResetPerformanceMonitor;
  315. end;
  316. procedure TFormGrass.LeafbarChange(Sender: TObject);
  317. begin
  318. UpdateGrass;
  319. end;
  320. procedure TFormGrass.GLSceneViewerClick(Sender: TObject);
  321. begin
  322. GLUserInterface.MouseLookActive:=not GLUserInterface.MouseLookActive;
  323. end;
  324. end.