Einzelnen Beitrag anzeigen

Benutzerbild von md_mse
md_mse

Registriert seit: 13. Aug 2003
Ort: Berlin
95 Beiträge
 
#1

Merkwürdiges Problem mit Z-Buffer...

  Alt 24. Okt 2005, 11:05
Hallo Delphianer.

Ich bin am rum experimentieren mit DirectX (9) und dem Erstellen von 3D Landschaften. DirectX ist übrigens auch ein relativ neues Thema für mich !
Zur Zeit kämpfe ich mit einem sehr merkwürdigem Problem des Z-Buffers(?).
Obwohl er aktiviert ist, auch vor dem Rendern eines Frames gelöscht wird, kommt es dazu, dass beim rotieren der Kamera der Hintergrund der Landschaft plötzlich vor dem Vordergrund gezeichnet wird ...
Dies tritt auch auf, wenn ich die Welt per Matrix-Befehl drehe.
Anbei ein Screenshot des Problems, und das Programm.

Hier nochmal einige Auszüge aus dem Quellcode:
Initialisierung von D3D:
Delphi-Quellcode:
  D3DInit := Direct3DCreate9(D3D_SDK_VERSION);
  if (D3DInit = nil) then
    FatalError(0, '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;

    PresentationInterval := D3DPRESENT_INTERVAL_IMMEDIATE;

    // Initialisieren des Backbuffers
    Windowed := True;
    if not Windowed then
    begin
      // Vollbild
      BackBufferWidth := 800;
      BackBufferHeight := 600;
      BackBufferFormat := D3DFind16BitMode;
      BackBufferCount := 1; // 1 Backbuffer
    end else
    begin
      // Fenster
      hr := D3DInit.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, d3ddm);
      if Failed(hr) then FatalError(hr, 'Fehler beim Ermitteln des Dislaymodes');
      BackBufferFormat := d3ddm.Format;
    end;
  end;

  // Hardware T&L?
  hr := D3DInit.GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, FD3dDevCaps);
  if Failed(hr) then
    FatalError(hr, 'Fehler beim Abfragen der DevCaps');
  FHwVertexProcess := FD3dDevCaps.DevCaps and D3DDEVCAPS_HWTRANSFORMANDLIGHT <> 0;

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

  //Erstellen des D3D-Device
  hr := D3DInit.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Handle, vp, @d3dpp, D3DRenderer);
Erstellen der Landschaft aus einer Heightmap:
Delphi-Quellcode:
var
  Bitmap: TBitmap;
  ix, iy, Index: Integer;
  WorldHeight, WorldWidth: Integer;
  AvailWorldHeight, AvailWorldWidth: Integer;
  VertexList: array of TD3DLVertex;
  IndexList: array of Word;
  bBuffer: Pointer;

  idm: ID3DXMesh;
