PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Direct3D: Z-Buffer funktioniert nicht.


Robbson
2006-03-31, 06:50:20
Toll... habe jetzt den ganzen Abend und die ganze Nacht damit verbracht herauszubekommen, wieso ich in meinem
Direct3D Programm den Z-Buffer nicht aktivieren kann... vergebens. Habe alles so konfiguriert, wie es überall nachzulesen ist (SDK Doku, D3D Bücher, Internetlinks), verschiedene Bufferformate ausprobiert und sonstwas... nix... kein Z-Buffer. Keine Funktion murrt herum bzw. bringt eine Fehlermeldung, aber in meiner Szene überlappen sich alle später gerenderten Dreiecke, obwohl sie räumlich ganz hinten liegen. :confused:

Die Beispielapplikationen von MS bringen mir nix, die haben meist nur ein einziges Objekt und außerdem nutzen die Applikationen 1000 Hilfsklassen in Subfiles, sodaß man kaum noch durchblickt, wo 'mal welches Flag gesetzt wurde. :mad:

Es ist alles (zusätzliche) drin, was drin sein muß, damit D3D einen Z-Buffer erzeugt:
In den D3DPRESENT_PARAMETERS die Parameter
EnableAutoDepthStencil = TRUE;
AutoDepthStencilFormat = D3DFMT_D16; (oder ein anderes supportetes Format)
gesetzt.

Später dann der State gesetzt: SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

Und vor dem Rendern natürlich noch den Z-Buffer löschen:
Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

Doch nix zu sehen vom "Herrn Z-Buffer"... Egal ob im Window mode oder fullscreen.

