fClothActorD.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. unit fClothActorD;
  2. interface
  3. uses
  4. Winapi.OpenGL,
  5. System.SysUtils,
  6. System.Classes,
  7. Vcl.Graphics,
  8. Vcl.Controls,
  9. Vcl.Forms,
  10. Vcl.Dialogs,
  11. Vcl.StdCtrls,
  12. Vcl.ExtCtrls,
  13. Vcl.Imaging.Jpeg,
  14. GLS.Scene,
  15. GLScene.VectorTypes,
  16. GLS.VectorFileObjects,
  17. GLS.Objects,
  18. GLS.Cadencer,
  19. GLS.Texture,
  20. GLS.SceneViewer,
  21. GLS.FileSMD,
  22. GLS.File3DS,
  23. GLS.VerletTypes,
  24. GLS.VerletClothify,
  25. GLS.ShadowVolume,
  26. GLS.XCollection,
  27. GLScene.VectorGeometry,
  28. GLS.GeometryBB,
  29. GLS.SpacePartition,
  30. GLS.Material,
  31. GLS.BaseClasses,
  32. GLS.RenderContextInfo,
  33. GLS.Context,
  34. GLScene.Utils,
  35. GLS.Coordinates,
  36. GLS.PersistentClasses;
  37. type
  38. TFormClothActor = class(TForm)
  39. GLScene1: TGLScene;
  40. GLSceneViewer1: TGLSceneViewer;
  41. GLMaterialLibrary1: TGLMaterialLibrary;
  42. GLCadencer1: TGLCadencer;
  43. GLCamera1: TGLCamera;
  44. GLActor1: TGLActor;
  45. ActorDummy: TGLDummyCube;
  46. Timer1: TTimer;
  47. OctreeRenderer: TGLDirectOpenGL;
  48. cbShowOctree: TCheckBox;
  49. GLLightSource1: TGLLightSource;
  50. GLPlane1: TGLPlane;
  51. GLShadowVolume1: TGLShadowVolume;
  52. Cape: TGLActor;
  53. GLLightSource2: TGLLightSource;
  54. StaticTextFPS: TStaticText;
  55. procedure FormCreate(Sender: TObject);
  56. procedure FormDestroy(Sender: TObject);
  57. procedure GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
  58. X, Y: Integer);
  59. procedure GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  60. procedure GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double);
  61. procedure Timer1Timer(Sender: TObject);
  62. procedure OctreeRendererRender(Sender: TObject; var rci: TGLRenderContextInfo);
  63. public
  64. mx, my: Integer;
  65. VerletWorld: TGLVerletWorld;
  66. EdgeDetector: TGLEdgeDetector;
  67. AirResistance: TGLVerletAirResistance;
  68. end;
  69. var
  70. FormClothActor: TFormClothActor;
  71. implementation
  72. {$R *.dfm}
  73. // Mesh normal recalculation routines
  74. procedure PrepareMeshForNormalsRecalc(BaseMesh: TGLBaseMesh);
  75. var
  76. i, j, k: Integer;
  77. mo: TGLMeshObject;
  78. fg: TFGVertexNormalTexIndexList;
  79. begin
  80. // update normals
  81. // (not very efficient, could use some work...)
  82. for i := 0 to BaseMesh.MeshObjects.Count - 1 do
  83. begin
  84. mo := BaseMesh.MeshObjects[i];
  85. for j := 0 to mo.FaceGroups.Count - 1 do
  86. begin
  87. if mo.FaceGroups[j] is TFGVertexNormalTexIndexList then
  88. begin
  89. fg := TFGVertexNormalTexIndexList(mo.FaceGroups[j]);
  90. for k := 0 to fg.VertexIndices.Count - 1 do
  91. begin
  92. fg.NormalIndices.List[k] := fg.VertexIndices.List[k];
  93. end;
  94. end;
  95. end;
  96. end;
  97. BaseMesh.StructureChanged;
  98. end;
  99. procedure RecalcMeshNormals(BaseMesh: TGLBaseMesh);
  100. var
  101. i, j, k: Integer;
  102. mo: TGLMeshObject;
  103. fg: TFGVertexIndexList;
  104. n: TAffineVector;
  105. begin
  106. // update normals
  107. // (not very efficient, could use some work...)
  108. for i := 0 to BaseMesh.MeshObjects.Count - 1 do
  109. begin
  110. mo := BaseMesh.MeshObjects[i];
  111. FillChar(mo.Normals.List[0], SizeOf(TAffineVector) * mo.Normals.Count, 0);
  112. for j := 0 to mo.FaceGroups.Count - 1 do
  113. begin
  114. if mo.FaceGroups[j] is TFGVertexIndexList then
  115. begin
  116. fg := TFGVertexIndexList(mo.FaceGroups[j]);
  117. k := 0;
  118. while k <= fg.VertexIndices.Count - 3 do
  119. begin
  120. n := CalcPlaneNormal(mo.Vertices.List[fg.VertexIndices.List[k]],
  121. mo.Vertices.List[fg.VertexIndices.List[k + 1]],
  122. mo.Vertices.List[fg.VertexIndices.List[k + 2]]);
  123. mo.Normals.TranslateItem(fg.VertexIndices.List[k], n);
  124. mo.Normals.TranslateItem(fg.VertexIndices.List[k + 1], n);
  125. mo.Normals.TranslateItem(fg.VertexIndices.List[k + 2], n); // }
  126. Inc(k, 3);
  127. end;
  128. end;
  129. end;
  130. mo.Normals.Normalize;
  131. end;
  132. BaseMesh.StructureChanged;
  133. end;
  134. procedure TFormClothActor.FormCreate(Sender: TObject);
  135. var
  136. FloorVC: TGLVerletFloor;
  137. Path: TFileName;
  138. begin
  139. Path := GetCurrentAssetPath();
  140. Randomize;
  141. // Load dynamic models of actors with textures and/or animations
  142. SetCurrentDir(Path + '\modelext');
  143. GLActor1.LoadFromFile('trinityRAGE.smd');
  144. GLActor1.AddDataFromFile('walk.smd');
  145. GLActor1.Animations[1].MakeSkeletalTranslationStatic;
  146. GLActor1.SwitchToAnimation('walk');
  147. GLActor1.BuildSilhouetteConnectivityData;
  148. // Load static models of objects
  149. SetCurrentDir(Path + '\model');
  150. // the cape must be loaded after trinityRAGE
  151. Cape.LoadFromFile('cape.3ds');
  152. Cape.Position.Y := GLActor1.BoundingSphereRadius - 10;
  153. PrepareMeshForNormalsRecalc(Cape);
  154. Cape.BuildSilhouetteConnectivityData;
  155. // Set up the floor texture and reposition to below the actors feet
  156. SetCurrentDir(Path + '\texture');
  157. GLPlane1.Material.Texture.Image.LoadFromFile('beigemarble.jpg');
  158. GLPlane1.Material.Texture.Disabled := False;
  159. GLPlane1.Position.Y := -GLActor1.BoundingSphereRadius * 0.9;
  160. // Setting up the verlet world using the optional dynamic octree can
  161. // give good perfamnce increases.
  162. VerletWorld := TGLVerletWorld.Create;
  163. VerletWorld.CreateOctree(AffineVectorMake(0, 0, 0), AffineVectorMake(0, 0, 0), 10, 6);
  164. VerletWorld.UpdateSpacePartion := uspEveryFrame;
  165. VerletWorld.Iterations := 3;
  166. // 'Clothify' the cape and add it to the verlet world
  167. EdgeDetector := TGLEdgeDetector.Create(Cape);
  168. EdgeDetector.ProcessMesh;
  169. EdgeDetector.AddEdgesAsSticks(VerletWorld, 0.15);
  170. EdgeDetector.AddEdgesAsSolidEdges(VerletWorld);
  171. // EdgeDetector.AddOuterEdgesAsSolidEdges(VerletWorld);
  172. // Set up verlet gravity and add the floor as a constraint
  173. TGLVerletGravity.Create(VerletWorld).Gravity := AffineVectorMake(0, -98.1, 0);
  174. FloorVC := TGLVerletFloor.Create(VerletWorld);
  175. FloorVC.Normal := GLPlane1.Direction.AsAffineVector;
  176. FloorVC.Location := VectorAdd(GLPlane1.Position.AsAffineVector,
  177. VectorScale(GLPlane1.Direction.AsAffineVector, 0.1));
  178. (* Load the skeleton colliders. Skeleton colliders define an
  179. approximate collision boundary for actors and are controlled
  180. by the actor's skeleton. *)
  181. SetCurrentDir(Path + '\scenery');
  182. GLActor1.Skeleton.Colliders.LoadFromFile('trinityRAGE.glsc');
  183. GLActor1.Skeleton.Colliders.AlignColliders;
  184. // Add the collider's verlet constraints to the verlet world
  185. AddVerletConstriantsToVerletWorld(GLActor1.Skeleton.Colliders, VerletWorld);
  186. (*
  187. AirResistance := TGLVerletAirResistance.Create(VerletWorld);
  188. AirResistance.DragCoeff := 0.001;
  189. AirResistance.WindDirection := AffineVectorMake(0,0,1);
  190. AirResistance.WindMagnitude := 15;
  191. AirResistance.WindChaos := 2;
  192. // *)
  193. FloorVC.Free;
  194. end;
  195. procedure TFormClothActor.FormDestroy(Sender: TObject);
  196. begin
  197. VerletWorld.Free;
  198. end;
  199. procedure TFormClothActor.GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double);
  200. var
  201. i: Integer;
  202. begin
  203. // Step the verlet world (this is where the magic happens)
  204. VerletWorld.Progress(deltaTime, newTime);
  205. // Recalculate the cape's normals
  206. RecalcMeshNormals(Cape);
  207. // Cycle the floor texture to make it look like it's moving
  208. GLPlane1.YOffset := GLPlane1.YOffset - 0.25 * deltaTime;
  209. if GLPlane1.YOffset < 0 then
  210. GLPlane1.YOffset := GLPlane1.YOffset + 1;
  211. // Orbit the light (to show off the pretty shadow volumes)
  212. GLLightSource1.MoveObjectAround(GLActor1, 0, -deltaTime * 20);
  213. GLLightSource1.PointTo(GLActor1, YHMGVector);
  214. end;
  215. procedure RenderAABB(AABB: TAABB; w, r, g, b: single);
  216. begin
  217. glColor3f(r, g, b);
  218. glLineWidth(w);
  219. glBegin(GL_LINE_STRIP);
  220. glVertex3f(AABB.min.X, AABB.min.Y, AABB.min.Z);
  221. glVertex3f(AABB.min.X, AABB.max.Y, AABB.min.Z);
  222. glVertex3f(AABB.max.X, AABB.max.Y, AABB.min.Z);
  223. glVertex3f(AABB.max.X, AABB.min.Y, AABB.min.Z);
  224. glVertex3f(AABB.min.X, AABB.min.Y, AABB.min.Z);
  225. glVertex3f(AABB.min.X, AABB.min.Y, AABB.max.Z);
  226. glVertex3f(AABB.min.X, AABB.max.Y, AABB.max.Z);
  227. glVertex3f(AABB.max.X, AABB.max.Y, AABB.max.Z);
  228. glVertex3f(AABB.max.X, AABB.min.Y, AABB.max.Z);
  229. glVertex3f(AABB.min.X, AABB.min.Y, AABB.max.Z);
  230. glEnd;
  231. glBegin(GL_LINES);
  232. glVertex3f(AABB.min.X, AABB.max.Y, AABB.min.Z);
  233. glVertex3f(AABB.min.X, AABB.max.Y, AABB.max.Z);
  234. glVertex3f(AABB.max.X, AABB.max.Y, AABB.min.Z);
  235. glVertex3f(AABB.max.X, AABB.max.Y, AABB.max.Z);
  236. glVertex3f(AABB.max.X, AABB.min.Y, AABB.min.Z);
  237. glVertex3f(AABB.max.X, AABB.min.Y, AABB.max.Z);
  238. glEnd;
  239. end;
  240. procedure RenderOctreeNode(Node: TGLSectorNode);
  241. var
  242. i: Integer;
  243. AABB: TAABB;
  244. begin
  245. if Node.NoChildren then
  246. begin
  247. AABB := Node.AABB;
  248. if Node.RecursiveLeafCount > 0 then
  249. RenderAABB(AABB, 1, 0, 0, 0)
  250. else
  251. RenderAABB(AABB, 1, 0.8, 0.8, 0.8) // }
  252. end
  253. else
  254. begin
  255. for i := 0 to Node.ChildCount - 1 do
  256. RenderOctreeNode(Node.Children[i]);
  257. end;
  258. end;
  259. procedure TFormClothActor.OctreeRendererRender(Sender: TObject; var rci: TGLRenderContextInfo);
  260. begin
  261. if cbShowOctree.Checked then
  262. begin
  263. if VerletWorld.SpacePartition is TGLOctreeSpacePartition then
  264. begin
  265. glPushAttrib(GL_ENABLE_BIT or GL_CURRENT_BIT or GL_LINE_BIT or GL_COLOR_BUFFER_BIT);
  266. glDisable(GL_LIGHTING);
  267. RenderOctreeNode(TGLOctreeSpacePartition(VerletWorld.SpacePartition).RootNode);
  268. glPopAttrib;
  269. end;
  270. end;
  271. end;
  272. procedure TFormClothActor.Timer1Timer(Sender: TObject);
  273. begin
  274. StaticTextFPS.Caption := Format('%2.1f FPS', [GLSceneViewer1.FramesPerSecond]);
  275. GLSceneViewer1.ResetPerformanceMonitor;
  276. end;
  277. procedure TFormClothActor.GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
  278. Shift: TShiftState; X, Y: Integer);
  279. begin
  280. mx := X;
  281. my := Y;
  282. end;
  283. procedure TFormClothActor.GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  284. X, Y: Integer);
  285. begin
  286. if ssLeft in Shift then
  287. GLCamera1.MoveAroundTarget(my - Y, mx - X);
  288. mx := X;
  289. my := Y;
  290. end;
  291. end.