begin
  Bitmap := TBitmap.Create;
  Bitmap.LoadFromFile(FileName);

  try
    with FTargetRenderer do
    begin
      WorldWidth := Bitmap.Width;
      WorldHeight := Bitmap.Height;
      //
      // Maps, die größer sind als 100x100 würden mehr als die gültigen 2^16
      // Vertices besitzen, also muss demnach die Präzision verändert werden!
      //
      if (WorldWidth * WorldHeight > 21845{(2^16)-1 / 3}) then
        FMapPrecision := Round(Ceil((WorldWidth * WorldHeight) / 21845));

      AvailWorldWidth := WorldWidth div FMapPrecision;
      AvailWorldHeight := WorldHeight div FMapPrecision;

      FVerticeCount := AvailWorldWidth * AvailWorldHeight;

      // Buffer erstellen
      CreateVertexBuffer(FVerticeCount * SizeOf(TD3DLVertex), D3DUSAGE_WRITEONLY or D3DUSAGE_DYNAMIC,
        D3DFVF_LVertexFormat, D3DPOOL_DEFAULT, FVertexBuffer, nil);
      CreateIndexBuffer(65536 * SizeOf(Word), D3DUSAGE_WRITEONLY,
        D3DFMT_INDEX16, D3DPOOL_DEFAULT, FIndexBuffer, nil);

      // Sicherstellen dass später keine falschen Werte berechnet werden...
      FBoundingBoxMin := D3DXVector3(MaxSingle, MaxSingle, MaxSingle);
      FBoundingBoxMax := D3DXVector3(MinSingle, MinSingle, MinSingle);
      
      //
      // Vertices mit Höheninformationen aus HeightMap erstellen...
      //
      Index := 0;
      SetLength(VertexList, FVerticeCount);
      SetLength(IndexList, 65536);

      for ix := 0 to AvailWorldWidth - 1 do
      begin
        for iy := 0 to AvailWorldHeight - 1 do
        begin
          FMap[ix, iy] := Bitmap.Canvas.Pixels[ix, iy] mod 256;
          VertexList[Index] := D3DLVertex(ix * FMapExpansionFactor / AvailWorldWidth, FMap[ix, iy] *
                                  FMapHeightExpFactor / 255, iy * FMapExpansionFactor / AvailWorldHeight,
                                  D3DCOLOR_XRGB(200, 100, 50), 0, 0);
          VertexList[Index].tu := ix / AvailWorldWidth;
          VertexList[Index].tv := iy / AvailWorldHeight;

          // Bounding box erstellen...
          FBoundingBoxMin := MinVertex(FBoundingBoxMin, VertexList[Index]);
          FBoundingBoxMax := MaxVertex(FBoundingBoxMax, VertexList[Index]);

          Inc(Index);
        end;
      end;

      //
      // Vertices mit Höheninformationen miteinander verbinden, damit Polygone
      // entstehen...
      //
      Index := 0;
      for ix := 0 to AvailWorldWidth - 2 do
      begin
        for iy := 0 to AvailWorldHeight - 2 do
        begin
          IndexList[Index] := ix + (iy * AvailWorldWidth);
          IndexList[Index + 1] := ix + 1 + (iy * AvailWorldWidth);
          IndexList[Index + 2] := ix + ((iy + 1) * AvailWorldWidth);

          IndexList[Index + 3] := ix + 1 + (iy * AvailWorldWidth);
          IndexList[Index + 4] := ix + 1 + ((iy + 1) * AvailWorldWidth);
          IndexList[Index + 5] := ix + ((iy + 1) * AvailWorldWidth);
          Inc(Index, 6);
        end;
      end;
      FIndexCount := Index;

      // Vertices in Buffer kopieren
      //if Failed(FVertexBuffer.Lock(0, 0, bBuffer, 0)) then
      // raise EFatalException.Create('Buffer lock failed in GenerateTarrainFromHeightMap');
      Assert(not Failed(FVertexBuffer.Lock(0, 0, bBuffer, 0)), 'Vertex-Buffer lock failed');
      Move(VertexList[0], bBuffer^, SizeOf(TD3DLVertex) * Length(VertexList));
      FVertexBuffer.Unlock;

      // Indices in Buffer kopieren
      Assert(not Failed(FIndexBuffer.Lock(0, 0, bBuffer, 0)), 'Index-Buffer lock failed');
      Move(IndexList[0], bBuffer^, SizeOf(Word) * Length(IndexList));
      FIndexBuffer.Unlock;
        
    end;

    // Textur laden...
    D3DXCreateTextureFromFile(FTargetRenderer, PChar(TextureBaseDir + 'NoTex.dds'), FTexture);

  finally
    Bitmap.Free;
    SetLength(VertexList, 0);
    SetLength(IndexList, 0);
  end;
Rendern der Szene/Landschaft:
Delphi-Quellcode:
var
  ViewMatrix: TD3DXMatrix;
  i: Integer;
  n: Integer; //Our translation matrix

  R: TRect;
begin
  Rotation := Rotation + IncRotationBy;

  if Assigned(D3DRenderer) then
  with D3DRenderer do
  begin
    Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0);

    R := Bounds(1, 1, 0, 0);
    dxFont.DrawTextA(nil, PChar('FPS: ' + IntToStr(FPS)), -1, @R, DT_NOCLIP, D3DCOLOR_XRGB(255, 255, 255));

    if Succeeded(BeginScene) then
    begin
      D3DXMatrixLookAtLH(ViewMatrix, D3DXVector3(Sin(PiBy180 * Rotation) * HeightDistance * 1.5,
                                               HeightDistance,
                                               Cos(PiBy180 * Rotation) * HeightDistance * 1.5),
                                   D3DXVector3(0.0, 0.0, 0.0),
                                   D3DXVector3(0.0, 1.0, 0.0));
      SetTransform(D3DTS_VIEW, ViewMatrix);

      SetTexture(0, FTexture);

      // Mit D3DTSS_COLLORP wird festgelegt, wie die Farbe jedes einzelnen Pixels
      // verarbeitet wird. D3DTOP_SELECTARG1 verweist auf D3DTSS_COLORARG1
      SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
      // Mit D3DTSS_COLORARG1 wird festgelegt, daß die Farbe nur von der Textur
      // genommen wird und von nichts anderem.
      SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
      // Wir benutzen kein Alpha blending, also schalten wir es ab.
      SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
      // MipMapping
      SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
      SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
      SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

      SetFVF(D3DFVF_LVertexFormat);
      SetStreamSource(0, FVertexBuffer, 0, SizeOf(TD3DLVertex));
      SetIndices(FIndexBuffer);
      DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, FVerticeCount, 0, FIndexCount div 3);

      EndScene;
    end;

    // Zeige Resultate auf dem Bildschirm
    Present(nil, nil, 0, nil);
    Inc(RenderedFramesCount);
  end;
Miniaturansicht angehängter Grafiken
terrainerror_m_160.png  
Angehängte Dateien
Dateityp: zip terrainerror_809.zip (930,2 KB, 16x aufgerufen)
  Mit Zitat antworten Zitat