Da Games auf meinem Rechner ja auch keine Probleme mit dem Z-Buffer haben, ist mir der "Bug" absolut rätselhaft.
Vielleicht ein Treiberbug für Developer... oder nvidia hat ein eigenes Z-Buffer Format-Flag... keine Ahnung.
:(

Robbson.

Neomi
2006-03-31, 12:32:07
Setz mal explizit auch die anderen States, D3DRS_ZWRITEENABLE und D3DRS_ZFUNC. Deren Defaultwerte sollten zwar dem entsprechen, was gewünscht wird, aber sicher ist sicher.

Wenn das nichts bringt, dann kannst du mit ZFUNC prüfen, wo genau der Fehler zu suchen ist...
D3DCMP_NEVER: wenn hier noch etwas gezeichnet wird, existiert der ZBuffer wohl nicht.
D3DCMP_GREATER: wenn hier in umgekehrter Zeichenreihenfolge die Dreiecke sichtbar sind, hast du ein Problem mit der Projektionsmatrix.

Robbson
2006-03-31, 18:10:17
Setz mal explizit auch die anderen States, D3DRS_ZWRITEENABLE und D3DRS_ZFUNC. Deren Defaultwerte sollten zwar dem entsprechen, was gewünscht wird, aber sicher ist sicher.

Wenn das nichts bringt, dann kannst du mit ZFUNC prüfen, wo genau der Fehler zu suchen ist...
D3DCMP_NEVER: wenn hier noch etwas gezeichnet wird, existiert der ZBuffer wohl nicht.
D3DCMP_GREATER: wenn hier in umgekehrter Zeichenreihenfolge die Dreiecke sichtbar sind, hast du ein Problem mit der Projektionsmatrix.

Danke erstmal für die Hilfe. Hatte bereits zuvor D3DRS_ZWRITEENABLE ausprobiert und und mit den Vergleichsvarianten von D3DRS_ZFUNC herumgespielt, was aber keine Änderung brachte. Allerdings habe ich nicht daran gedacht, daß dies auch für Diagnosezwecke dienen kann...

Nun ja, weder bei D3DCMP_NEVER noch bei D3DCMP_GREATER sehe ich irgend etwas... ob das ein gutes Zeichen ist? Bei letzterem hätte ich auch lieber irgend was falsch gerendertes gesehen als garnix. :(
Woran kann das nur liegen...

Grüße,
Robbson.

Coda
2006-03-31, 18:19:34
Kannst du mal Source-Code zeigen, so groß ist das Programm wohl noch nicht oder?

Robbson
2006-03-31, 19:23:35
OK, hier das Wesentliche vom Source-Code... habe nur die ellenlange Funktion zum Erstellen der Vertexbuffer herausgenommen (einmalig bei Programmstart), den ganzen Eingabekram und die vielen Altlasten (auskommentiertes Zeugs).

Die Funktionen sind in der Regel an das erste Microsoft Tutorial angelehnt, also recht übersichtlich denke ich mal.

Na dann, riskiert 'mal 'nen Blick... mir sind alle Ideen zum Problem ausgegangen...

Robbson.


//-----------------------------------------------------------------------
// Robbson's first test application for Direct3D9 based on 1. MS Tutorial
//-----------------------------------------------------------------------
#include <windows.h>
#include <mmsystem.h>
#include <d3dx9.h>

// Funktionsprototypen
VOID Cleanup();

//-----------------------------------------------------------------------------
// Global Direct 3D Types & Variables
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device

// 3D-Koordinaten
struct CUSTOMVERTEX // z.Z. mit 24 Byte für pos, color, u/v
{
FLOAT x, y, z; // The untransformed, 3D position for the vertex
DWORD color; // The vertex color
FLOAT tu, tv; // The texture coordinates
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)


// Datenfeld zum Sichern der Kameraposition und des Blickwinkels (haben wir ja nie gemacht!)
struct cam_type
{
float yaw, pitch, roll; // Winkel der aktuellen Blickrichtung (RAD)

// Richtungsvektoren für alle Achsen, wobei vDir die Blickrichtung ist (häufigste Bewegungsachse)
D3DXVECTOR3 vUp, vDir, vRight;
D3DXVECTOR3 pos; // Koord. des Standpunktes
};
cam_type cam1; // globale Kamera


// NEU: Cube mit zusätzlichen Vertices für weitere UV-Koordinaten
// -> für 2 verschiedene Texturen: (A: 4fach wiederholt an den vertikalen Seiten, B: oben und unten)
// -> auch hier noch mit .5er Koordinaten, damit ganzzahlige Koordinaten für den Mittelpunkt stehen
CUSTOMVERTEX vCube3[]=
{
// Die vorderen 4+2 Eckpunkte (für die erste Kante vorne links 2 zusätzlich, wegen Texturumwicklung)
{-0.5f, 0.5f,-0.5f, 0xffffffff, 0.0f, 0.0f}, // vlo 0
{ 0.5f, 0.5f,-0.5f, 0xffffffff, 1.0f, 0.0f}, // vro 1
{-0.5f,-0.5f,-0.5f, 0xffffffff, 0.0f, 1.0f}, // vlu 2
{ 0.5f,-0.5f,-0.5f, 0xffffffff, 1.0f, 1.0f}, // vru 3
{-0.5f, 0.5f,-0.5f, 0xffffffff, 4.0f, 0.0f}, // vlo 4 nochmal
{-0.5f,-0.5f,-0.5f, 0xffffffff, 4.0f, 1.0f}, // vlu 5 nochmal

// Die hinteren 4 Eckpunkte (in der für den Uhrzeigersinn passenden Reihenfolge)
{ 0.5f, 0.5f, 0.5f, 0xffffffff, 2.0f, 0.0f}, // hro 6
{-0.5f, 0.5f, 0.5f, 0xffffffff, 3.0f, 0.0f}, // hlo 7
{ 0.5f,-0.5f, 0.5f, 0xffffffff, 2.0f, 1.0f}, // hru 8
{-0.5f,-0.5f, 0.5f, 0xffffffff, 3.0f, 1.0f}, // hlu 9

// Die oberen 4 Eckpunkte nochmal einzeln, damit einzelne Floor Textur zuweisbar
{-0.5f, 0.5f,-0.5f, 0xffffffff, 0.0f, 1.0f}, // vlo 10
{ 0.5f, 0.5f,-0.5f, 0xffffffff, 1.0f, 1.0f}, // vro 11
{ 0.5f, 0.5f, 0.5f, 0xffffffff, 1.0f, 0.0f}, // hro 12
{-0.5f, 0.5f, 0.5f, 0xffffffff, 0.0f, 0.0f}, // hlo 13

// Die unteren 4 Eckpunkte nochmal einzeln, damit einzelne Ceiling Textur zuweisbar (gleich mit Floor)
{-0.5f,-0.5f,-0.5f, 0xffffffff, 0.0f, 1.0f}, // vlu 14
{ 0.5f,-0.5f,-0.5f, 0xffffffff, 1.0f, 1.0f}, // vru 15
{ 0.5f,-0.5f, 0.5f, 0xffffffff, 1.0f, 0.0f}, // hru 16
{-0.5f,-0.5f, 0.5f, 0xffffffff, 0.0f, 0.0f} // hlu 17
};

// Index zum neuen Cube3 (Triangle List)
// -> Hier ist darauf zu achten, daß für die obere und untere (sowie linke) Fläche auch die eigenen Vertices
// herangezogen werden (und nicht die von Vorder- und Rückseite), da die Vertices der oberen/unteren
// Seite sonst keine eigene Fläche definieren würden, was also nicht texturierbar ist. (oder doch?)
// ---> Oder zumindest nicht mit einer Flächenfarbe überlagerbar ;-)
// -> Reihenfolge entsprechend Anordnung der Vertices: vorne, rechts, hinten, links, oben, unten
// (könnte eventuell noch optimiert werden, aber Vertexcache von 10 Vertices in der GPU genügt wohl)
WORD iCube3[]={0,1,2,2,1,3, 1,6,3,3,6,8, 6,7,8,8,7,9, 7,4,9,9,4,5, 11,10,12,12,10,13, 14,15,17,17,15,16};


// NEU: Datenstrukur ausschließlich für statische Vertex Buffer (inkl. Index Buffer)
struct StaticVB_type
{
LPDIRECT3DVERTEXBUFFER9 pV;
LPDIRECT3DINDEXBUFFER9 pI;
LPDIRECT3DTEXTURE9 pTex; // Textur für Buffer
IDirect3DStateBlock9 *pTexConfig; // enthält States zur Konfig. der Texturausgabe
int size_v, size_i; // Größe der Buffer (als Vertices bzw. Indices), nicht Byte

// Reine Hilfsvariablen für die Erstellung des Buffers (ansonsten used nicht mehr nötig)
int used_v, used_i; // als Vertices bzw. Indices
};
StaticVB_type staticVB[10]; // Feld für max. 10 VB mit unterschiedlichen Texturen (oder teils derselben)


//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
// Create the D3D object, which is needed to create the D3DDevice.
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )return E_FAIL;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );

d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY; // oder D3DSWAPEFFECT_DISCARD ...
d3dpp.BackBufferFormat = 3DFMT_UNKNOWN; // oder D3DFMT_X8R8G8B8 ...
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // VSync aus
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // oder auch anderes kompatibles


