Registriert seit: 13. Aug 2003
Ort: Berlin
95 Beiträge
|
Merkwürdiges Problem mit Z-Buffer...
24. Okt 2005, 12: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;
|