Denkproblem mit IDirect3DDevice9
-
Also ich bin nicht 100% sicher ob ich dich richtig verstehen, aber naja.
Meine Meinung: vergiss 3 & 4.
Was du mit "forward-declaration einer Hauptklasse" meinst weiss ich nicht ganz.
Ebenso was du unter einer "globalen Klasse" verstehst. "Global" klingt schonmal nicht gut.Normalerweise hat man ein Objekt welches das D3D Device "besitzt". Die Klasse heisst dann oft wieder "Device" oder auch mal "Engine" oder sowas.
Soweit, so gut.
Wenn du Klassen machen möchtest die "sich selbst zeichnen" können, haben diese üblicherweise eine Render() Funktion.
Dieser Render() Funktion könntest du z.B. direkt das D3D Device mitgeben.
Oder du gibst einen Zeiger auf deine "Engine" Klasse mit, und ermöglichst den "zeichenbaren" Klassen irgendwie Zugriff auf das "darin enthaltene" D3D Device (z.B. per friend).
Du kannst es auch weiter abstrahieren, indem du eine "RenderContext" Klasse machst, die alles enthält was ein "zeichenbares" Ding braucht um "sich zu zeichnen". Und diesen "RenderContext" dann an die Render() Funktion übergeben. Das kann vorteilhaft sein, wenn man den "zeichenbaren" Dingern nicht vollen Zugriff auf die Interna der "Engine" Klasse geben will. (Diese Variante nutze ich im Moment in einem Projekt)
Man kann das ganze allerdings auch umdrehen, und alles Zeichnen in der "Engine" Klasse erledigen. Die "zeichenbaren" Objekte enthalten dann lediglich Funktionen die quasi eine "Beschreibung" abliefern was denn nun gezeichnet werden soll. Ist allerdings nach meiner Erfahrung deutlich mehr Aufwand.
-
hustbaer schrieb:
Dieser Render() Funktion könntest du z.B. direkt das D3D Device mitgeben.
Ok, werde ich machen.
hustbaer schrieb:
Oder du gibst einen Zeiger auf deine "Engine" Klasse mit, und ermöglichst den "zeichenbaren" Klassen irgendwie Zugriff auf das "darin enthaltene" D3D Device (z.B. per friend).
Ich möchte nicht so viele Freunde haben
hustbaer schrieb:
Du kannst es auch weiter abstrahieren, indem du eine "RenderContext" Klasse machst, die alles enthält was ein "zeichenbares" Ding braucht um "sich zu zeichnen". Und diesen "RenderContext" dann an die Render() Funktion übergeben. Das kann vorteilhaft sein, wenn man den "zeichenbaren" Dingern nicht vollen Zugriff auf die Interna der "Engine" Klasse geben will. (Diese Variante nutze ich im Moment in einem Projekt)
Was meinst du damit? Ist das nicht genau die passende Beschreibung auf die Device Klasse? Diese benötigt ja alles, um rendern zu können.
-
Die Frage ist: Brauchst du wirklich eine Device Klasse? Was würde die tun? Die würde am Ende doch sowieso einfach nur alle Methoden vom Device wrappen. Ich würde da lieber auf höherer Ebene ansetzen und darunter einfach direkt mit Direct3D arbeiten.
-
Was ist so schlecht an nem Singleton? Ich verstehe das mit dem Resourcenfressend-sein ehrlich gesagt nicht so ganz.
-
TravisG schrieb:
Was ist so schlecht an nem Singleton?
http://www.google.at/search?sourceid=chrome&ie=UTF-8&q=sinlgeton+evil
-
@dot:
Ich verwende die Device Klasse um Resourcen (meine eigenen Klassen, welche ihrerseits D3D Resourcen verwalten) zu tracken.Wenn ich das Device resetten möchte, habe ich so eine Liste von Resource-Objekten denen ich sagen kann dass das Device jetzt resettet wird. Dazu muss ich ja z.B. Texturen die nicht im Managed-Pool sind freigeben, und danach wieder anlegen. (Da ich Render-Texturen verwende komme ich um Default-Pool Texturen nicht herum.) Das Wieder-Anlegen der D3D Resourcen geht genau so, meine Device-Klasse klappert alle meine Resource-Objekte durch, und diese erzeugen dann "ihre" D3D Resourcen neu (sofern es nicht Managed-Pool Resourcen waren, die gar nicht freigegeben wurden).
Weiters kann ich so das Device komplett zerstören und neu anlegen, z.B. wenn der User das Fenster auf einen anderen Monitor verschiebt. Dazu müssen dann sämtliche D3D Resourcen freigegeben und neu angelegt werden. Danach müssen dann die Texturen "neu befüllt" werden, was ebenso meine Resource-Klassen erledigen.
z.B. weiss die "StaticTexture" Klasse wo "ihr" Inhalt herkommt - sie hält einen Zeiger auf eine "ImageFactory", die wiederum das Bild laden/erzeugen kann.
Bzw. Render-Texturen werden als "dirty" markiert, damit sie beim nächsten mal Rendern aktualisiert werden.Wie ich das ohne eine "Device" Klasse machen sollte, weiss ich nicht. Der Name war auch nur ein Beispiel (hab ich auch dazugeschrieben), man könnte die Klasse genau so gut anders nennen.
Ich verwende die Device-Klasse *in* diesem Layer auch *nicht* um die gesamte D3D-Funktionalität zu kapseln, das würde wirklich keinen Sinn machen.
Allerdings muss der nächste Layer darüber keinen direkten Zugriff auf die D3D Objekte mehr haben. (Im Moment ist das noch nicht ganz so, aber naja)
Viel wichtiger aber: der Layer darüber muss sich ums Device Resetten nicht kümmern. Ebenso nicht darum was alles zu geschehen hat, wenn das Device zerstört und neu angelegt wird. Er ruft einfachdevice->MoveToBestAdapter(rect)
auf, und um den Rest kümmert sich der "Device" Layer.----
Aber mal ganz abgesehen davon: ich sagte bereits der Name "Device" ist nur ein Beispiel. Irgendwem muss das D3D-Device ja gehören. Ich sehe zumindest keine Möglichkeit (zumindest nichts was ich als sinnvoll erachten würde), wie man ohne eine Klasse auskommt, der das D3D Device gehört.
Wie würdest du es denn sonst machen?
-
TravisG schrieb:
Was ist so schlecht an nem Singleton? Ich verstehe das mit dem Resourcenfressend-sein ehrlich gesagt nicht so ganz.
Ja resourcenfressend verstehen ich auch nicht. Schlecht ist es aber ganz sicher.
Was machst du nämlich wenn du mal zwei-oder-mehr Devices brauchst statt einem?
Was machst du wenn zwei-oder-mehr unabhängige Programmteile die selbe Library verwenden möchten, aber eben unabhängig voneinander, evtl. in verschiedenen Threads, aber eben im selben Prozess?Mit Singletons betrittst du da eine Welt des Schmerzes.
-
Mit Ressourcenfressend meinte ich, dass jeder Instanzaufruf Performance kostet, aber egal.
Ich gebe jetzt einfach an jede render Funktion eine Device Referenz.
Aber mich plagt auch gerade ein ganz anderes Problem:
Mein Dreieck will einfach nicht farbig werden und bleibt immer nur schwarz
Hier ist der Code:#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE) struct CUSTOMVERTEX{ float x, y, z; DWORD color; }; bool Init() { CUSTOMVERTEX vertices[] = { {25.0f, -30.0f, 0.0f, D3DCOLOR_XRGB(0xff, 0xff, 0xff)}, {0.0f, 30.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 0)}, {-25.0f, -30.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 0)} }; d3dd->CreateVertexBuffer(sizeof(vertices), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, 0); void* pvoid; v_buffer->Lock(0, 0, &pvoid, 0); memcpy(pvoid, vertices, sizeof(vertices)); v_buffer->Unlock(); return true; } void Draw() { d3dd->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0xaa, 0xaa, 0xaa), 1.0f, 0); d3dd->BeginScene(); d3dd->SetFVF(CUSTOMFVF); D3DXMATRIX matIdentity; D3DXMatrixIdentity(&matIdentity); d3dd->SetTransform(D3DTS_WORLD, &matIdentity); D3DXMATRIX matView; D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3 (0.0f, 0.0f, 10.0f), &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), &D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); d3dd->SetTransform(D3DTS_VIEW, &matView); D3DXMATRIX matProjection; D3DXMatrixOrthoLH(&matProjection,static_cast<float>(width), static_cast<float>(height),-1.0f,100.0f); d3dd->SetTransform(D3DTS_PROJECTION, &matProjection); d3dd->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); d3dd->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1); d3dd->EndScene(); d3dd->Present(0, 0, 0, 0); }
Den Code habe ich hierher
Ohne diese Vektor-Transformierung wird mein Dreieck übrignes eingefärbt.
-
Ich habe den Fehler gefunden, ich musste das lightning ausstellen. Allerdings bleiben mir da noch eine Frage. Wenn ich diesen Code benutze
void Draw() { d3dd->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); d3dd->BeginScene(); d3dd->SetFVF(CUSTOMFVF); D3DXMATRIX matWorld; D3DXMatrixIdentity(&matWorld); d3dd->SetTransform(D3DTS_WORLD, &matWorld); D3DXMATRIX matView; D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3 (0.0f, 0.0f, 1.0f), &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), &D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); d3dd->SetTransform(D3DTS_VIEW, &matView); D3DXMATRIX matProjection; D3DXMatrixOrthoOffCenterLH(&matProjection, 0.0f, width, 0.0f, height, 0.0f, 1.0f); d3dd->SetTransform(D3DTS_PROJECTION, &matProjection); d3dd->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); d3dd->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1); d3dd->EndScene(); d3dd->Present(0, 0, 0, 0); }
müssen alle x-Koordinaten im negativen Bereich sein, damit man sie sehen kann. Die y-Koordinaten müssen aber positiv sein. Wie kann ich das ändern, damit auch die x-Koordinaten im positiven Bereich sein müssen?
-
Du meinst wohl die z-Koordinaten!? Nun, überleg dir einfach mal wo deine Kamera ist und wo sie hinschaut...
@hustbaer: Natürlich ist das immer eine Frage auf welcher Ebene du wie abstrahieren willst und dein Ansatz ist sicherlich eine gute Lösung. Ich setze meine Abstraktionsschicht normalerweise erst etwas höher an. Mein Ressourcenmanagement läuft über RAII, darum brauch ich keine Managerklasse die sich ums Aufräumen kümmert. Device Loss ist natürlich ein Argument in D3D9, da ich kaum noch D3D9 verwende bin ich da in der glücklichen Lage mich nicht wirklich drum kümmern zu müssen. Aber in dem Fall kommt man dann wohl kaum umhin eine zentrale Stelle zu haben die alle Objekte kennt und dann ein OnDeviceReset aufruft. Eine solche Stelle hat man normalerweise aber so oder so, nämlich jenes Objekt das sich ums Rendern und Presenten kümmert. Ich habe dazu üblicherweise ein Renderer Objekt das alle Fenster/Displays verwaltet. Für mich funktioniert das bisher ganz gut, dein Design ist allerdings natürlich auf einer anderen Ebene viel allgemeiner gehalten.
-
Nein ich meine die X-Koordinaten. Wenn ich diese Vektoren benutze
CUSTOMVERTEX vertices[] = { { -100.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), }, { -25.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), }, { -50.0f, 50.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), }, };
sehe ich die Eckpunkte im Fenster an den stellen 100|0 25|0 50|50
Aber der zweite Teil deiner Antwort hats gelöst, statt auf der z-Position 1.0f zu liegen muss die Kamera au der z-Position -1.0f liegen. Ich habe es vorher nur mit RH statt LH versucht, und dabei kam dann eben nichts bei raus.
-
Achso, sry hab deine Projektionsmatrix übersehen. Naja, ist doch klar, du verwendest D3DXMatrixOrthoOffCenterLH() und spezifizierst dass du den Bereich von x=0..width bzw y=0..height sehen willst. Nachdem deine Kamera von (0 0 1) aus entgegen die z-Achse blickt ist das genau der Bereich von x=0..-width und y=0..height!?
-
Ich habe noch ein Problem mit den Fullscreen Modus, ich habe jetzt schon ca. 10 verschiedene Beispiele ausprobiert, aber jedes mal hängt sich bei mir
CreateDevice()
auf. Die Funktion gibt auch keinen Wert mehr zurück und der Task Manager sagt mir, dass das Programm nicht mehr reagiert. Hier mal ein Minimalbeispiel, bei dem genau das passiert:WNDCLASSEX wc; ZeroMemory(&wc, sizeof(WNDCLASSEX)); wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = StaticWndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); // wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszClassName = L"WindowClass"; RegisterClassEx(&wc); hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program", WS_EX_TOPMOST | WS_POPUP, 0, 0, width, height, NULL, NULL, hInstance, NULL); d3d = Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = FALSE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hWnd; d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; d3dpp.BackBufferWidth = width; d3dpp.BackBufferHeight = height; if (FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3dd))) { return false; }
Ich kann das ganze noch mit etlichen Funktionen etc. erweitern, aber das Problem bleibt immer dasselbe.
Der Fenstermodus funktioniert aber einwandfrei.
-
Debug Runtime aktivieren und Fehlermeldungen prüfen?
-
Ich hab den Debugger an, und dadurch auch rausgefunden, worans liegt. Aber wenn ich CreateDevice aufrufe muss auch der Debugger dran glauben, weil wirklich alles hängen bleibt und ich nurnoch alles gewaltsam über den Task Manager beenden kann.
-
Warum eigentlich D3DCREATE_SOFTWARE_VERTEXPROCESSING, hast du nur Intel Chipset Grafik oder so!? Ich bin mir ziemlich sicher dass sich der Debugger nicht aufhängt. Das Problem mit Fullscreen debuggen ist aber dass, wenn die Ausführung unterbrochen wird, dann dein fullscreen Window über dem Debugger liegt. Was du dann siehst ist zwar das darunterliegende Fenster (wegen Device loss) allerdings kannst du nicht mit ihm interagieren weil dein fullscreen Window im Weg ist (wenn du genau schaust kannst du sicher den Rahmen sehen). Debuggen von fullscreen Anwendungen geht nur gescheit mit einem zweiten Bildschirm.
-
dot schrieb:
Warum eigentlich D3DCREATE_SOFTWARE_VERTEXPROCESSING, hast du nur Intel Chipset Grafik oder so!?
Ist wie gesagt nur ein Minimalbeispiel. Ich wollte eben alle möglichen Fehlerquellen reduzieren.
Gibt es auch irgendeine möglichkeit gescheit ohne zweiten Bildschirm zu debuggen?
-
DirektIx schrieb:
Gibt es auch irgendeine möglichkeit gescheit ohne zweiten Bildschirm zu debuggen?
Jop, den Fenstermodus :p
-
Das bringt mir ja viel, weil da ja alles so klappt wie es soll
Was mich aber auch wundert ist, dass dieses Problem im Internet anscheinend gar nciht existiert und ich der einzige Idiot bin, bei dem ständig das Programm abkratzt.
-
Kannst ja mal versuchen über ne log Datei oder so rauszufinden wo es ca. abkackt...