// Create the Direct3D device.
if( FAILED( g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}

// Device state would normally be set here

// DAS allein reicht nicht für die Aktivierung des Z-Buffers!
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); // default


// Turn off D3D lighting, since we are providing our own vertex colors
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );


// Kamera zeigt anfangs in Richtung Z-Achse
cam1.vDir.x=0.0f;
cam1.vDir.y=0.0f;
cam1.vDir.z=1.0f;
cam1.vRight.x=1.0f;
cam1.vRight.y=0.0f;
cam1.vRight.z=0.0f;
cam1.vUp.x=0.0f;
cam1.vUp.y=1.0f;
cam1.vUp.z=0.0f;

// Kamera positionieren und drehen
cam1.pos.x=10.0f;
cam1.pos.y=12.0f;
cam1.pos.z=-10.0f;
cam1.yaw=0.0f;
cam1.pitch=0.0f;
cam1.roll=0.0f;

// Textur laden
//if(FAILED( D3DXCreateTextureFromFile(g_pd3dDevice, "HG_Texture1.bmp", &pTex1) ))return E_FAIL;

return S_OK;
}


//---------------------------------------------------------------------------------
// InitStaticMesh() erzeugt aus der kompletten Map VertexBuffer, denen jeweils eine
// best. Textur zugeordnet ist
//---------------------------------------------------------------------------------
HRESULT InitStaticMesh()
{
// ...
// Anmerkung: Hier weggelassen, zeichnet lediglich ein Array von Quadern, würde aber
// alles unnötig aufblähen
// ...
}


//-----------------------------------------------------------------------------
// Schnelle Inline-Funktion für das Dot-Produkt
inline float xUtil_Punktprodukt(D3DVECTOR *v1, D3DVECTOR *v2)
{
return (v1->x * v2->x + v1->y * v2->y + v1->z * v2->z);
}


//-----------------------------------------------------------------------------
// Name: CalcViewMatrix()
// Desc: Modifizierte Version aus dem Stefan Zerbst Tutorial
// -> ersetzt die anscheinend unbrauchbare D3DXMatrixLookAtLH() Funktion
// -> Erspart mir auch die eigene Berechnung der Richtungsvektoren
// (bei der Drehung) für die Kamera!
//-----------------------------------------------------------------------------
void CalcViewMatrix(D3DMATRIX *matView, cam_type *cam)
{
// Werte nur einmal berechnen!
float fSinYaw = sinf(cam->yaw), fCosYaw = cosf(cam->yaw);
float fSinPitch = sinf(cam->pitch), fCosPitch = cosf(cam->pitch);
float fSinRoll = sinf(cam->roll), fCosRoll = cosf(cam->roll);

// Igitt: Rotation von Hand:
cam->vRight.x = fCosYaw*fCosRoll + fSinYaw*fSinPitch*fSinRoll;
cam->vRight.y = fSinRoll*fCosPitch;
cam->vRight.z = fCosYaw*fSinPitch*fSinRoll - fSinYaw*fCosRoll;

cam->vUp.x = fSinYaw*fSinPitch*fCosRoll - fCosYaw*fSinRoll;
cam->vUp.y = fCosRoll*fCosPitch;
cam->vUp.z = fSinRoll*fSinYaw + fCosRoll*fCosYaw*fSinPitch;

cam->vDir.x = fCosPitch*fSinYaw;
cam->vDir.y = -fSinPitch;
cam->vDir.z = fCosPitch*fCosYaw;

// Erzeuge die View Matrix für Direct3D
matView->_11 = cam->vRight.x;
matView->_21 = cam->vRight.y;
matView->_31 = cam->vRight.z;
matView->_41 = -xUtil_Punktprodukt(&cam->pos, &cam->vRight);
matView->_12 = cam->vUp.x;
matView->_22 = cam->vUp.y;
matView->_32 = cam->vUp.z;
matView->_42 = -xUtil_Punktprodukt(&cam->pos, &cam->vUp);
matView->_13 = cam->vDir.x;
matView->_23 = cam->vDir.y;
matView->_33 = cam->vDir.z;
matView->_43 = -xUtil_Punktprodukt(&cam->pos, &cam->vDir);
matView->_14 = 0.0f;
matView->_24 = 0.0f;
matView->_34 = 0.0f;
matView->_44 = 1.0f;
}


//-----------------------------------------------------------------------------
// Name: SetupMatrices()
// Desc: Sets up the world, view, and projection transform matrices.
//-----------------------------------------------------------------------------
VOID SetupMatrices()
{
// 2. Berechnung der ViewMatrix für die Kamera
D3DXMATRIXA16 mView; // Warum A16 (also 16Byte-aligned) nötig?
CalcViewMatrix(&mView, &cam1);

// 3. Matrix als neue ViewMatrix setzen
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mView);

// For the projection matrix, we set up a perspective transform
D3DXMATRIXA16 matProj;
float aspectratio=1.333333f; // Für 4:3
D3DXMatrixPerspectiveFovLH( &matProj, /*D3DX_PI/4*/ 1.1f, aspectratio, 0.0f, 1000.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}


//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
if( NULL == g_pd3dDevice )return;

// Clear the backbuffer to a black color & ZBuffer
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// Setup the world, view, and projection matrices
SetupMatrices();

// NEU: Rendern der vorberechneten statischen Buffer
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

for(int i=0;i<10;i++)
{
if(staticVB[i].pV) // Kontrolle, ob Buffer mit Daten befüllt
{
g_pd3dDevice->SetStreamSource(0, staticVB[i].pV, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(staticVB[i].pI);
g_pd3dDevice->SetTexture(0,staticVB[i].pTex);

// momentan erstmal so konfigurieren
if(i==0)g_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);

// Auch diese Info brauche ich noch: Anzahl der zu rendernden Primitive
g_pd3dDevice->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST, 0, 0, staticVB[i].used_i, 0, staticVB[i].used_i/3);
}
}


// End the scene
g_pd3dDevice->EndScene();
}

// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}


//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}


//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
// Register the window class
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"D3D Tutorial", NULL };

RegisterClassEx( &wc );

// Create the application's window
HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 01: CreateDevice",
WS_OVERLAPPEDWINDOW, 0, 0, 1024, 768,
GetDesktopWindow(), NULL, wc.hInstance, NULL );

if(SUCCEEDED(InitD3D(hWnd))) // Initialize Direct3D
{
InitStaticMesh(); // statische VertexBuffer erzeugen

// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );

// Enter the message loop (inkl. Renderaufruf)
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) // Peek, damit kein Warten!!
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render();
}
}

// Ende
UnregisterClass( "D3D Tutorial", wc.hInstance );
return 0;
}


//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
// Feld mit statischen (indizierten) Vertex Buffern löschen
for(int i=0;i<10;i++)
{
if(staticVB[i].pV)staticVB[i].pV->Release();
if(staticVB[i].pI)staticVB[i].pI->Release();
if(staticVB[i].pTex)staticVB[i].pTex->Release();
if(staticVB[i].pTexConfig)staticVB[i].pTexConfig->Release();
}

if( g_pd3dDevice != NULL)g_pd3dDevice->Release();
if( g_pD3D != NULL)g_pD3D->Release();
}

Neomi
2006-03-31, 21:32:42
Du hast die Near Clipping Plane (beim Generieren der Projektionsmatrix) auf 0.0 stehen, das kann nicht funktionieren. Setz die mal auf einen Wert größer 0 (bei einer Far Clipping Plane von 1000.0 bietet sich 0.1 an). So klein wie nötig, so groß wie möglich. Der ZBuffer hat logarithmische Werte, seine Genauigkeit hängt vom Faktor zwischen Near und Far Clipping Plane ab. Und der ist bei dir quasi unendlich.

PS: bei der Diagnose mit D3DCMP_GREATER hatte ich vergessen, daß der ZBuffer dafür mit 0.0 statt 1.0 gelöscht werden sollte. Etwas größeres als 1.0 kann es ja nicht geben.

PS/2: du solltest lieber die schönen Möglichkeiten nutzen, die dir D3D9 bietet. VertexDeclarations sind in jeder Hinsicht viel besser als FVFs. Und Shader sind zwar am Anfang etwas mehr Aufwand, du wirst aber danach nie wieder Fixed Function nutzen wollen. ;)

Expandable
2006-03-31, 22:57:25
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);

*Murks* Danke. Jetzt weiß ich wieder, warum ich OpenGL bevorzuge. Dieser völlig überflüssige kryptische Schmarrn den D3D da verwendet... *kotz* -- Sorry für OT

Aber eine Near Clipping Plane von 0.0 kann wirklich nicht funktieren (Division durch 0!). Ich verwende meist 1.0. Bei 0.1 habe ich oft z-fighting issues, trotz 24 bit z-Buffer!

Coda
2006-03-31, 23:03:03
Diese States gibts genauso unter OpenGL auch.

glEnable(GL_DEPTH_TEST)
glDepthMask(TRUE);
glDepthFunc(GL_LEQUAL);

Was daran jetzt viel besser oder schlechter sein soll entzieht sich meiner Auffassungsgabe. Ja es ist kürzer, aber man muss sich dafür auch mehr Eintrittspunkte merken.

Robbson
2006-03-31, 23:11:53
Du hast die Near Clipping Plane (beim Generieren der Projektionsmatrix) auf 0.0 stehen, das kann nicht funktionieren. Setz die mal auf einen Wert größer 0 (bei einer Far Clipping Plane von 1000.0 bietet sich 0.1 an). So klein wie nötig, so groß wie möglich. Der ZBuffer hat logarithmische Werte, seine Genauigkeit hängt vom Faktor zwischen Near und Far Clipping Plane ab. Und der ist bei dir quasi unendlich.

PS: bei der Diagnose mit D3DCMP_GREATER hatte ich vergessen, daß der ZBuffer dafür mit 0.0 statt 1.0 gelöscht werden sollte. Etwas größeres als 1.0 kann es ja nicht geben.

PS/2: du solltest lieber die schönen Möglichkeiten nutzen, die dir D3D9 bietet. VertexDeclarations sind in jeder Hinsicht viel besser als FVFs. Und Shader sind zwar am Anfang etwas mehr Aufwand, du wirst aber danach nie wieder Fixed Function nutzen wollen. ;)

BOAH WAHNSINNNN!!!!!!!!! Du lagst goldrichtig !! ;D ;D Wie kann ich Dir nur danken? :massa:
Da wäre ich wohl von selbst nie drauf gekommen, daß es an der Clipping Plane liegen könnte... die habe ich immer ignoriert... Am Anfang setzte ich den Wert runter, weil es mir gefiel, wie die Polygonkanten einem in's Auge gestochen haben... wirkt viel realistischer. :-)

