Jos malo OpenGL-a i DirectX-a

2

Jos malo OpenGL-a i DirectX-a

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2483
  • Gde živiš: Ljubljana

Napisano: 23 Avg 2010 22:35

Od tipova objekata cemo podrzati tacke, linije i trouglove jer od njih moze da se napravi skoro sve, a podrzavaju ih i DirectX i OpenGL. Prvo cemo dodati tip podatka koji definise te tipove objekata:

type   TSGE_PrimitiveType = (     ESGE_PT_POINTLIST,     ESGE_PT_LINELIST,     ESGE_PT_LINESTRIP,     ESGE_PT_TRIANGLELIST,     ESGE_PT_TRIANGLESTRIP,     ESGE_PT_TRIANGLEFAN   );

Point list znaci da ce drajver buffer citati kao niz tacaka i crtace onoliko tacaka koliko je vertex-a u buffer-u. Line list znaci da ce drajver crtati linije, a svaka linija je definisana uz pomoc dva vertex-a, sto znaci da za3 linije moramo da imamo 6 vertex-a u buffer-u. Line strip takodje crta linije, ali s tom razlikom da osim prve svaka sledeca linija pocinje tamo gde je prethodna zavrsena i zbog toga za 6 linija nam treba samo 7 vertex-a (2 vertex-a za prvu i po jedan za svaku sledecu liniju). Triangle list znaci da ce drajver crtati trouglove, a svaki trougao je definisan uz pomoc 3 vertex-a i za 6 trouglova nam treba 18 vertex-a. Triangle strip crta trouglove, ali se svaki sledeci trougao nastavlja na 2 vertex-a prethodnog, sto znaci da nam za prvi trougao trebaju 3 vertex-a, a za svaki sledeci samo po 1. Triangle fan je slican kao i triangle strip s razlikom da je prvi vertex centar oko kojeg se kreiraju trouglovi.

Ok... sada moramo dodati taj parametar u RenderOperation klasu preko jedne privatne promenljive i funkcije za citanje i postavljanje:

type   TRenderOperation = class(TSGERenderOperation)   private     FPrimitiveType: TSGE_PrimitiveType;   protected     function GetPrimitiveType: TSGE_PrimitiveType; override;     procedure SetPrimitiveType(APrimitiveType: TSGE_PrimitiveType); override;   public     property PrimitiveType: TSGE_PrimitiveType read GetPrimitiveType write SetPrimitiveType;   end; function TRenderOperation.GetPrimitiveType: TSGE_PrimitiveType; begin   Result := FPrimitiveType; end; procedure TRenderOperation.SetPrimitiveType(APrimitiveType: TSGE_PrimitiveType   ); begin   FPrimitiveType := APrimitiveType; end;

Zatim moramo u support klasama dodati funkcije koje ce nas tip prevesti u tip za DirectX i OpenGL. Prvo cemo obraditi OpenGL jer je laksi:

function TOGLSupport.GetPrimitiveType(APrimitiveType: TSGE_PrimitiveType   ): Cardinal; begin   case APrimitiveType of     ESGE_PT_POINTLIST:       Result := GL_POINTS;     ESGE_PT_LINELIST:       Result := GL_LINES;     ESGE_PT_LINESTRIP:       Result := GL_LINE_STRIP;     ESGE_PT_TRIANGLELIST:       Result := GL_TRIANGLES;     ESGE_PT_TRIANGLESTRIP:       Result := GL_TRIANGLE_STRIP;     ESGE_PT_TRIANGLEFAN:       Result := GL_TRIANGLE_FAN;   else     Result := GL_TRIANGLES;   end; end;

Funkcija direktno mapira nas tip na OpenGL tip i vraca rezultat. Render funkcija mora uzeti u obzir tip objekta i zato sada izgleda ovako:

procedure TOGLRenderer.Render(ARenderOperation: TSGERenderOperation); var   I: Integer;   VertexDeclaration: TSGEVertexDeclaration;   VertexBufferBinding: TSGEVertexBufferBinding;   VertexBuffer: TOGLVertexBuffer;   Data: PByte; begin   inherited Render(ARenderOperation);   VertexDeclaration := ARenderOperation.VertexDeclaration;   VertexBufferBinding := ARenderOperation.VertexBufferBinding;   for I := 0 to VertexDeclaration.Count - 1 do   begin     VertexBuffer := TOGLVertexBuffer(VertexBufferBinding.VertexBuffers[VertexDeclaration.Elements[I].ElementSource]);     if VertexBuffer <> nil then     begin       if GetSupport.HardwareBuffers then       begin         glBindBufferARB(GL_ARRAY_BUFFER_ARB, VertexBuffer.HWVertexBuffer);         Data := PByte(VertexDeclaration.Elements[I].ElementOffset);       end       else         Data := VertexBuffer.SWVertexBuffer + VertexDeclaration.Elements[I].ElementOffset;       if ARenderOperation.VertexOffset <> 0 then         Data := Data + (VertexBuffer.VertexSize * ARenderOperation.VertexOffset);       case VertexDeclaration.Elements[I].ElementUsage of         ESGE_VEU_POSITION:         begin           glVertexPointer(GetSupport.GetElementTypeSize(VertexDeclaration.Elements[I].ElementType),             GetSupport.GetElementType(VertexDeclaration.Elements[I].ElementType),             VertexBuffer.VertexSize, Data);           glEnableClientState(GL_VERTEX_ARRAY);         end;         ESGE_VEU_NORMAL:         begin           glNormalPointer(GetSupport.GetElementType(VertexDeclaration.Elements[I].ElementType),             VertexBuffer.VertexSize, Data);           glEnableClientState(GL_NORMAL_ARRAY);         end;         ESGE_VEU_DIFFUSE:         begin           glColorPointer(GetSupport.GetElementTypeSize(VertexDeclaration.Elements[I].ElementType),             GetSupport.GetElementType(VertexDeclaration.Elements[I].ElementType),             VertexBuffer.VertexSize, Data);           glEnableClientState(GL_COLOR_ARRAY);         end;         ESGE_VEU_TEXTURE_COORDINATES:         begin           if GetSupport.Multitexture then             glClientActiveTextureARB(GL_TEXTURE0_ARB + VertexDeclaration.Elements[I].ElementIndex)           else             if VertexDeclaration.Elements[I].ElementIndex <> 0 then               Continue;           glTexCoordPointer(GetSupport.GetElementTypeSize(VertexDeclaration.Elements[I].ElementType),             GetSupport.GetElementType(VertexDeclaration.Elements[I].ElementType),             VertexBuffer.VertexSize, Data);           glEnableClientState(GL_TEXTURE_COORD_ARRAY);         end;       end;     end;   end;   glDrawArrays(GetSupport.GetPrimitiveType(ARenderOperation.PrimitiveType), 0, ARenderOperation.VertexCount);   glDisableClientState(GL_VERTEX_ARRAY);   glDisableClientState(GL_NORMAL_ARRAY);   glDisableClientState(GL_COLOR_ARRAY);   if GetSupport.Multitexture then   begin     for I := 0 to VertexDeclaration.Count - 1 do       if VertexDeclaration.Elements[I].ElementUsage = ESGE_VEU_TEXTURE_COORDINATES then       begin         glClientActiveTextureARB(GL_TEXTURE0_ARB + VertexDeclaration.Elements[I].ElementIndex);         glDisableClientState(GL_TEXTURE_COORD_ARRAY);       end;   end   else     glDisableClientState(GL_TEXTURE_COORD_ARRAY); end;

Kao sto vidite, jedina razlika u odnosu na prethodnu verziju je da glDrawArrays funkcija kao prvi parametar uzima tip objekta koji zelimo, sve ostalo je ostalo isto.

DirectX za razliku od OpenGL-a u funkciji za crtanje ne trazi broj vertex-a koje zelimo da iskoristimo za crtanje, nego broj objekata koje zelimo da nacrtamo pa cemo zato morati da napisemo funkciju koja ce vratiti tip objekta i funkciju koja ce na osnovu tipa objekta i broja vertex-a vratiti broj objekata za crtanje (na pocetku odgovora sam objasnio u kakvom odnosu su broj vertex-a i broj objekata za koji tip):

function TDX9Support.GetPrimitiveType(APrimitiveType: TSGE_PrimitiveType   ): TD3DPrimitiveType; begin   case APrimitiveType of     ESGE_PT_POINTLIST:       Result := D3DPT_POINTLIST;     ESGE_PT_LINELIST:       Result := D3DPT_LINELIST;     ESGE_PT_LINESTRIP:       Result := D3DPT_LINESTRIP;     ESGE_PT_TRIANGLELIST:       Result := D3DPT_TRIANGLELIST;     ESGE_PT_TRIANGLESTRIP:       Result := D3DPT_TRIANGLESTRIP;     ESGE_PT_TRIANGLEFAN:       Result := D3DPT_TRIANGLEFAN;   else     Result := D3DPT_TRIANGLELIST;   end; end; function TDX9Support.GetPrimitiveCount(APrimitiveType: TSGE_PrimitiveType;   AVertexCount: Integer): Integer; begin   case APrimitiveType of     ESGE_PT_POINTLIST:       Result := AVertexCount;     ESGE_PT_LINELIST:       Result := AVertexCount div 2;     ESGE_PT_LINESTRIP:       Result := AVertexCount - 1;     ESGE_PT_TRIANGLELIST:       Result := AVertexCount div 3;     ESGE_PT_TRIANGLESTRIP:       Result := AVertexCount - 2;     ESGE_PT_TRIANGLEFAN:       Result := AVertexCount - 2;   else     Result := AVertexCount div 3;   end; end;

Sad kad imamo te dve pomocne funkcije, mozemo popraviti kod za crtanje:

procedure TDX9Renderer.Render(ARenderOperation: TSGERenderOperation); var   Device: IDirect3DDevice9;   VertexBufferBinding: TSGEVertexBufferBinding;   I, LastVertexBufferIndex: Integer; begin   inherited Render(ARenderOperation);   Device := GetDevice;   Device.SetVertexDeclaration(TDX9VertexDeclaration(ARenderOperation.VertexDeclaration).D3DVertexDeclaration);   LastVertexBufferIndex := -1;   VertexBufferBinding := ARenderOperation.VertexBufferBinding;   for I := 0 to VertexBufferBinding.Count - 1 do     if VertexBufferBinding.VertexBuffers[I] <> nil then     begin       Device.SetStreamSource(I, TDX9VertexBuffer(VertexBufferBinding.VertexBuffers[I]).D3DVertexBuffer,         0, VertexBufferBinding.VertexBuffers[I].VertexSize);       LastVertexBufferIndex := I;     end     else       Device.SetStreamSource(I, nil, 0, 0);   for I := VertexBufferBinding.Count to FLastVertexBufferIndex do     Device.SetStreamSource(I, nil, 0, 0);   FLastVertexBufferIndex := LastVertexBufferIndex;   Device.DrawPrimitive(GetSupport.GetPrimitiveType(ARenderOperation.PrimitiveType),     ARenderOperation.VertexOffset,     GetSupport.GetPrimitiveCount(ARenderOperation.PrimitiveType, ARenderOperation.VertexCount)); end;

Kao i u OpenGL verziji, razlika je samo u zvanju funkcije za crtanje koja sada uzima tip i broj objekata za crtanje na osnovu PrimitiveType parametra iz RenderOperation-a.

Sada u glavnom programu mozete malo da eksperimentisete raznim nacinima crtanja... potrebno je samo postaviti tip objekta:

program HelloWorld; {$I SGE.inc} {$IFDEF SGE_Delphi} {$APPTYPE CONSOLE} {$ENDIF} uses   {$IFDEF SGE_Windows}   Windows,   {$ENDIF}   SysUtils,   SGETypes in '..\..\Common\SGETypes.pas',   HTMLLogger in 'HTMLLogger.pas',   {$IFDEF SGE_Windows}   DX9Renderer in '..\..\Source\Renderers\DX9Renderer\DX9Renderer.pas',   {$ENDIF}   OGLRenderer in '..\..\Source\Renderers\OGLRenderer\OGLRenderer.pas'; type   TMyVertex = packed record     X, Y, Z: Single;     R, G, B, A: Single;   end; const   Vertices: array[0..2] of TMyVertex = (     (X: 0; Y: 1; Z: 0; R: 1; G: 0; B: 0; A: 1),     (X: 1; Y: -1; Z: 0; R: 0; G: 1; B: 0; A: 1),     (X: -1; Y: -1; Z: 0; R: 0; G: 0; B: 1; A: 1)); var   Engine: TSGEEngine = nil;   HTML: THTMLLogger = nil;   {$IFDEF SGE_Windows}   DX9Rendr: TDX9Renderer = nil;   {$ENDIF}   OGLRendr: TOGLRenderer = nil;   RendrIndex: String;   I: Integer;   VertexBuffer: TSGEVertexBuffer;   VertexBufferData: Pointer;   VertexDeclaration: TSGEVertexDeclaration;   VertexBufferBinding: TSGEVertexBufferBinding;   RenderOperation: TSGERenderOperation; begin   try     try       HTML := THTMLLogger.Create('SGE.html');       Engine := CreateSGEEngine('', HTML.Log);       Engine.Logger.LogLevel := ESGE_LL_INFO;       {$IFDEF SGE_Windows}       DX9Rendr := TDX9Renderer.Create(Engine);       Engine.RegisterRenderer(DX9Rendr);       {$ENDIF}       OGLRendr := TOGLRenderer.Create(Engine);       Engine.RegisterRenderer(OGLRendr);       WriteLn('Registered renderers:');       for I := 0 to Engine.RendererCount - 1 do         WriteLn(Format('  %d. %s', [I + 1, Engine.Renderers[I].Name]));       WriteLn;       Write('Select renderer: ');       ReadLn(RendrIndex);       I := StrToIntDef(RendrIndex, 0) - 1;       if (I < 0) or (I >= Engine.RendererCount) then         Exit;       Engine.Initialize(Engine.Renderers[I]);       Engine.Renderer.CreateWindow('SGE using ' + Engine.Renderers[I].Name);       Engine.Renderer.Matrix[ESGE_MT_PROJECTION] := SGEMatrixPerspective(45,         Engine.Renderer.RenderWindow.Width / Engine.Renderer.RenderWindow.Height, 1, 1000);       Engine.Renderer.Matrix[ESGE_MT_VIEW] := SGEMatrixLookAt(         SGEVector3(0, 3, 5), SGEVector3(0, 0, 0), SGEVector3(0, 1, 0));       VertexBuffer := Engine.Renderer.CreateVertexBuffer(7 * SizeOf(Single), 3, ESGE_BU_STATIC);       VertexBufferData := VertexBuffer.Lock(0, 0, ESGE_LT_NORMAL);       Move(Vertices, VertexBufferData^, VertexBuffer.BufferSize);       VertexBuffer.Unlock;       VertexDeclaration := Engine.Renderer.CreateVertexDeclaration;       VertexDeclaration.AddElement(0, 0, ESGE_VET_FLOAT3, ESGE_VEU_POSITION);       VertexDeclaration.AddElement(0, 3 * SizeOf(Single), ESGE_VET_COLOUR, ESGE_VEU_DIFFUSE);       VertexBufferBinding := Engine.Renderer.CreateVertexBufferBinding;       VertexBufferBinding.AddVertexBuffer(VertexBuffer);       RenderOperation := Engine.Renderer.CreateRenderOperation;       RenderOperation.VertexDeclaration := VertexDeclaration;       RenderOperation.VertexBufferBinding := VertexBufferBinding;       RenderOperation.VertexCount := 3;       RenderOperation.PrimitiveType := ESGE_PT_TRIANGLELIST;       while Engine.ProcessMessages do       begin         Engine.Renderer.BeginFrame;         Engine.Renderer.Clear([ESGE_FBT_COLOR], SGEColor(0.4, 0.4, 1, 0));         Engine.Renderer.Matrix[ESGE_MT_WORLD] := SGEMatrixRotate(Engine.Timer.Time / 20, 0, 1, 0);         Engine.Renderer.Render(RenderOperation);         Engine.Renderer.EndFrame;         Engine.Renderer.SwapBuffers;       end;       RenderOperation.Drop;       VertexBufferBinding.Drop;       VertexDeclaration.Drop;       VertexBuffer.Drop;       Engine.Finalize;     except       on E: Exception do       begin         {$IFDEF SGE_Windows}         MessageBox(0, PChar(E.Message), PChar(ExtractFileName(ParamStr(0))), 0);         {$ELSE}         WriteLn(ExtractFileName(ParamStr(0)) + ': ' + E.Message);         {$ENDIF}       end;     end;   finally     {$IFDEF SGE_Windows}     DX9Rendr.Free;     {$ENDIF}     OGLRendr.Free;     Engine.Free;     HTML.Free;   end; end.

