AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Projektion mit Direct3D berechnen
Thema durchsuchen
Ansicht
Themen-Optionen

Projektion mit Direct3D berechnen

Offene Frage von "oXmoX"
Ein Thema von oXmoX · begonnen am 27. Jul 2005 · letzter Beitrag vom 28. Jul 2005
 
oXmoX

Registriert seit: 8. Jun 2005
85 Beiträge
 
#1

Projektion mit Direct3D berechnen

  Alt 27. Jul 2005, 20:39
Hallo!

Ich möchte mit Direct3D einen 2D-Schriftzug auf dem Bildschirm genau dort zeichnen, wo sich die Kante eines Würfels befindet.

Hier erstmal mein Quellcode

Code:
unit RendererD3D;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Direct3D8, d3dx8, ExtCtrls, ComCtrls;

const
  Pi180      = Pi/180.0;
  Fovy      = Pi/4;     // Öffnungswinkel des Sichtkegels (Field of view)
  ViewDist  = 15;       // Abstand des Betrachters vom Nullpunkt
  ViewHeight = 5;        // Höhe des Betrachters
  Delta     = 0.01;     // Winkelinkrement für Animation

  CubeCount = 36;

type
  TMyVertex = record
    x,y,z    : single;
    color    : dword;
    end;

  // Vertexliste für Würfel
  TCube = array [0..CubeCount-1] of TMyVertex;

const
  D3D8T_CUSTOMVERTEX =D3DFVF_XYZ or D3DFVF_DIFFUSE;

  // Standardwürfel (Seitenlänge 2)
  NormCube : TCube = ( 
    (x :-1.0; y :-1.0; z :-1.0; color : $000000FF), // Vorn
    (x :-1.0; y : 1.0; z :-1.0; color : $000000FF),
    (x : 1.0; y : 1.0; z :-1.0; color : $000000FF),
    (x : 1.0; y : 1.0; z :-1.0; color : $000000FF),
    (x : 1.0; y :-1.0; z :-1.0; color : $000000FF),
    (x :-1.0; y :-1.0; z :-1.0; color : $000000FF),

    (x :-1.0; y :-1.0; z : 1.0; color : $00FF00FF), // Links
    (x :-1.0; y : 1.0; z : 1.0; color : $00FF00FF),
    (x :-1.0; y : 1.0; z :-1.0; color : $00FF00FF),
    (x :-1.0; y : 1.0; z :-1.0; color : $00FF00FF),
    (x :-1.0; y :-1.0; z :-1.0; color : $00FF00FF),
    (x :-1.0; y :-1.0; z : 1.0; color : $00FF00FF),

    (x : 1.0; y :-1.0; z : 1.0; color : $0000FF00), // Hinten
    (x : 1.0; y : 1.0; z : 1.0; color : $0000FF00),
    (x :-1.0; y : 1.0; z : 1.0; color : $0000FF00),
    (x :-1.0; y : 1.0; z : 1.0; color : $0000FF00),
    (x :-1.0; y :-1.0; z : 1.0; color : $0000FF00),
    (x : 1.0; y :-1.0; z : 1.0; color : $0000FF00),

    (x : 1.0; y :-1.0; z :-1.0; color : $0000FFFF), // Rechts
    (x : 1.0; y : 1.0; z :-1.0; color : $0000FFFF),
    (x : 1.0; y : 1.0; z : 1.0; color : $0000FFFF),
    (x : 1.0; y : 1.0; z : 1.0; color : $0000FFFF),
    (x : 1.0; y :-1.0; z : 1.0; color : $0000FFFF),
    (x : 1.0; y :-1.0; z :-1.0; color : $0000FFFF),

    (x :-1.0; y : 1.0; z :-1.0; color : $00FF0000), // Oben
    (x :-1.0; y : 1.0; z : 1.0; color : $00FF0000),
    (x : 1.0; y : 1.0; z : 1.0; color : $00FF0000),
    (x : 1.0; y : 1.0; z : 1.0; color : $00FF0000),
    (x : 1.0; y : 1.0; z :-1.0; color : $00FF0000),
    (x :-1.0; y : 1.0; z :-1.0; color : $00FF0000),

    (x : 1.0; y :-1.0; z :-1.0; color : $00FFFF00), // Unten
    (x : 1.0; y :-1.0; z : 1.0; color : $00FFFF00),
    (x :-1.0; y :-1.0; z : 1.0; color : $00FFFF00),
    (x :-1.0; y :-1.0; z : 1.0; color : $00FFFF00),
    (x :-1.0; y :-1.0; z :-1.0; color : $00FFFF00),
    (x : 1.0; y :-1.0; z :-1.0; color : $00FFFF00));