Ansonsten ja, mir ist schon klar, daß D3D9 einige Möglichkeiten mehr bietet, aber ich möchte erstmal die klassischen Dinge abgrasen, Stück für Stück wie ich sie brauche, bevor es dann an die Pixel und Vertex Shader geht. Von denen würden mich ja vor allem die in Assembler geschriebenen Reizen nach all den Hochsprachenjahren... ;-)
Der erste Shader den ich für ganz wichtig erachte, ist eine vernünftige Beleuchtung. Die alte Methode mit der Unterteilung selbst von geraden Flächen, damit das Vertex Lightning besser aussieht, sind wirklich Steinzeit.

Momentan geht's mir aber noch viel um die Basics, wie Graphen-Management und statische/dynamische Buffer.
Frage mich gerade, wie die Entwickler damals bei RedFaction das wohl gemacht haben. Da die Umgebung komplett zerstörbar war, konnten ja praktisch keine statischen Vertex-Buffer zum Einsatz kommen...

Oh mann, ich kann's immer noch nicht fassen... jetzt macht die Weiterentwicklung ja wieder Spaß *gg.

Und diese Vertex Declarations.... ooops... "endlich" mal wieder 'nen Begriff mit dem ich nix anfangen kann... momentan jedenfalls. Wo ist denn der Vorteil gegenüber FVF? Ist das ein D3D9 only Feature?

Grüße,
Robbson.

Coda
2006-03-31, 23:13:05
Frage mich gerade, wie die Entwickler damals bei RedFaction das wohl gemacht haben. Da die Umgebung komplett zerstörbar war, konnten ja praktisch keine statischen Vertex-Buffer zum Einsatz kommen...
Einen BSP sollte man eh über einen dynamischen Vertexbuffer rendern, sonst hätte man viel zu kleine Batches (sichtbare Nodes markieren und alle Geometry darin mit gleichem Renderstates in einen Batch packen).

Und nein dynamische Vertexbuffer sind nicht so viel langsamer.

Und diese Vertex Declarations.... ooops... "endlich" mal wieder 'nen Begriff mit dem ich nix anfangen kann... momentan jedenfalls. Wo ist denn der Vorteil gegenüber FVF? Ist das ein D3D9 only Feature?
Nein das gabs schon unter D3D8. Der Vorteil ist dass die Reihenfolge der Daten beliebig ist (wichtig für Shader mit mehren Streams, etc.).

FVF gibts eigentlich nur noch um ältere Hardware zu unterstützen. Würde ich nicht mehr benützen.

Neomi
2006-03-31, 23:48:43
BOAH WAHNSINNNN!!!!!!!!! Du lagst goldrichtig !! ;D ;D Wie kann ich Dir nur danken? :massa:

Keine Ursache! :)

Bei den älteren Dingen (FVFs und Fixed Function Pipeline) solltest du dich dann aber darauf beschränken, sie auszubrobieren, bis sie funktionieren. Ernsthaft verwenden würde ich diese Dinge nicht mehr, vor allem da du ja so auf Effizienz stehst. ;) Ein Fixed Function Setup muß in vielen Einzelaufrufen gesetzt werden und zur Laufzeit validiert werden. Ein Pixelshader wird vorab validiert und benötigt nur einen Aufruf, um aktiv zu sein.

VertexDeclarations sind die modernere und deutlich flexiblere Art, zu bestimmen, welche Elemente in einem Vertex vorliegen. Anstatt nur zu sagen, welche Elemente vorkommen (in einer Reihenfolge, die von Direct3D starr vorgegeben wird), sagst du, welche Elemente mit welchem Typ, in welchem Stream und an welcher Position dort zu finden sind. Hier ein Beispiel, das deinem FVF entspricht:

const D3DVERTEXELEMENT9 vdPosColTex [] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END ()
};

Die Texturkoordinaten z.B. sind in Stream 0, Offset 16 Bytes, bestehen aus zwei Floats (die Declmethod danach ist für High Order Surfaces relevant, wird aber wohl kaum wirklich genutzt) und gehen als Texturkoordinaten im Set 0 (Usage Index, der letzte Eintrag) an den Vertexshader. So ein Array wird an CreateVertexDeclaration übergeben und man bekommt ein Handle zurück. VertexDeclarations funktionieren, wenn sie passend schlicht gehalten werden, auch mit alter Hardware. Da du ja schon weißt, wie man FVFs nutzt, kannst du ja jetzt zu den Declarations übergehen. ;)

Auf jeden Fall dranbleiben, es lohnt sich. Und wenn irgendwo Fragen aufkommen, immer her damit.

Robbson
2006-03-31, 23:53:19
Einen BSP sollte man eh über einen dynamischen Vertexbuffer rendern, sonst hätte man viel zu kleine Batches (sichtbare Nodes markieren und alle Geometry darin mit gleichem Renderstates in einen Batch packen).
Und nein dynamische Vertexbuffer sind nicht so viel langsamer.


Hallo Coda! Nun bei dem BSP Baum sind vielleicht größere Räume mit je einer Textur als statische Buffer machbar. Jedenfalls habe ich auch eine dynamische Version bei mir vor der "Idee" mit den echt statischen Buffern probiert, die Speed ist ok, aber das Umschaufeln und der Transport über den Bus kosten dann halt doch schon etwas Speed. Für meine Leveldaten ist momentan noch kein BSP Baum nötig bzw. der spezielle Aufbau macht diesen momentan überflüssig. ;-) Nutzen denn moderne 3D Engines überhaupt noch statische Buffer? So schön es ist die Dinger im VRam abzulegen... sortieren von vorne nach hinten oder ähnlich kann man sie pro Frame so jedenfalls nicht mehr.


Nein das gabs schon unter D3D8. Der Vorteil ist dass die Reihenfolge der Daten beliebig ist (wichtig für Shader mit mehren Streams, etc.).
FVF gibts eigentlich nur noch um ältere Hardware zu unterstützen. Würde ich nicht mehr benützen.

Hmm... muß ich mir mal anschauen... sehe so aus dem Bauch heraus keinen Sinn, die Vertexdaten, Texturkoord., etc. beliebig zu mischen... ich mags da eher aufgeräumter. :-)

Robbson.

Robbson
2006-04-01, 00:01:24
@Neomi

Ok, Neomi, die Erklärung schau' ich mir morgen nochmal an... habe seit 48 Stunden nicht geschlafen... viel geht nicht mehr hinein in das Hirn. :rolleyes:
Habe mir nur gerade noch mit letzter Kraft so gedacht: Ein Vertex Shader läuft ja die ganze Zeit auf der GPU... d.h. der könnte dann ja problemlos auf die statischen Vertex Buffer im VRam ohne Speedverlust zugreifen oder?
Dann könnte man diesen vom Programm aus kurze Botschaften mitteilen, wie er sich zu verhalten hat... Oder kann der Shader nur eine statische Aufgabe in einem Loop lösen und nicht auf Ereignisse reagieren?

Oh mann... ich habe ja noch nichtmal 'ne Beleuchtung in meiner Szene... das kommt aber daher, daß ich einen best. Look nachahmen will, der keine Beleuchtung braucht *gg. Jedenfalls momentan noch nicht. Jetzt muß ich erstmal sehen wie ich das alte Datenformat mit der Map vom Amiga in meine 3D Map bekomme....

Robbson.

Coda
2006-04-01, 00:01:56
Hallo Coda! Nun bei dem BSP Baum sind vielleicht größere Räume mit je einer Textur als statische Buffer machbar.
Ich glaube kaum dass das einen Vorteil bringt. Bei so kleinen (<1000 Polygone) Batches ist das nicht sinnvoll, glaub mir.

Nutzen denn moderne 3D Engines überhaupt noch statische Buffer?
Fast ausschließlich. Bei UT2004 & Half-Life 2 wird nur die grobe Geometry (BSP) wohl dynamisch gerendert, die ganzen feindetailierten Meshes werden ins VRAM geladen.

So schön es ist die Dinger im VRam abzulegen... sortieren von vorne nach hinten oder ähnlich kann man sie pro Frame so jedenfalls nicht mehr.
Grob sortieren nach Meshes reicht meistens.

Expandable
2006-04-01, 00:38:00
Diese States gibts genauso unter OpenGL auch.

glEnable(GL_DEPTH_TEST)
glDepthMask(TRUE);
glDepthFunc(GL_LEQUAL);

Was daran jetzt viel besser oder schlechter sein soll entzieht sich meiner Auffassungsgabe. Ja es ist kürzer, aber man muss sich dafür auch mehr Eintrittspunkte merken.

Äh... ja, genau das meinte ich ja. Das IST wesentlich besser zu lesen. Finde ich persönlich zumindest. Also wenn ich das mit dem hier vergleiche:

g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);

Man spart es sich, immer ein Objekt (g_pd3dDevice) mitrumzuschleppen. Man muss nicht explizit sagen, dass man die State Machine ändert will (SetRenderState) und dann noch sagen, WAS man ändern will (D3DRS_ZENABLE z.B.). Geht gleich in einer Funktion. Ingesamt ist also
glEnable(GL_DEPTH_TEST) wesentlich leichter zu lesen und zu erfassen als
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE) - ODER?

Was Du jetzt mit Eintrittspunkten meinst, weiß ich nicht genau. Meinst Du Funktionsnamen? Das ist ja wohl völlig egal, ob ich mir 100 verschiedene Funktionsnamen merke oder 100 verschiedene Konstanten für das erste Argument von SetRenderState()...

Außerdem finde ich die Präfixe (D3DRS_*, D3DCMP_*, D3DZB_*) unschön und schwieriger zu schreiben als "gl" bzw. "GL_*", da man bei der 3 von der Shift-Taste runter muss. Da vertippe ich mich (mein persönliches Problem) öfters mal. GL_ schreibt sich einfach schneller.

Lange Rede kurzer Sinn und es ist ja eh nur meine ganz persönliche Meinung: OpenGL hat eine wesentlich schönere, kürzere, übersichtlichere und leichter erfassbare und verständlichere Syntax. Zumindest jetzt in diesem Beispiel. Wie Texturen, Shader o.Ä. in D3D funktionieren, weiß ich nicht.

Coda
2006-04-01, 00:58:07
Lange Rede kurzer Sinn und es ist ja eh nur meine ganz persönliche Meinung: OpenGL hat eine wesentlich schönere, kürzere, übersichtlichere und leichter erfassbare und verständlichere Syntax. Zumindest jetzt in diesem Beispiel. Wie Texturen, Shader o.Ä. in D3D funktionieren, weiß ich nicht.
Wenn man sich an sowas aufhält hat man bei anderen viel komplexeren Dingen eh schon verloren. Ich bitte dich, das ist Syntax und das Ganze gehört eh abstrahiert.

Nein wirklich, ich halte mich mit solchen Lapalien gar nicht erst auf, es geht um die Funktionalität der API, schließlich kann man mit einem relative dünnen Layer eh Direct3D und OpenGL gleichzeitig erschlagen. Ich kann Glaubenskriege um sowas echt nicht nachvollziehen.

Außerdem kann man über schön und nicht schön herrlich streiten ohne groß was zu bezwecken. Im Endeffekt weiß man bei D3D wenigstens gleich um was für eine Sache es sich dreht wenn man das Objekt vorne dran hat.

