Delphi рендеринг Direct3D в растровое изображение вместо экрана - PullRequest
0 голосов
/ 15 марта 2020

Я новичок в Delphi direct3D. Наконец-то получили базовый c фреймворк и запустили рендеринг 2 треугольников на экран. Работает. Однако я бы хотел, чтобы он теперь отображался в Tbitmap. После 2 дней поиска я не нашел ни одного примера в Интернете ... может быть, кто-то здесь может помочь.

Здесь вы найдете код "доказательства концепции". (устранена вся проверка ошибок и т. д. c ..)

в "d3dDevice.Present (nil, nil, 0, nil);" Я хотел бы вывести результат в растровое изображение с именем "frame"

любопытно, если у кого-то есть рабочий код для этого!

grtz Фред

    unit Unit1;
    interface
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    //  {$IFDEF DXG_COMPAT} DirectXGraphics {$ELSE} Direct3D8 {$ENDIF},
      Direct3D8, D3DX8, mmsystem, ExtCtrls ,
      System.Variants,  Vcl.StdCtrls,  Vcl.ComCtrls, types;
    type
      TForm1 = class(TForm)
        Image1: TImage;
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Private declarations }
        procedure IdleHandler(Sender: TObject; var Done: Boolean);
      public
        { Public declarations }
      end;

    var
      Form1              : TForm1;

      frame              : Tbitmap;
      PointerFrameBuffer : pointer;
      screen             : hdc;

    implementation
    {$R *.DFM}

    type
      CUSTOMVERTEX = record         // A structure for our custom vertex type
        position : TD3DXVector3;    // The untransformed, 3D position for the vertex
        color    : dword;
      end;
      PCUSTOMVERTEX = array[0..0] of CUSTOMVERTEX;

    const
      D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ or D3DFVF_DIFFUSE {or D3DFVF_NORMAL});     // Our custom FVF, which describes our custom vertex structure

    // Global variables
    var
      D3D                : IDirect3D8             = nil; // Used to create the D3DDevice
      d3dDevice          : IDirect3DDevice8       = nil; // Our rendering device
      VertexBuffer       : IDirect3DVertexBuffer8 = nil; // Buffer to hold vertices



    procedure Render;  // Name: Render()  // Desc: Draws the scene
    var
     i,tmpMemP : longint;

    begin
      d3dDevice.Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER,  D3DCOLOR_XRGB(0,0,55), 1.0, 0);      // Clear the backbuffer and the zbuffer
      d3dDevice.BeginScene;  // Begin the scene
        // Render the vertex buffer contents
        d3dDevice.SetStreamSource(0, VertexBuffer, SizeOf(CUSTOMVERTEX));
        d3dDevice.SetVertexShader(D3DFVF_CUSTOMVERTEX);
        d3dDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1);
        d3dDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP, 3, 1);
      d3dDevice.EndScene;

      d3dDevice.Present(nil, nil, 0, nil);    // Present the backbuffer contents to the display
      // IN STEAD OFF PRESENTING THE RESULT TO THE SCREEN I WOULD LIKE IT RENDERED/COPIED INTO MY "FRAME" Tbitmap
      tmpMemP := longint(PointerFrameBuffer);
      for i:= 0 to 1024*512-1 do begin longint(pointer(TmpMemP)^) :=  random(256*256*256); inc(tmpMemP,4);  end;
      form1.Image1.Picture.Assign(frame);
    //  CornerOfProgram := form1.clienTToScreen(Point(0,0));                  // we want to dump our frame at the corner of our program
    //  StretchBlt(screen, CornerOfProgram.x , CornerOfProgram.y,1024,512, frame.canvas.handle,0,0,frame.Width,frame.Height,srccopy); // should give non blinking update of screen at higher framerates
    end;



    procedure TForm1.FormCreate(Sender: TObject);
    var
      d3ddm     : TD3DDisplayMode;
      d3dpp     : TD3DPresentParameters;
      pVertices : ^PCUSTOMVERTEX;
      i         : DWORD;
      ViewMatrix, ProjMatrix : TD3DXMatrix;
    begin
    frame := Tbitmap.Create;
    with frame do begin
      HandleType   :=bmDDB; //DDB?
      pixelformat  :=pf32bit;
      Width        :=1024;
      Height       :=512;
      pointerFrameBuffer      := ScanLine[frame.height-1];                          // OPGELET bitmaps liggen omgekeerd in het geheugen               pointer naar laatste scanline = begin onze werkbuffer
    end;
    screen                    := getdc(0);                                          // get a direct handle to our hardware screen for fast dump of frame

      D3D := Direct3DCreate8(D3D_SDK_VERSION);                                   // Create the D3D object
      D3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, d3ddm);                      // Get the current desktop display mode, so we can set up a back buffer of the same format
      // Set up the structure used to create the D3DDevice. Since we are now  using more complex geometry, we will create a device with a zbuffer.
      ZeroMemory(@d3dpp, SizeOf(d3dpp));
      d3dpp.Windowed               := True;
      d3dpp.SwapEffect             := D3DSWAPEFFECT_DISCARD;
      d3dpp.BackBufferFormat       := d3ddm.Format;
      d3dpp.EnableAutoDepthStencil := True;
      d3dpp.AutoDepthStencilFormat := D3DFMT_D16;

      D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, handle, D3DCREATE_hardWARE_VERTEXPROCESSING, d3dpp, d3dDevice);    // Create the Direct3D device
      d3dDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);       // Turn off culling
      d3dDevice.SetRenderState(D3DRS_ZENABLE , iTrue);              // Turn on the zbuffer
      d3dDevice.SetRenderState(D3DRS_LIGHTING, iFalse);             // Turn off D3D lighting, since we are providing our own vertex colors
      // Setup the view, and projection matrices
      D3DXMatrixLookAtLH(ViewMatrix, D3DXVector3(0.0, 0.0, 0.0),    // point from where we look
                                     D3DXVector3(0.0, 0.0, 1.0),    // to where we look
                                     D3DXVector3(0.0, 1.0, 0.0));   // Y axis is our up direction
      d3dDevice.SetTransform(D3DTS_VIEW, ViewMatrix);
      D3DXMatrixPerspectiveFovLH(ProjMatrix, 1, 2, 1.0, 1000.0);    // 512-1024 res -> 1/2          //  we need the field of view (1/4 pi is common), the aspect ratio, and the near and far clipping planes (which define at what distances geometry should be no longer be rendered).
      d3dDevice.SetTransform(D3DTS_PROJECTION, ProjMatrix);

      // INIT GEOMETRY
      d3dDevice.CreateVertexBuffer(50*2*SizeOf(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, Vertexbuffer);    // Create the vertex buffer.
      // Fill the vertex buffer. We are algorithmically generating a cylinder here, including the normals, which are used for lighting.
      Vertexbuffer.Lock(0, 0, PByte(pVertices), 0);

       i:=0; with pVertices[i] do begin position := D3DXVector3(-80,  0,100); color := $ffff0000; end;
       i:=1; with pVertices[i] do begin position := D3DXVector3(-80, 40,100); color := $ffff0000; end;
       i:=2; with pVertices[i] do begin position := D3DXVector3(-80,  0,140); color := $ffff0000; end;

       i:=3; with pVertices[i] do begin position := D3DXVector3( -40, 10, 120); color := $ff00ff00; end;
       i:=4; with pVertices[i] do begin position := D3DXVector3( -40, 30, 120); color := $ff00ff00; end;
       i:=5; with pVertices[i] do begin position := D3DXVector3( -120, 10, 120); color := $ff00ff00; end;

      Vertexbuffer.Unlock;
      Application.OnIdle:= IdleHandler;
    end;




    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      if (VertexBuffer <> nil) then Vertexbuffer:= nil;
      if (d3dDevice    <> nil) then d3dDevice   := nil;
      if (D3D          <> nil) then D3D         := nil;
      releaseDC(0, screen)
    end;





    procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
    begin
      Render;
      Done:= False;
    end;

    end.
...