Registriert seit: 13. Aug 2003
Ort: Berlin
95 Beiträge
|
Merkwürdiges Problem mit Z-Buffer...
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 ![Angel](images/smilies/azzangel.gif) !
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 ![Grübelnd...](images/smilies/gruebel.gif) ...
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;
|