Robbson
2006-04-01, 01:36:45
Also um OpenGL habe ich diesmal einen großen Bogen gemacht. Denn erstens kenne ich das noch aus dem Studium und ich wollte mich endlich einmal mit Direct3D beschäftigen... zumal die API im Gamesbereich dominiert.

Und zweitens.... jetzt kommen wir 'mal zum Thema Übersichtlichkeit: Das GL Extension Management ist der absolute Garaus. Um erweiterte Funktionen einer Grafikkarte zu nutzen, muß in OpenGL jede Extension eines jeden Grafikkartenherstellers zunächst erfaßt werden. Das Chaos will ich mir jedenfalls nicht antun, allein nVidia definiert einige 1000 Extensions. :down:

Ich erinnere nur an die 5 Renderpfade in Doom3... ein paar für nVidia, ATI und dann noch 'nen Generic.

Wenn ich hingegen z.B. eine BumpMap in Direct3D einrichte, dann wird sie wohl auf den meisten Geräten laufen, die das Feature unterstützen, ohne für jeden eine Extrawurst zu braten.

Robbson.

Expandable
2006-04-01, 11:40:49
@Coda: War ja auch nur meine persönliche Meinung.

@Robbson: Es ist ja wohl egal, ob ich in OpenGL nach Extensions oder in D3D nach Caps abfrage. Jedenfalls kann man BumpMapping in OpenGL auch ohne Extensions realisieren ;o) Und verschiedene Renderpfade gibt es in D3D auch - einen für D3D9, einen für D3D8, einen für D3D7 (s. HL2 z.B.). Also für mich persönlich überwiegen die Vorteile der Extensions gegenüber deren Nachteilen. Allerdings programmiere ich auch nur zu meiner persönlichen Belustigung, kann sein, dass das bei kommerziellen Anwendungen anders aussieht.

Coda
2006-04-01, 12:19:09
Bei einer großen Applikation sind die Vor- und Nachteile der APIs ungefähr ausgewogen und zudem sollte man diese sowieso abstrahieren. Es ist in einem objektorientierten Programm für die Erweiterbarkeit irgendwie nicht so schön wenn man überall Direct3D oder OpenGL verstreut hat.

Die meisten Spieleentwickler unterstützen deshalb Direct3D, weil der Treibersupport dafür einfach besser ist (GMA900 lässt grüßen :()

Demirug
2006-04-01, 12:56:30
Also was den lessbarkeit und das rapid development angeht bin ich ein absoluter Fan von Managed Direct3D.

device.RenderState.ZBufferEnable = true;
device.RenderState.ZBufferWriteEnable = true;
device.RenderState.ZBufferFunction = Compare.LessEqual;

Das sieht jetzt zwar nach mehr Code aus aber dank Intellisence muss ich davon ja kaum etwas tippen.

Expandable
2006-04-01, 13:20:21
Demirug: Ja, irgendwie schade, dass IntelliSense in C++ so mies ist. Ich habe mir auch mal MDX angeschaut, im Vergleich zu Unmanged D3D ist das wirklich sehr gut. Bin auch grad am überlegen, ob ich mein OpenGL-Projekt mal nach C#/MDX portieren soll - mal sehen...

Robbson
2006-04-01, 16:29:56
Gibt's bei diesem managed 3D eigentlich irgendwelche Vorteile (performancemäßig), außer daß der Code schöner aussehen kann?

Robbson.

Coda
2006-04-01, 16:52:31
Ist eher langsamer.

Robbson
2006-04-01, 17:04:55
Eben. Hat doch was mit NET zu tun und so 'nen Bytecode wird ja wohl unmöglich performanter sein. Deswegen mach' ich auch 'nen großen Bogen um den Speicherfresser Eclipse, das ist in Java geschrieben und trotz der angepaßten GUI Klasse träge, wie 'ne Schnecke vor'm Einschlafen.

Robbson.

Demirug
2006-04-01, 17:28:20
Eben. Hat doch was mit NET zu tun und so 'nen Bytecode wird ja wohl unmöglich performanter sein. Deswegen mach' ich auch 'nen großen Bogen um den Speicherfresser Eclipse, das ist in Java geschrieben und trotz der angepaßten GUI Klasse träge, wie 'ne Schnecke vor'm Einschlafen.

Robbson.

Das hat doch nichts mit dem Bytecode zu tun aber da Managed DirectX ein zusätzlicher Layer über der unmanaged Version ist kosten die Aufrufe ein paar zusätzliche Anweisungen mehr.

Es gibt im SDK sogar Beispiele bei dennen die managed Version schneller als die umanaged Version ist.

Robbson
2006-04-01, 22:46:01
Das hat doch nichts mit dem Bytecode zu tun aber da Managed DirectX ein zusätzlicher Layer über der unmanaged Version ist kosten die Aufrufe ein paar zusätzliche Anweisungen mehr.

Es gibt im SDK sogar Beispiele bei dennen die managed Version schneller als die umanaged Version ist.

Nun, wenn es nix mit NET zu tun hat, wozu dann managed DirectX ? Wird es einfacher? Effizienter? Oder wie nu?

Robbson.

Demirug
2006-04-01, 22:55:23
Nun, wenn es nix mit NET zu tun hat, wozu dann managed DirectX ? Wird es einfacher? Effizienter? Oder wie nu?

Robbson.

Ich meinte der Performances unterschied kommt nicht vom Bytecode. Ein Managed DirectX ist notwendig damit man DirectX mit einer mananged Sprache verwenden kann.

Godmode
2006-04-01, 23:25:11
Ich meinte der Performances unterschied kommt nicht vom Bytecode. Ein Managed DirectX ist notwendig damit man DirectX mit einer mananged Sprache verwenden kann.

Es sind aber hoffentlich keine Wrapper?

Demirug
2006-04-01, 23:32:52
Es sind aber hoffentlich keine Wrapper?

Was sollte es den anderes sein?

SgtTynis
2006-04-02, 14:58:48
Hat doch was mit NET zu tun und so 'nen Bytecode wird ja wohl unmöglich performanter sein.

Soweit mir bekannt ist fuehrt .NET keinen Bytecode aus, sondern kompiliert zur Laufzeit (nach eigenen Erfahrungen Methodenweise) in Maschinensprache der Zielplattform.

Expandable
2006-04-02, 15:09:58
Soweit mir bekannt ist fuehrt .NET keinen Bytecode aus, sondern kompiliert zur Laufzeit (nach eigenen Erfahrungen Methodenweise) in Maschinensprache der Zielplattform.

Ja und war nicht eines der tollen Features von .NET, dass der compilierte Code gespeichert wird? Also auf jedem PC wird 1 mal compiliert und danach ist die Programmausführung etwas schneller, weil eben gleich "nativer" Code ausgeführt wird?

SgtTynis
2006-04-02, 15:29:27
Naja, jedenfalls ist auffaellig das jede .NET Anwendung beim zweiten mal starten deutlich schneller in die Gaenge kommt - mehr als durch konventionelles Caching erklaerbar waere. Nach einem Betriebssystemneustart wird das gecachte allerdings wieder verworfen. Ein permanentes Kompilieren fuer die Zielplattform ist auch moeglich, allerdings nur fuer Assemblies im GAC und auch nur fuer so lange wie nichts an der Plattform veraendert wird. Ansonsten greift der Fallback auf die temporaeres Compilat bis Neustart Variante.
Was den Wrapper um D3D angeht, hab ich mal gelesen das managed D3D mittlerweile auch kein dumpfer COM-Wrapper mehr ist; wie das nun genau realisiert ist, entziehts sich allerdings meiner Kenntnis.

Demirug
2006-04-02, 15:45:57
Was den Wrapper um D3D angeht, hab ich mal gelesen das managed D3D mittlerweile auch kein dumpfer COM-Wrapper mehr ist; wie das nun genau realisiert ist, entziehts sich allerdings meiner Kenntnis.

Es war nie ein dumpfer COM-Wrapper vorallem weil das D3D COM sowieso aus custom Interfaces besteht die mit dem automatischen Wrappern gar nicht richtig abgedeckt werden können.

Der Managed D3D Wrapper ist eine mixed .Net Assembly die man mit dem C++ Compiler erstellen kann. Damit wird es möglich unmanaged und managed Code zu mischen. Ich mache das gerade für D3D10.

Godmode
2006-04-04, 12:15:13
Was sollte es den anderes sein?

Also werden hier dann unmanaged Funktionen aufgerufen? Ich dachte das soll recht langsam sein wenn man von Managed Unmanaged aufruft?

Demirug
2006-04-04, 12:35:04
Also werden hier dann unmanaged Funktionen aufgerufen? Ich dachte das soll recht langsam sein wenn man von Managed Unmanaged aufruft?

Wenn man den Wrapper automatisch bauen lässt was mit DirectX aber sowieso nicht funktionieren würde. Baut man den Wrapper von Hand mit managed C++ (.Net 1.1) bzw C++/CLR (.Net 2.0) entfällt dieser Call Overhead fast völlig. Im Vergleich zu dem was die Runtime und der Treiber dann an Taktzyklen braucht spielt es keine Rolle mehr. Problematisch sind dann eher die Fälle wo es um den syntaktischen Zucker geht.

Robbson
2006-04-07, 05:15:41
Naja, jedenfalls ist auffaellig das jede .NET Anwendung beim zweiten mal starten deutlich schneller in die Gaenge kommt - mehr als durch konventionelles Caching erklaerbar waere. Nach einem Betriebssystemneustart wird das gecachte allerdings wieder verworfen.

Was macht denn das für 'nen Sinn? Reicht doch wenn's einmal kompiliert ist... schließlich wechsel ich doch nicht mit jedem Neustart die zugrundeliegende Systemarchitektur. :|
Naja, ich seh' schon, außerhalb von Webanwendungen habe ich den Sinn von .NET noch nicht so ganz geschnallt, muß ich bei Gelegenheit mal nachholen... :rolleyes:

Robbson.

Robbson
2006-04-07, 05:20:42
Soweit mir bekannt ist fuehrt .NET keinen Bytecode aus, sondern kompiliert zur Laufzeit (nach eigenen Erfahrungen Methodenweise) in Maschinensprache der Zielplattform.

Ja aber Bytecode ist es sowieso (als Basis)... auch Java kann Passagen per JIT-Compiler in Echtzeit kompilieren.
Die Programme werde ja wohl kaum als Sourcecode 'rumliegen.

Aber die ganze Aufregung um DirectX und .NET ist mir sowieso rätselhaft... wo doch Microsoft auf der eigenen Hompage rät, für performante Anwendungen unmanaged Code einzusetzen. Bleiben halt noch die anderen Anwendungsfälle... wie von .NET aus Direct3D nutzen... bspw. beim CCC von ATI, was ja niemand mag.

Ansonsten würde jedes gestartete Game beim ersten Mal immer "etwas zäher" zu spielen sein. :biggrin:

Robbson.