InovoScene.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:13k
源码类别:

2D图形编程

开发平台:

Delphi

  1. unit InovoScene;
  2. //---------------------------------------------------------------------------
  3. // InovoScene.pas                                       Modified: 28-Apr-2007
  4. // A small 3D graphics engine for Asphyre                         Version 1.0
  5. //---------------------------------------------------------------------------
  6. // Important Notice:
  7. //
  8. // If you modify/use this code or one of its parts either in original or
  9. // modified form, you must comply with Mozilla Public License v1.1,
  10. // specifically section 3, "Distribution Obligations". Failure to do so will
  11. // result in the license breach, which will be resolved in the court.
  12. // Remember that violating author's rights is considered a serious crime in
  13. // many countries. Thank you!
  14. //
  15. // !! Please *read* Mozilla Public License 1.1 document located at:
  16. //  http://www.mozilla.org/MPL/
  17. //
  18. // If you require any clarifications about the license, feel free to contact
  19. // us or post your question on our forums at: http://www.afterwarp.net
  20. //---------------------------------------------------------------------------
  21. // The contents of this file are subject to the Mozilla Public License
  22. // Version 1.1 (the "License"); you may not use this file except in
  23. // compliance with the License. You may obtain a copy of the License at
  24. // http://www.mozilla.org/MPL/
  25. //
  26. // Software distributed under the License is distributed on an "AS IS"
  27. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  28. // License for the specific language governing rights and limitations
  29. // under the License.
  30. //
  31. // The Original Code is InovoScene.pas.
  32. //
  33. // The Initial Developer of the Original Code is M. Sc. Yuriy Kotsarenko.
  34. // Portions created by M. Sc. Yuriy Kotsarenko are Copyright (C) 2007,
  35. // M. Sc. Yuriy Kotsarenko. All Rights Reserved.
  36. //---------------------------------------------------------------------------
  37. interface
  38. //---------------------------------------------------------------------------
  39. uses
  40.  d3dx9, Vectors3, Matrices3, Matrices4, AsphyreColors, AsphyreMatrices,
  41.  AsphyreMeshes, AsphyreDevices, InovoFluxFx;
  42. //---------------------------------------------------------------------------
  43. type
  44.  PInovoLight = ^TInovoLight;
  45.  TInovoLight = record
  46.   Position : TVector3;
  47.   Direction: TVector3;
  48.   FieldOfView: Single;
  49.   NearPlane  : Single;
  50.   FarPlane   : Single;
  51.   AspectRatio: Single;
  52.  end;
  53. //---------------------------------------------------------------------------
  54.  PInovoMaterial = ^TInovoMaterial;
  55.  TInovoMaterial = record
  56.   Ambient  : Single;
  57.   Specular : TAsphyreColor;
  58.   SpecPower: Single;
  59.   SkinIndex: Integer;
  60.   BumpIndex: Integer;
  61.   TexTrans : TMatrix3;
  62.  end;
  63. //---------------------------------------------------------------------------
  64.  PInovoInstance = ^TInovoInstance;
  65.  TInovoInstance = record
  66.   Mesh    : TAsphyreCustomMesh;
  67.   Material: TInovoMaterial;
  68.   MeshW   : TMatrix4; // Local-to-world transform
  69.   MeshWV  : TMatrix4; // Local-to-view transform
  70.   
  71.   OriginV : TVector3; // Position in view space
  72.  end;
  73. //---------------------------------------------------------------------------
  74.  TInovoScene = class
  75.  private
  76.   Instances: array of TInovoInstance;
  77.   DrawOrder: array of PInovoInstance;
  78.   DataCount: Integer;
  79.   Capacity : Integer;
  80.   FView : TAsphyreMatrix;
  81.   FProj : TAsphyreMatrix;
  82.   TempM : TAsphyreMatrix;
  83.   FLight: TInovoLight;
  84.   FDevice: TAsphyreDevice;
  85.   FShader: TInovoFluxFx;
  86.   FShadowMap: Integer;
  87.   FScreenShadow: Integer;
  88.   function GetLight(): PInovoLight;
  89.   procedure Grow();
  90.   // Updates MeshWV (Local-to-view) transform of meshes, as well as their
  91.   // position in view space.
  92.   procedure UpdateMeshesWVH(const View: TMatrix4);
  93.   // Initializes the draw order of meshes.
  94.   procedure InitDrawOrder();
  95.   // Sorts meshes by their position in view space.
  96.   procedure SortByOriginV(Left, Right: Integer);
  97.   // Walks through the list sending meshes for shadow rendering to shader.
  98.   procedure ShadeMeshShadows(const Proj: TMatrix4);
  99.   // Prepares the shadow rendering and calls ShadeMeshShadows().
  100.   procedure RenderMeshShadows(Sender: TAsphyreDevice; Tag: TObject);
  101.   // Calculates the view and projection matrices for light source.
  102.   procedure ComputeLightViewProj(out View, Proj: TMatrix4); overload;
  103.   // Calculates the combined matrix View * Projection for the light source.
  104.   function ComputeLightViewProj(): TMatrix4; overload;
  105.   procedure DrawNormal(const View, Proj: TMatrix4);
  106.  public
  107.   property Device: TAsphyreDevice read FDevice;
  108.   property Shader: TInovoFluxFx read FShader;
  109.   // The light used to project shadow maps and illuminate the scene.
  110.   property Light: PInovoLight read GetLight;
  111.   property View : TAsphyreMatrix read FView;
  112.   property Proj : TAsphyreMatrix read FProj;
  113.   // Index to the image holding the shadow map (should be a valid and ready to
  114.   // use Render Target). The depth information will be rendered here.
  115.   property ShadowMap: Integer read FShadowMap write FShadowMap;
  116.   // Index to the image holding screen shadow (should be a valid and ready to
  117.   // use Render Target). The shadow mapped scene will be rendered here.
  118.   property ScreenShadow: Integer read FScreenShadow write FScreenShadow;
  119.   // The following method resets the scene, so a new scene can be rendered.
  120.   // This is usually called at the beginning of rendering phase, before
  121.   // further calls to AddScene.
  122.   procedure ResetScene();
  123.   // Adds a new mesh instance to the scene with the given attributes.
  124.   procedure AddScene(Mesh: TAsphyreCustomMesh; const World: TMatrix4;
  125.    Ambient: Single; Specular: Cardinal; SpecPower: Single; Skin,
  126.    Bump: Integer; const TexTrans: TMatrix3);
  127.   // Renders depth values to shadow map texture from the light perspective.
  128.   procedure RenderShadowMap();
  129.   // Renders the scene normally.
  130.   procedure Render(UseProj: Boolean);
  131.   constructor Create(ADevice: TAsphyreDevice);
  132.   destructor Destroy(); override;
  133.  end;
  134. //---------------------------------------------------------------------------
  135. implementation
  136. //---------------------------------------------------------------------------
  137. const
  138.  MinGrow  = 4;
  139.  GrowUnit = 8;
  140. //---------------------------------------------------------------------------
  141. constructor TInovoScene.Create(ADevice: TAsphyreDevice);
  142. begin
  143.  inherited Create();
  144.  FDevice:= ADevice;
  145.  Capacity := 0;
  146.  DataCount:= 0;
  147.  FView:= TAsphyreMatrix.Create();
  148.  FProj:= TAsphyreMatrix.Create();
  149.  TempM:= TAsphyreMatrix.Create();
  150.  FShader:= TInovoFluxFx.Create(FDevice);
  151.  FShadowMap:= -1;
  152.  FScreenShadow:= -1;
  153. end;
  154. //---------------------------------------------------------------------------
  155. destructor TInovoScene.Destroy();
  156. begin
  157.  FShader.Free();
  158.  TempM.Free();
  159.  FProj.Free();
  160.  FView.Free();
  161.  inherited;
  162. end;
  163. //---------------------------------------------------------------------------
  164. function TInovoScene.GetLight(): PInovoLight;
  165. begin
  166.  Result:= @FLight;
  167. end;
  168. //---------------------------------------------------------------------------
  169. procedure TInovoScene.Grow();
  170. var
  171.  Delta: Integer;
  172. begin
  173.  Delta:= MinGrow + (Capacity div GrowUnit);
  174.  Inc(Capacity, Delta);
  175.  SetLength(Instances, Capacity);
  176.  SetLength(DrawOrder, Capacity);
  177. end;
  178. //---------------------------------------------------------------------------
  179. procedure TInovoScene.AddScene(Mesh: TAsphyreCustomMesh;
  180.  const World: TMatrix4; Ambient: Single; Specular: Cardinal; SpecPower: Single;
  181.  Skin, Bump: Integer; const TexTrans: TMatrix3);
  182. var
  183.  Index: Integer;
  184. begin
  185.  // (1) Make sure the capacity requirements are met for storing new instance.
  186.  if (DataCount >= Capacity) then Grow();
  187.  // (2) Increment number of instances.
  188.  Index:= DataCount;
  189.  Inc(DataCount);
  190.  // (3) Insert instance data
  191.  Instances[Index].Mesh:= Mesh;
  192.  Instances[Index].Material.Ambient  := Ambient;
  193.  Instances[Index].Material.Specular := Specular;
  194.  Instances[Index].Material.SpecPower:= SpecPower;
  195.  Instances[Index].Material.SkinIndex:= Skin;
  196.  Instances[Index].Material.BumpIndex:= Bump;
  197.  Instances[Index].Material.TexTrans := TexTrans;
  198.  Instances[Index].MeshW  := World;
  199.  Instances[Index].MeshWV := IdentityMtx4;
  200.  Instances[Index].OriginV:= ZeroVec3;
  201. end;
  202. //---------------------------------------------------------------------------
  203. procedure TInovoScene.UpdateMeshesWVH(const View: TMatrix4);
  204. var
  205.  i: Integer;
  206. begin
  207.  for i:= 0 to DataCount - 1 do
  208.   with Instances[i] do
  209.    begin
  210.     MeshWV := MeshW * View;
  211.     OriginV:= MeshWV.GetPos();
  212.   end;
  213. end;
  214. //---------------------------------------------------------------------------
  215. procedure TInovoScene.InitDrawOrder();
  216. var
  217.  i: Integer;
  218. begin
  219.  for i:= 0 to DataCount - 1 do
  220.   DrawOrder[i]:= @Instances[i];
  221. end;
  222. //---------------------------------------------------------------------------
  223. procedure TInovoScene.SortByOriginV(Left, Right: Integer);
  224. var
  225.  Lo, Hi  : Integer;
  226.  TempElem: PInovoInstance;
  227.  MidValue: Single;
  228. begin
  229.  Lo:= Left;
  230.  Hi:= Right;
  231.  MidValue:= DrawOrder[(Left + Right) div 2].OriginV.z;
  232.  repeat
  233.   while (DrawOrder[Lo].OriginV.z < MidValue) do Inc(Lo);
  234.   while (DrawOrder[Hi].OriginV.z > MidValue) do Dec(Hi);
  235.   if (Lo <= Hi) then
  236.    begin
  237.     TempElem:= DrawOrder[Lo];
  238.     DrawOrder[Lo]:= DrawOrder[Hi];
  239.     DrawOrder[Hi]:= TempElem;
  240.     Inc(Lo);
  241.     Dec(Hi);
  242.    end;
  243.  until (Lo > Hi);
  244.  if (Left < Hi) then SortByOriginV(Left, Hi);
  245.  if (Lo < Right) then SortByOriginV(Lo, Right);
  246. end;
  247. //---------------------------------------------------------------------------
  248. procedure TInovoScene.ComputeLightViewProj(out View, Proj: TMatrix4);
  249. begin
  250.  View:= LookAtMtx4(FLight.Position, FLight.Position + Norm3(FLight.Direction),
  251.   AxisYVec3);
  252.  Proj:= PerspectiveFovYMtx4(FLight.FieldOfView, FLight.AspectRatio,
  253.   FLight.NearPlane, FLight.FarPlane);
  254. end;
  255. //---------------------------------------------------------------------------
  256. function TInovoScene.ComputeLightViewProj(): TMatrix4;
  257. var
  258.  View, Proj: TMatrix4;
  259. begin
  260.  ComputeLightViewProj(View, Proj);
  261.  Result:= View * Proj;
  262. end;
  263. //---------------------------------------------------------------------------
  264. procedure TInovoScene.ShadeMeshShadows(const Proj: TMatrix4);
  265. var
  266.  i: Integer;
  267. begin
  268.  for i:= 0 to DataCount - 1 do
  269.   begin
  270.    Shader.LightWVP:= Instances[i].MeshWV * Proj;
  271.    Shader.DrawShadow(Instances[i].Mesh);
  272.   end;
  273. end;
  274. //---------------------------------------------------------------------------
  275. procedure TInovoScene.RenderMeshShadows(Sender: TAsphyreDevice; Tag: TObject);
  276. var
  277.  View, Proj: TMatrix4;
  278. begin
  279.  // (1) Retreive View and Projection matrices for light source.
  280.  ComputeLightViewProj(View, Proj);
  281.  // (2) Update World->View transformation for all meshes and calculate their
  282.  // position in view space.
  283.  UpdateMeshesWVH(View);
  284.  // (3) Order the meshes by view depth.
  285.  InitDrawOrder();
  286.  SortByOriginV(0, DataCount - 1);
  287.  // (4) Select technique for building the shadow map.
  288.  FShader.Technique:= itBuildShadowMap;
  289.  // (5) Render the meshes using selected technique.
  290.  FShader.BeginAll();
  291.  ShadeMeshShadows(Proj);
  292.  FShader.EndAll();
  293. end;
  294. //---------------------------------------------------------------------------
  295. procedure TInovoScene.RenderShadowMap();
  296. begin
  297.  if (DataCount > 0)and(FDevice <> nil) then
  298.   FDevice.RenderTo(FShadowMap, RenderMeshShadows, Self, 0, 1.0, 0);
  299. end;
  300. //---------------------------------------------------------------------------
  301. procedure TInovoScene.ResetScene();
  302. begin
  303.  DataCount:= 0;
  304. end;
  305. //---------------------------------------------------------------------------
  306. procedure TInovoScene.DrawNormal(const View, Proj: TMatrix4);
  307. var
  308.  LightViewProj: TMatrix4;
  309.  i: Integer;
  310. begin
  311.  LightViewProj:= ComputeLightViewProj();
  312.  // Eye Position
  313.  Shader.EyePos:= View.GetPos();
  314.  // Light Position
  315.  Shader.LightPos:= FLight.Position;
  316.  // Light Direction
  317.  Shader.LightDir:= FLight.Direction;
  318.  for i:= 0 to DataCount - 1 do
  319.   begin
  320.    Shader.WorldViewProj:= Instances[i].MeshWV * Proj;
  321.    Shader.LightWVP     := LightViewProj;
  322.    Shader.WorldInvT    := TransposeMtx4(InvertMtx4(Instances[i].MeshW));
  323.    Shader.World        := Instances[i].MeshW;
  324.    Shader.Ambient  := Instances[i].Material.Ambient;
  325.    Shader.Specular := Instances[i].Material.Specular;
  326.    Shader.SpecPower:= Instances[i].Material.SpecPower;
  327.    Shader.TexMtx   := Instances[i].Material.TexTrans;
  328.    Shader.UpdateParams();
  329.    with Instances[i].Material do
  330.     begin
  331.      Shader.UpdateTex(FDevice.Images[FShadowMap], FDevice.Images[SkinIndex],
  332.       FDevice.Images[BumpIndex]);
  333.     end;
  334.    Shader.DrawMesh(Instances[i].Mesh);
  335.   end;
  336. end;
  337. //---------------------------------------------------------------------------
  338. procedure TInovoScene.Render(UseProj: Boolean);
  339. begin
  340.  UpdateMeshesWVH(FView.RawMtx^);
  341.  InitDrawOrder();
  342.  SortByOriginV(0, DataCount - 1);
  343.  if (UseProj) then FShader.Technique:= itProjBumpPhong
  344.   else FShader.Technique:= itShadowBumpPhong;
  345.  FShader.BeginAll();
  346.  DrawNormal(FView.RawMtx^, FProj.RawMtx^);
  347.  FShader.EndAll();
  348. end;
  349. //---------------------------------------------------------------------------
  350. end.