GXS.PhysFields.pas 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. //
  2. // The graphics engine GXScene
  3. //
  4. unit GXS.PhysFields;
  5. interface
  6. uses
  7. System.Classes,
  8. Stage.VectorGeometry,
  9. GXS.XCollection,
  10. GXS.Coordinates,
  11. GXS.Scene,
  12. GXS.Behaviours,
  13. (* GXS.RigidBodyInertia *)
  14. GXS.PhysInertias,
  15. GXS.PhysManager;
  16. type
  17. TGLUniformGravityEmitter = class(TgxBaseForceFieldEmitter)
  18. private
  19. fGravity: TgxCoordinates;
  20. protected
  21. procedure SetGravity(const val: TgxCoordinates);
  22. public
  23. constructor Create(aOwner: TXCollection); override;
  24. destructor Destroy; override;
  25. procedure Assign(Source: TPersistent); override;
  26. procedure WriteToFiler(writer: TWriter); override;
  27. procedure ReadFromFiler(reader: TReader); override;
  28. class function FriendlyName: String; override;
  29. class function FriendlyDescription: String; override;
  30. class function UniqueItem: Boolean; override;
  31. function CalculateForceField(Body: TgxBaseSceneObject)
  32. : TAffineVector; override;
  33. published
  34. property Gravity: TgxCoordinates read fGravity write SetGravity;
  35. end;
  36. TGLRadialGravityEmitter = class(TgxBaseForceFieldEmitter)
  37. private
  38. fMass: Real;
  39. fMassOverG: Real;
  40. public
  41. constructor Create(aOwner: TXCollection); override;
  42. destructor Destroy; override;
  43. procedure Assign(Source: TPersistent); override;
  44. procedure WriteToFiler(writer: TWriter); override;
  45. procedure ReadFromFiler(reader: TReader); override;
  46. class function FriendlyName: String; override;
  47. class function FriendlyDescription: String; override;
  48. class function UniqueItem: Boolean; override;
  49. function CalculateForceField(Body: TgxBaseSceneObject)
  50. : TAffineVector; override;
  51. published
  52. property Mass: Real read fMass write fMass;
  53. end;
  54. TgxDampingFieldEmitter = class(TgxBaseForceFieldEmitter)
  55. private
  56. fDamping: TgxDamping;
  57. protected
  58. procedure SetDamping(const val: TgxDamping);
  59. public
  60. constructor Create(aOwner: TXCollection); override;
  61. destructor Destroy; override;
  62. procedure Assign(Source: TPersistent); override;
  63. procedure WriteToFiler(writer: TWriter); override;
  64. procedure ReadFromFiler(reader: TReader); override;
  65. class function FriendlyName: String; override;
  66. class function FriendlyDescription: String; override;
  67. class function UniqueItem: Boolean; override;
  68. function CalculateForceField(Body: TgxBaseSceneObject)
  69. : TAffineVector; override;
  70. published
  71. property Damping: TgxDamping read fDamping write SetDamping;
  72. end;
  73. const
  74. GravitationalConstant = 6.6726E-11;
  75. // ==================================================================
  76. implementation
  77. // ==================================================================
  78. // -------------------------------------
  79. // ---- TGLUniformGravityEmitter
  80. // -------------------------------------
  81. constructor TGLUniformGravityEmitter.Create(aOwner: TXCollection);
  82. begin
  83. inherited Create(aOwner);
  84. fGravity := TgxCoordinates.CreateInitialized(Self, nullHmgVector, csVector);
  85. end;
  86. destructor TGLUniformGravityEmitter.Destroy;
  87. begin
  88. fGravity.Free;
  89. inherited Destroy;
  90. end;
  91. procedure TGLUniformGravityEmitter.Assign(Source: TPersistent);
  92. begin
  93. if Source.ClassType = Self.ClassType then
  94. begin
  95. fGravity := TGLUniformGravityEmitter(Source).fGravity;
  96. end;
  97. end;
  98. class function TGLUniformGravityEmitter.FriendlyName: String;
  99. begin
  100. Result := 'Uniform Gravity';
  101. end;
  102. class function TGLUniformGravityEmitter.FriendlyDescription: String;
  103. begin
  104. Result := 'Uniform Gravity, appropriate near surface of planet';
  105. end;
  106. class function TGLUniformGravityEmitter.UniqueItem: Boolean;
  107. begin
  108. Result := false;
  109. end;
  110. procedure TGLUniformGravityEmitter.WriteToFiler(writer: TWriter);
  111. begin
  112. inherited;
  113. with writer do
  114. begin
  115. fGravity.WriteToFiler(writer);
  116. end;
  117. end;
  118. procedure TGLUniformGravityEmitter.ReadFromFiler(reader: TReader);
  119. begin
  120. inherited;
  121. with reader do
  122. begin
  123. fGravity.ReadFromFiler(reader);
  124. end;
  125. end;
  126. procedure TGLUniformGravityEmitter.SetGravity(const val: TgxCoordinates);
  127. begin
  128. fGravity.Assign(val);
  129. end;
  130. // CalculateForceField (TODO: ParticleInertia -> BaseInertia, add BaseInertia.ApplyAcceleration)
  131. function TGLUniformGravityEmitter.CalculateForceField(Body: TgxBaseSceneObject)
  132. : TAffineVector;
  133. var
  134. inertia1: TgxParticleInertia;
  135. begin
  136. inertia1 := TgxParticleInertia
  137. (Body.Behaviours.GetByClass(TgxParticleInertia));
  138. if Assigned(inertia1) then
  139. begin
  140. Result := VectorScale(fGravity.AsAffineVector, inertia1.Mass);
  141. inertia1.ApplyForce(Result);
  142. end
  143. else
  144. Result := nullVector;
  145. end;
  146. // ------------------------------------------------------------------------------
  147. // ------------------------------Radial Gravity Emitter -------------------------
  148. // ------------------------------------------------------------------------------
  149. constructor TGLRadialGravityEmitter.Create(aOwner: TXCollection);
  150. begin
  151. inherited Create(aOwner);
  152. end;
  153. destructor TGLRadialGravityEmitter.Destroy;
  154. begin
  155. inherited Destroy;
  156. end;
  157. procedure TGLRadialGravityEmitter.Assign(Source: TPersistent);
  158. begin
  159. if Source.ClassType = Self.ClassType then
  160. begin
  161. fMass := TGLRadialGravityEmitter(Source).fMass;
  162. end;
  163. end;
  164. class function TGLRadialGravityEmitter.FriendlyName: String;
  165. begin
  166. Result := 'Radial Gravity';
  167. end;
  168. class function TGLRadialGravityEmitter.FriendlyDescription: String;
  169. begin
  170. Result := 'Radial Gravity, can be applied anywhere (use for planets)';
  171. end;
  172. class function TGLRadialGravityEmitter.UniqueItem: Boolean;
  173. begin
  174. Result := false;
  175. end;
  176. procedure TGLRadialGravityEmitter.WriteToFiler(writer: TWriter);
  177. begin
  178. inherited;
  179. with writer do
  180. begin
  181. WriteFloat(fMass);
  182. end;
  183. end;
  184. procedure TGLRadialGravityEmitter.ReadFromFiler(reader: TReader);
  185. begin
  186. inherited;
  187. with reader do
  188. begin
  189. fMass := ReadFloat();;
  190. end;
  191. end;
  192. // CalculateForceField (TODO: ParticleInertia -> BaseInertia if possible)
  193. function TGLRadialGravityEmitter.CalculateForceField(Body: TgxBaseSceneObject)
  194. : TAffineVector;
  195. var
  196. inertia1: TgxParticleInertia;
  197. R: TAffineVector;
  198. L: Real;
  199. begin
  200. inertia1 := TgxParticleInertia
  201. (Body.Behaviours.GetByClass(TgxParticleInertia));
  202. if Assigned(inertia1) then
  203. begin
  204. R := VectorSubtract(Body.Position.AsAffineVector,
  205. Self.OwnerBaseSceneObject.Position.AsAffineVector);
  206. L := VectorLength(R);
  207. Result := VectorScale(R, -GravitationalConstant * (fMass / L));
  208. inertia1.ApplyForce(Result);
  209. end
  210. else
  211. Result := nullVector;
  212. end;
  213. // -----------------------------------------------------------------------------
  214. // ------------------------------Damping Field Emitter -------------------------
  215. // -----------------------------------------------------------------------------
  216. constructor TgxDampingFieldEmitter.Create(aOwner: TXCollection);
  217. begin
  218. inherited Create(aOwner);
  219. fDamping := TgxDamping.Create(Self);
  220. end;
  221. destructor TgxDampingFieldEmitter.Destroy;
  222. begin
  223. fDamping.Free;
  224. inherited Destroy;
  225. end;
  226. procedure TgxDampingFieldEmitter.Assign(Source: TPersistent);
  227. begin
  228. if Source.ClassType = Self.ClassType then
  229. begin
  230. fDamping := TgxDampingFieldEmitter(Source).fDamping;
  231. end;
  232. end;
  233. class function TgxDampingFieldEmitter.FriendlyName: String;
  234. begin
  235. Result := 'Damping Field';
  236. end;
  237. class function TgxDampingFieldEmitter.FriendlyDescription: String;
  238. begin
  239. Result := 'Damping Field, to approximate air/fluid resistance';
  240. end;
  241. class function TgxDampingFieldEmitter.UniqueItem: Boolean;
  242. begin
  243. Result := false;
  244. end;
  245. procedure TgxDampingFieldEmitter.WriteToFiler(writer: TWriter);
  246. begin
  247. inherited;
  248. with writer do
  249. begin
  250. fDamping.WriteToFiler(writer);
  251. end;
  252. end;
  253. procedure TgxDampingFieldEmitter.ReadFromFiler(reader: TReader);
  254. begin
  255. inherited;
  256. with reader do
  257. begin
  258. fDamping.ReadFromFiler(reader);
  259. end;
  260. end;
  261. procedure TgxDampingFieldEmitter.SetDamping(const val: TgxDamping);
  262. begin
  263. fDamping.Assign(val);
  264. end;
  265. // CalculateForceField (TODO: ParticleInertia -> BaseInertia, BaseInertia.ApplyDamping?)
  266. function TgxDampingFieldEmitter.CalculateForceField(Body: TgxBaseSceneObject)
  267. : TAffineVector;
  268. var
  269. inertia1: TgxParticleInertia;
  270. // velocity:TAffineVector;
  271. // v:Real;
  272. begin
  273. inertia1 := TgxParticleInertia
  274. (Body.Behaviours.GetByClass(TgxParticleInertia));
  275. if Assigned(inertia1) then
  276. inertia1.ApplyDamping(Damping);
  277. { Inertia1:=TgxParticleInertia(Body.Behaviours.GetByClass(TgxParticleInertia));
  278. if Assigned(inertia1) then
  279. begin
  280. velocity:=VectorScale(inertia1.LinearMomentum, 1/Inertia1.Mass); // v = p/m
  281. //apply force in opposite direction to velocity
  282. v:=VectorLength(velocity);
  283. // F = -Normalised(V)*( Constant + (Linear)*(V) + (Quadtratic)*(V)*(V) )
  284. Result:=VectorScale(VectorNormalize(velocity),-(fDamping.Constant+fDamping.Linear*v+fDamping.Quadratic*v*v));
  285. inertia1.ApplyForce(Result);
  286. end
  287. else
  288. Result:=nullvector;
  289. }
  290. end;
  291. // -------------------------------------------------------------------------
  292. initialization
  293. // -------------------------------------------------------------------------
  294. RegisterXCollectionItemClass(TGLUniformGravityEmitter);
  295. RegisterXCollectionItemClass(TGLRadialGravityEmitter);
  296. RegisterXCollectionItemClass(TgxDampingFieldEmitter);
  297. end.