type
  TRendererD3D = class
    procedure StartScene(Handle: HWND);
    procedure StopScene;
  private
    lpd3d           : IDIRECT3D8;
    lpd3ddevice     : IDirect3DDevice8;
    D3dDevCaps      : TD3DCaps8;

    // Vertexbuffer für Würfel
    CubeVB : IDirect3DVertexBuffer8;

    // Rotationswinkel für den Beobachter in Grad
    RotY  : single ;

    HwVertexProcess,
    FullScreen,
    Animate         : boolean;

    FFont:  TFont;
    FDXFont: ID3DXFont;

    procedure D3DInit(Handle: HWND);
    procedure D3DShutdown;
    procedure D3DInitScene;
    procedure D3DKillScene;
    procedure D3DRender;
    procedure MyIdleHandler (Sender: TObject; var Done: Boolean);
  public
    constructor Create;
  end;

implementation

constructor TRendererD3D.Create;
begin
  // Font erzeugen
  Self.FFont := TFont.Create;
  with Self.FFont do
  begin
    Style := [fsBold];
    Size := 10;
    Name := 'Arial';
  end;

  lpd3d:=nil;
  lpd3ddevice:=nil;
  CubeVB:=nil;

  RotY:=0;
  Animate:=false;
  Application.OnIdle:= MyIdleHandler;
  end;

procedure TRendererD3D.D3DInit(Handle: HWND);
var
  hr   : HRESULT;
  d3dpp : TD3DPRESENTPARAMETERS;
  d3ddm : TD3DDISPLAYMODE;
  vp   : integer;
begin
  lpd3d:=Direct3DCreate8(D3D_SDK_VERSION);
  if(lpd3d=nil) then
    raise Exception.Create('Fehler beim Erstellen von Direct3D!');

  // Setze zunächst alle D3DPRESENT_PARAMETERS auf 0 
  ZeroMemory(@d3dpp,sizeof(d3dpp));
  with d3dpp do begin
    SwapEffect:=D3DSWAPEFFECT_DISCARD;
    hDeviceWindow:=Handle;     // Dies ist unser HWND von TForm

    // Wir brauche einen Z-Buffer also schalten wir ihn ein
    EnableAutoDepthStencil := TRUE;
    AutoDepthStencilFormat := D3DFMT_D16;

    // Initialisieren des Backbuffers
    Windowed:=not FullScreen;

    hr:=lpd3d.GetAdapterDisplayMode(D3DADAPTER_DEFAULT,d3ddm);
    if failed(hr) then
      raise Exception.Create('Fehler beim Ermitteln des Dislaymodes');
    BackBufferFormat := d3ddm.Format;

  end;

  // Hardware T&L? 
  hr:=lpd3d.GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,D3dDevCaps);
  if FAILED(hr) then
    raise Exception.Create('Fehler beim Abfragen der DevCaps');
  HwVertexProcess:=D3dDevCaps.DevCaps and D3DDEVCAPS_HWTRANSFORMANDLIGHT <> 0;

  if HwVertexProcess then vp:=D3DCREATE_HARDWARE_VERTEXPROCESSING
  else vp:=D3DCREATE_SOFTWARE_VERTEXPROCESSING;

  //Erstellen des D3D-Device
  hr:=lpd3d.CreateDevice(D3DADAPTER_DEFAULT,
                         D3DDEVTYPE_HAL,
                         Handle,
                         vp,
                         d3dpp,
                         lpd3ddevice);
  if FAILED(hr) then
    raise Exception.Create('Fehler beim Erzeugen des 3D-Device');
  end;

// *** D3DShutdown hier werden die Resourcen von D3D wieder freigegeben
procedure TRendererD3D.D3DShutdown;
begin
  if assigned(lpd3ddevice) then lpd3ddevice:=nil;
  if assigned(lpd3d) then lpd3d:=nil;
  end;

procedure TRendererD3D.D3DInitScene;
var
  hr           : HRESULT;
  vbVertices   : pByte;
  ProjMatrix   : TD3DXMATRIX;

begin
  HR := D3DXCreateFont(Self.lpd3ddevice, Self.FFont.Handle, Self.FDXFont);
  if HR <> S_OK then
    raise Exception.Create('Fehler beim Erzeugen des Font.');

  if assigned(lpd3ddevice) then with lpd3ddevice do begin
    // Vertex Buffer für Würfel
    hr:=CreateVertexBuffer (sizeof(TCube),
                            D3DUSAGE_WRITEONLY, // Nur Schreibzugriffe
                            D3D8T_CUSTOMVERTEX, // Unser Vertex
                            D3DPOOL_MANAGED,
                            CubeVB);            // Pointer zu unserem Buffer

    if FAILED(hr) then
      raise Exception.Create('Fehler beim Erstellen des Vertex Buffers');

    // Nun kopieren wir unsere Vertizes in den Buffer
    // Wir müssen es zuvor mit Lock festhalten, um es bearbeiten zu können
    with CubeVB do begin
      hr:=Lock(0, // Offset, an dem wir beginnen
               0, // Größe des locks ( 0 für alles )
               vbVertices, // Wenn erfolgreich dann hier ablegen
               0); // sonstige Flags
      if FAILED(hr) then
        raise Exception.Create('Fehler beim Locken des Vertex-Buffers');
      // Hier wird der Vertexbuffer kopiert.
      Move(NormCube,vbVertices^,SizeOf(TCube));
      // Und wieder loslassen
      Unlock;
      end;

    // Lighting abschalten
    SetRenderState(D3DRS_LIGHTING,0);
    // Z-Buffer beim Rendern einschalten
    SetRenderState(D3DRS_ZENABLE,D3DZB_TRUE);

    // Erstelle eine Projektionsmatrix
    D3DXMatrixPerspectiveFovLH(ProjMatrix, // Resultierende Matrix
                               Fovy,       // Öffnungswinkel des Sichtkegels
                               640/480,    // Seitenverhältnis der Ansicht
                               1.0,        // Mindeste Nähe
                               1000.0);    // Maximal sichtbare Entfernung
    SetTransform(D3DTS_PROJECTION,ProjMatrix );
    end;
  Animate:=true;
  end;