Imajte na umu da za sada point list crta tacke velicine 1 pixel-a i dosta ih je tesko videti... taj problem cemo resiti kad budemo napravili materijale koji ce sluziti za postavljanje raznih opcija za crtanje, od toga da li svetlo utice na crtanje, preko tekstura, do magle i drugih efekata.

U ovoj arhivi su popravljene greske iz prethodne i program ce raditi kako treba: https://www.mycity.rs/must-login.png

za sledeci tutorijal bi mogli da uzmemo teksture Smile

Dopuna: 24 Avg 2010 20:10

Engine ce morati malo da poceka jer sam dobio neki projekat da uradim... ali, cim vreme dozvoli nastavljamo dalje Smile

Dopuna: 29 Sep 2010 23:18

S vremena na vreme radim malo na engine-u... malo sam promenio arhitekturu da vise lici na Pascal jezik. Dodao sam teksturice, mogucnost za kreiranje fullscreen prozora, mogucnost promene rezolucije u toku izvrsavanja programa, poceo sam sa pravljenjem objekata koji ce se koristiti za crtanje (nema smisla rucno puniti buffer-e i opisne klase), tu je jos i jednostavna klasa za ulazne podatke sa tastature i misa (dzojstici ce posle doci na red), i jos svasta nesto... sve u svemu, cim budem imao malo vise vremena, pocecu ponovo da pisem i kako se sve to pravi. Do tada evo jednog malog primera koji koristi neke nove stvari (teksture, promenu rezolucije, "manual object" i materijale za crtanje, FSAA, ulaz sa tastature... i mislim da je to to):
program PGETest; {$I PGE.inc} uses   SysUtils, {$IFDEF PGE_Windows}   Windows, {$ENDIF}   PGETypes; type   TPGETest = class   private     FResized: Boolean;     FManualObject: TPGEManualObject;   public     constructor Create(ADevice: TPGEDevice);     destructor Destroy; override;     procedure OnRender(ADevice: TPGEDevice; ATime, ADeltaTime: Cardinal);     procedure OnUpdate(ADevice: TPGEDevice; ATime, ADeltaTime: Cardinal);     procedure OnKeyPress(ADevice: TPGEDevice; AKeyCode: TPGE_KeyCodes;       AChar: Char);   end;   { TPGETest } constructor TPGETest.Create(ADevice: TPGEDevice); begin   FResized := False;   ADevice.Renderer.Matrices[EPGE_MT_PROJECTION] := PGEMatrixPerspective     (45, ADevice.Renderer.RenderWindow.Width /       ADevice.Renderer.RenderWindow.Height, 1, 1000);   ADevice.Renderer.Matrices[EPGE_MT_VIEW] := PGEMatrixLookAt     (PGEVector3(0, 3, 5), PGEVector3(0, 0, 0), PGEVector3(0, 1, 0));   ADevice.Renderer.ClearColor := PGEColor(0.4, 0.4, 1, 0);   FManualObject := ADevice.SceneManager.CreateManualObject;   FManualObject.BeginObject(EPGE_PT_TRIANGLESTRIP);   FManualObject.TextureCoord(1, 1);   FManualObject.Vertex(1, -1, 0);   FManualObject.TextureCoord(1, 0);   FManualObject.Vertex(1, 1, 0);   FManualObject.TextureCoord(0, 1);   FManualObject.Vertex(-1, -1, 0);   FManualObject.TextureCoord(0, 0);   FManualObject.Vertex(-1, 1, 0);   FManualObject.EndObject;   FManualObject.Material := ADevice.Renderer.CreateMaterial;   FManualObject.Material.Textures[0] := ADevice.SceneManager.GetTexture     ('rocker.png');   FManualObject.Material.CullFace := EPGE_CF_NONE;   FManualObject.Material.LightingEnabled := False; end; destructor TPGETest.Destroy; begin   FManualObject.Material.Free;   FManualObject.Free;   inherited; end; procedure TPGETest.OnKeyPress(ADevice: TPGEDevice; AKeyCode: TPGE_KeyCodes;   AChar: Char); begin   if AKeyCode = EPGE_KC_ESCAPE then     ADevice.StopRendering; end; procedure TPGETest.OnRender(ADevice: TPGEDevice; ATime, ADeltaTime: Cardinal); begin   if ADevice.Renderer.BeginScene then   begin     ADevice.Renderer.Clear;     ADevice.Renderer.Matrices[EPGE_MT_WORLD] := PGEMatrixRotate       (ATime / 20, 0, 1, 0);     FManualObject.Render;     ADevice.Renderer.EndScene;   end; end; procedure TPGETest.OnUpdate(ADevice: TPGEDevice; ATime, ADeltaTime: Cardinal); begin   if ATime > 10000 then     if not FResized then     begin       FResized := True;       ADevice.Renderer.RenderWindow.SetWindowMode(VideoMode(1024, 768, 32),         ZBufferFormat(24, 8), WindowSettings(False, True, 2));     end; end; var   Device: TPGEDevice = nil;   RendererClass: TPGERendererClass;   RenderWindow: TPGERenderWindow = nil;   Test: TPGETest = nil; begin   try     Device := CreateDevice;     if Device <> nil then     begin       RendererClass := Device.RegisteredRenderers[0];       Device.Initialize(RendererClass, 'PGE using ' + RendererClass.GetName,         VideoMode(800, 600, 32), ZBufferFormat(0, 0), WindowSettings           (False, False, 2));       Test := TPGETest.Create(Device);       Device.OnRender := Test.OnRender;       Device.OnUpdate := Test.OnUpdate;       Device.OnKeyPress := Test.OnKeyPress;       Device.StartRendering;       Test.Free;       Device.Free;     end;   except     on E: Exception do     begin {$IFDEF PGE_Windows}       MessageBox(0, PChar(E.Message), PChar(ExtractFileName(ParamStr(0))), 0); {$ELSE}       WriteLn(ExtractFileName(ParamStr(0)) + ': ' + E.Message); {$ENDIF}     end;   end; end.

U zip-u su samo exe fajl i tekstura. Program je napravljen tako da ucita teksturicu, vrti je na ekranu, posle 10 sekundi promeni rezoluciju i onda nastavlja da vrti teksturu. Izlazi se pritiskom na taster Esc.

https://www.mycity.rs/must-login.png

Dopuna: 02 Okt 2010 17:04

Zaboravih da kazem... preimenovao sam engine iz SGE (Simple Graphics Engine) u PGE (Pascal Graphics Engine) jer polako, ali sigurno prestaje da bude "simple" Very Happy

Ovde je najnovija verzija engine-a u kojoj je skoro sve od funkcija koje sam zamislio napravljeno za DirectX renderer i Windows platformu. Posto je fajl malo veci, morao sam da ga stavim na eksterni sajt: http://www.zshare.net/download/810305139a30f296/



Registruj se da bi učestvovao u diskusiji. Registrovanim korisnicima se NE prikazuju reklame unutar poruka.
Ko je trenutno na forumu
 

Ukupno su 740 korisnika na forumu :: 26 registrovanih, 2 sakrivenih i 712 gosta   ::   [ Administrator ] [ Supermoderator ] [ Moderator ] :: Detaljnije

Najviše korisnika na forumu ikad bilo je 3466 - dana 01 Jun 2021 17:07

Korisnici koji su trenutno na forumu:
Korisnici trenutno na forumu: A.R.Chafee.Jr., AMCXXL, Andrija357, Apok, Bobrock1, Boris BM, CikaKURE, Duh sa sekirom, Frunze, indja, jackreacher011011, kolle.the.kid, ksyyaj, Kubovac, Lazarus, Lieutenant, Metanoja, naki011, nesa1962, nuke92, Oscar, Srki94, stagezin, suton, vathra, vlajkox