procedure TRendererD3D.D3DKillScene;
begin
  CubeVB:=nil;
  end;

// Rendern der Szene
procedure TRendererD3D.D3DRender;
var
  WorldMatrix,
  ViewMatrix,
  ProjMatrix,
  TempMatrix    : TD3DXMATRIX;
  WorldPoint    : TD3DXVector3;
  ScrnPoint     : TD3DXVector4;
  TXTRect       : TRect;
begin
  RotY:=RotY+Delta;   // Rotation des Beobachters

  if assigned(lpd3ddevice) then with lpd3ddevice do begin
    Clear(0,          // Wieviel Rechtecke löschen? 0 Löscht alle
          nil,        // Pointer zu den Rechtecken. nil = Ganzer Bildschirm
          D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER,
          D3DCOLOR_XRGB(0,0,0), //Hintergrundfarbe schwarz
          1,          // Lösche ZBuffer ( Wir haben momentan noch keinen )
          0 );

    if SUCCEEDED(BeginScene) then begin

      D3DXMatrixLookAtLH (ViewMatrix,D3DXVECTOR3(ViewDist*sin(Pi180*RotY),
                                                 ViewHeight,
                                                 ViewDist*cos(Pi180*RotY)),
                                     D3DXVECTOR3(0.0,0.0,0.0),
                                     D3DXVECTOR3(0.0,1.0,0.0));

      SetTransform(D3DTS_VIEW,ViewMatrix);

      // Vertex Typ einstellen
      SetVertexShader(D3D8T_CUSTOMVERTEX);

      // Stream auf Vertexbuffer für Würfel setzen
      SetStreamSource(0,CubeVB,sizeof(TMyVertex));

      SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
      // Setze die Welt-Matrix für die Kiste etwas nach oben
      D3DXMatrixTranslation(WorldMatrix,0,0,0);
      SetTransform(D3DTS_WORLD,WorldMatrix);

      // Zeichnen der Kiste
      DrawPrimitive(D3DPT_TRIANGLELIST,0,12);
      EndScene;
    end;

// Hier wird die Beschriftung gezeichnet =======================================

    GetTransform(D3DTS_WORLD, WorldMatrix);
    GetTransform(D3DTS_PROJECTION, ProjMatrix);
    GetTransform(D3DTS_VIEW,      ViewMatrix);

    D3DXMatrixMultiply(TempMatrix, WorldMatrix, ViewMatrix);
    D3DXMatrixMultiply(TempMatrix, TempMatrix, ProjMatrix);

    WorldPoint.x := NormCube[1].x;
    WorldPoint.y := NormCube[1].y;
    WorldPoint.z := NormCube[1].z;
    D3DXVec3Transform(ScrnPoint, WorldPoint, TempMatrix);

    TxtRect := Rect(Round(ScrnPoint.x), Round(ScrnPoint.y), 0, 0);
    Self.FDXFont.DrawTextA('Hallo', -1, TxtRect, DT_CALCRECT, 0);
    Self.FDXFont.DrawTextA('Hallo', -1, TxtRect, DT_LEFT, $FFFFFFFF);

    SetRenderState(D3DRS_ALPHATESTENABLE, 1);
    SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

// =============================================================================

    // Zeige Resultate auf dem Bildschirm
    Present(nil,nil,0,nil);
  end;
end;

procedure TRendererD3D.StartScene(Handle: HWND);
begin
  D3DInit(Handle);
  D3DInitScene;
  D3DRender;
end;

procedure TRendererD3D.StopScene;
begin
  D3DKillScene;
  D3DShutdown;
end;

procedure TRendererD3D.MyIdleHandler (Sender: TObject; var Done: Boolean);
begin
  if Animate then D3DRender;
  Done:=false;
end;

end.
Leider funktioniert das ganze nicht so, wie ich mir das vorstelle. Der Schirftzug "Hallo" irgendowo im oberen linken Fenster-Bereich gezeichnet ...und nicht etwa auf der Würfelkante.

Dabei müsste ich doch die Bildschirmkoordinaten rausbekommen, wenn ich

Wordlmatrix * Viewmatrix * Projektionmatrix

rechne, oder?

Gruß,
oXmoX
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:04 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz