JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=4aafd4a8aa1989fae23faa8c1f8caa36Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

2D mit Direct3D
Gehe zu Seite 1, 2  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> DirectX, OpenGL
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
Florian
Super JLI'ler


Alter: 36
Anmeldedatum: 20.06.2003
Beiträge: 302

Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 12:49    Titel: 2D mit Direct3D Antworten mit Zitat

Hallo wieder mal
In letzter Zeit versuche ich eine Sprite Klasse zu coden. Dazu wollte ich das ganze mit Direct3D realisieren, also das Sprite besteht aus 4 Vertize (Rechteck) auf diesem wird dann die Texture draufgeben.
Bis jetzt habe ich das mit dem Vertexformat XYZRHW gemacht. Hat auch wunderbar funktioniert und die Vertize habe ich global angelegt und mit DrawPrimitivUP() dargestellt also ohne VertexBuffer. Nun möchte ich diese Vertize in einen VertexBufferr speichern und dann mit DrawPrimitiv darstellen. Das Problem ist nun beim Bewegen des Sprites. Da das verwendete XYZRHW die Bildschirmcoordinaten enthält müsste ich bei jedem Bildwechsel die Vertize die sich in dem VertexBuffer befinden ändern. Und dies geschiet ja mittels Lock & Unlock. Das wird sich wohl auf die Performance auswirken.
Wie koennte man dies anderst loesen oder ist der Verluste doch nicht so groß ?

Danke schon mal Smile
_________________
Theorie ist, wenn man alles weiss und nichts funktioniert.
Praxis ist, wenn alles funktioniert und keiner weiss warum.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden MSN Messenger
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 13:20    Titel: Antworten mit Zitat

Naja, wenn du die Vertexe nciht per hand berechnen willst, musste halt von RHW wegkommen und alles mit Matrizen machen. Im Prinzip sind die raelativ einfach aufgebaut, wenn man weiß wie. Dann kannste einfach die Weltmatrix benutezn, um das Sprite zu drehn, oder verschieben.

Alelrdings ist dann die Frage was irgendwann schneller geht, schleißlich hat eine Matrix16 floats.Evtl. Ist es schneller Matrix so zu lassen wie sie ist, und die Vertexe neu zu berechnen und direkt aus dem Speicher zu rendern. Vertexbuffer machen keinen Sinn, wenn bei jedem durchlauf sie neu erstellt werden.
Entweder änderst du die Matrix, oder kopüierst jedesmal die Vertexdaten auf die GraKa ob nun per DrawPrimitiveUP oder Vertexbuffer, soltle nicht soo einen unterschied machen. Musst halt austesten, ob es schneller ist die Matrix zu setzen oder die paar Vertexe. (du kannst auch einen festen Indexbuffer bneutzen, der ändert sich aj nie, und mit DrawIndexedPrimitiveUP(so, oder so ähnlihc) direkt aus dem Speicher zeichen).
Wobei 2 Dreiecke mitsamt Texturkoordinaten wahrshcienlcih doch größer sind als eine Matrix.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 14:34    Titel: Antworten mit Zitat

Ich mach das meistens so, dass ich für jeden Sprite ein und denselben VB verwende. Dieser beinhaltet 4 Vertices, das sind bei einem Trianglestrip 2 Dreiecke. Die Koordination aller Objekte speichere ich in diversen Matrizen(im Grunde ja nur 4x 4d-Vektoren). Nach Lust und Laune kann man das sehr schön optimieren und verschlüsseln; es gibt verschiedene Algorithmen die eine Matrix in 4 unsigned longs komprimieren können, muss man halt etwas werkeln. Gibt da sehr schöne Ideen. Ich setze vorm Render diesen VB und für jedes Objekt ändere ich dann nur Matrix und Texture. Meine Engine hat da noch einige Optionen. Bei kleinen Spielen ist das Komprimieren jedoch unnötig.
Natürlich funktioniert so eine Arbeitsweise nur bei kleinen Bollboards oder allgemein 2d-Objekte, Sprites halt; nicht jedoch bei 3d-Meshs oder ähnlcihem. Muss man eben gucken, was da am besten für einen passt...

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 15:19    Titel: Antworten mit Zitat

Wieso komprimieren? ich denke mal nicht, das der Hauptspeicher sooo knapp ist, außerdem kann man die doch gar nicht komprimiert an die Grafikkrate übermitteln, oder? Und bei der Komprimierunggeht bestimmt ein wenig Genauigkeit verloren, obwohl das noch am allerwenigsten Probleme machen sollte.

Bei mir hat jedes Sprite einen eignene Vertexbuffer. Dies war leider nötig, da man ja ein wenig die Texturkoordinaten manipulieren muss, damit jeder Pixel 1 zu 1 auf den Bildschirm kommt.
Beim Rendern berechne ich aus den Renderkoordinaten die Matrix und setze die dann.

Das sieht dann ungefähr so aus:
CPP:
void D3DSprite::Init(LPDIRECT3DDEVICE9 lpDevice, std::string Dateiname, DWORD ColorKey, bool Colorkeying)
{
   Vertex *Vertices=NULL;
   //wenn das objekt schon geladen wurde, erst wieder freigebne und neu laden
   CleanUp();

   m_lpDevice=lpDevice;
   m_lpTexture=LoadBMP(Dateiname, &m_XSize, &m_YSize, ColorKey, Colorkeying);
   //wenn die Textur keine bmp ist kann vielleihct als tga geladen werden
   if(NULL==m_lpTexture)
      m_lpTexture=LoadTGA(Dateiname, &m_XSize, &m_YSize);
      
   if(NULL==m_lpTexture)
      cLog::GetInstance() << LOGE("Textur konnte nicht geladen werden!");


   const float fTexX=0.5f/m_XSize;
   const float fTexY=0.5f/m_YSize;

   m_lpDevice->CreateVertexBuffer(sizeof(Vertex)*4, 0, D3DFVF_XYZ | D3DFVF_TEX1, D3DPOOL_DEFAULT, &m_lpVertexBuffer, NULL);
   m_lpVertexBuffer->Lock(0, 0, reinterpret_cast<void**>(&Vertices), D3DLOCK_DISCARD);

   Vertices[0].x=0;
   Vertices[0].y=0;
   Vertices[0].z=0.5;
   Vertices[0].u=0+fTexX;
   Vertices[0].v=0+fTexY;
   //Vertices[0].Colour=0x00ff0000;
   Vertices[1].x=1;
   Vertices[1].y=0;
   Vertices[1].z=0.5;
   Vertices[1].u=1+fTexX;
   Vertices[1].v=0+fTexY;
   //Vertices[1].Colour=0x00ffffff;
   Vertices[2].x=0;
   Vertices[2].y=1;
   Vertices[2].z=0.5;
   Vertices[2].u=0+fTexX;
   Vertices[2].v=1+fTexY;
   //Vertices[2].Colour=0x000000ff;
   Vertices[3].x=1;
   Vertices[3].y=1;
   Vertices[3].z=0.5;
   Vertices[3].u=1+fTexX;
   Vertices[3].v=1+fTexY;
   //Vertices[3].Colour=0x000000ff;

   m_lpVertexBuffer->Unlock();


   
   m_lpDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
   m_lpDevice->SetRenderState(D3DRS_LIGHTING, false);
   m_lpDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
   m_lpDevice->SetTransform(D3DTS_VIEW, &MatrixOrthogonalView(1024, 768).D3DMatrix);
   m_lpDevice->SetTransform(D3DTS_PROJECTION, &MatrixOrthogonalProjektion(1024, 768).D3DMatrix);
   m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
   m_lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
   m_lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

   
}





void D3DSprite::Render(float XPos, float YPos)
{
   
   if(1==m_XScale && 1==m_YScale)
   {
      m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
      m_lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
   }
   else
   {
      m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
      m_lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
   }

   //nur absolut notwendige Dinge setzen, den falls adnere sprites gerendert wrden, verändert sich die Textur
   m_lpDevice->SetTransform(D3DTS_WORLD, &cMatrix(MatrixScalation(static_cast<float>(m_XSize*m_XScale), static_cast<float>(m_YSize*m_YScale))*MatrixTranslation(XPos, YPos)).D3DMatrix);//Identittsmatrix
   m_lpDevice->SetTexture(0, m_lpTexture);
   m_lpDevice->SetStreamSource(0, m_lpVertexBuffer, 0, sizeof(Vertex));
   m_lpDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   //m_lpDevice->SetStreamSource(0, NULL, 0, sizeof(Vertex));
}


Die Filter hab ich beim rendern in Origianlgröße rausgenommen, da ich dne Eindruck hatte, es wurde dann ein wenig verschwommen (also gefiltert). Gesetzt werdne müssen die leider jedesmal, da man ja keine Ahnung hat, ob das Sprite davor sie geändert hat oder nicht.
Naja, wenn jemand noch optimierungsideen hat, wäre ich froh drüber Wink
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 15:36    Titel: Antworten mit Zitat

Jonathan_Klein hat Folgendes geschrieben:
Wieso komprimieren? ich denke mal nicht, das der Hauptspeicher sooo knapp ist, außerdem kann man die doch gar nicht komprimiert an die Grafikkrate übermitteln, oder? Und bei der Komprimierunggeht bestimmt ein wenig Genauigkeit verloren, obwohl das noch am allerwenigsten Probleme machen sollte.

komprimieren, weil ich für jedes Objekt eine Matrix und eine Textur hab. Ich programmiere von Natur aus unter minimalen Umständen, dass ich gegebenenfalls sogar auf einem Win95 mit 32MB RAM auskommen könnte. Meine Engine überprüft das vorher. Angewöhnt hab ich mir das dadurch, dass früher, als ich noch auf der Schule war und dafür Projekte machen musste, diese auch auf den alten, verschrotteten, lahmen PCs da laufen sollten. Und der Dekomprimierungs-Algo ist ziemlich schnell, daher kann der Grafikkarte schnell eine richtige Matrix übergeben werden. Früher hab ich das noch selber gemacht, also ich hatte das alles getestet und da kam schon einiges an Vorteil heraus... Naja, Meinungssache. Ist halt so ne Macke von mir, alles bis aufs kleinste optimieren zu müssen Razz Und zur Genauigkeit: nun ja, ich hab das so gemacht, dass mir das für meine Verhältnisse genügt hat.

Jonathan_Klein hat Folgendes geschrieben:
Bei mir hat jedes Sprite einen eignene Vertexbuffer. Dies war leider nötig, da man ja ein wenig die Texturkoordinaten manipulieren muss, damit jeder Pixel 1 zu 1 auf den Bildschirm kommt.

ich mach das durch einen VB und ändere dann nur die Skalierungswerte der Objekte. Ist zwar auch net so genau, aber schnell und effizient. Für Spezialfälle (wenn welche vorkommen) nehm ichs aber trotzdem so ähnlich wie du.

Jonathan_Klein hat Folgendes geschrieben:
Naja, wenn jemand noch optimierungsideen hat, wäre ich froh drüber Wink

Wieso lädst du erst die Bitmap und wenn das schiefläuft den TGA? Könntest du das net vorher am Namen überprüfen? Naja, auch egal, da isser wieder, mein Optimierungszwang... Smile

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 16:29    Titel: Antworten mit Zitat

Ich würde generell nur einen Vertexbuffer für alle Sprites verwenden, da alleine das Binden der VBs sonst Overhead bedeuten dürfte - ist zumindest unter OpenGL so. Ich meine einmal in irgendeinem Paper gelesen zu haben, dass so kleine VBs auch von der Grafikkarte nicht sonderlich effektiv gemanaged werden können und das Ganze deshalb dann eher noch mit Performanceverlusten verbunden ist. Schlüsselwort 'static' macht sich in diesem Zusammenhang übrigens sehr schön, bevor du noch anfängst hier irgendwie mit Pointern rumzuhantieren. ;) Wie gesagt, alles eher Erfahrungswerte, allerdings dürftest du bei einem 2D-Spielchen auf einer halbwegs modernen Karte eh keine sonderlichen Performanceprobleme durch übermäßige Geometrie bekommen. Ich render sogar öfters einfach hardcore runter, indem ich die Geometrie einfach Vertex für Vertex in jedem Frame an die Grafikkarte schicke und hab auf meiner antiqierten Hardware selten Performance-Probleme.

Übrigens: Die Pluralform von Vertex ist weder Vertize noch Vertexe sondern Vertices, eure Verunstaltungen tun einem ja in den Augen weh. ;)

Edit:
Jonathan_Klein hat Folgendes geschrieben:
CPP:
void D3DSprite::Render(float XPos, float YPos)
{
   
   if(1==m_XScale && 1==m_YScale)
   {
      m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
      m_lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
   }
   else
   {
      m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
      m_lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
   }

   //nur absolut notwendige Dinge setzen, den falls adnere sprites gerendert wrden, verändert sich die Textur
   m_lpDevice->SetTransform(D3DTS_WORLD, &cMatrix(MatrixScalation(static_cast<float>(m_XSize*m_XScale), static_cast<float>(m_YSize*m_YScale))*MatrixTranslation(XPos, YPos)).D3DMatrix);//Identittsmatrix
   m_lpDevice->SetTexture(0, m_lpTexture);
   m_lpDevice->SetStreamSource(0, m_lpVertexBuffer, 0, sizeof(Vertex));
   m_lpDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   //m_lpDevice->SetStreamSource(0, NULL, 0, sizeof(Vertex));
}


Die Filter hab ich beim rendern in Origianlgröße rausgenommen, da ich dne Eindruck hatte, es wurde dann ein wenig verschwommen (also gefiltert). Gesetzt werdne müssen die leider jedesmal, da man ja keine Ahnung hat, ob das Sprite davor sie geändert hat oder nicht.
Naja, wenn jemand noch optimierungsideen hat, wäre ich froh drüber ;-)

Ohne mich jetzt zuweit aus dem Fenster lehnen zuwollen - ich kann nur von OpenGL her berichten, glaube aber kaum, dass es sich bei D3D mit den elementaren Dingen sehr anders verhält - das sieht verdammt lahm aus. ;)

Alleine das Setzen irgendwelcher States sollte man soweit wie möglich minimieren, du setzt bei jedem Sprite den Verkleinerungs- bzw. Vergrößerungsfilter, was absolut überflüssig ist, nach Texturen sollte sowieso sortiert werden - lol, ich packe extra immer soviel wie möglich Sprites auf eine Textur, um die langsamen Switches zu sparen ;) - 'SetStreamSource' entspricht sowie ich es auffasse dem Binden von VBOs in OpenGL, d.h. auch vermeidbar und zu guter Letzt auch noch ein Rendercall in jedem Sprite - autsch. Ich würde mir an deiner Stelle unbedingt ein gescheites Management-Sortier-System für meine Sprites einfallen lassen, sowas wie ein stark vereinfachten Scenegraph, damit du beispielsweise Sprites, die die selbe Textur verwenden hintereinander ohne zwischenzeitlichen Switch rendern kannst. Dann natürlich aus nur einem Vertexbuffer, es reicht doch, wenn du jedem Sprite lediglich ein paar Indices für den "globalen" Vertexbuffer mitgibst. ;) An den Rendercalls wirst du leider sicher nicht viel machen können, bzw. ich hab keine Idee, da die Sprites sich in ihrer Translierung/Skalierung/Rotation ja auch relativ zu einander verhalten können sollen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Florian
Super JLI'ler


Alter: 36
Anmeldedatum: 20.06.2003
Beiträge: 302

Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 17:59    Titel: Antworten mit Zitat

Bin jetzt mal auf diesen Artikel gestoßen
http://www.gamedev.net/reference/articles/article1972.asp
In diesem Artikel werden 2 verschiedene Arten erklärt wie man eine Sprite Klasse erstellen kann.

In der 1 Art wird mit dem Vertexformat xyzrhw gearbeitet und bei jedem Zeichnen wird mittels Lock & Unlock die sich im VertexBuffer befindlichen Vertice geändert.

In der 2 Art wird die meines erachtens bessere Sprite Klasse beschrieben. Denn hier werden nicht die Vertices im VertexBuffer geändert sondern nur die jeweiligen Transformations Matrizen gesetzt. Jedoch muss in diesem Fall ein andere Vertexformat verwendet werden XYZ und ein andere Projektionsmatrix gesetzt werden.(orthographic projection matrix)

Nun zu meinem Problem wie kann ich eine solche Projektion Matrix ohne D3DX erstellen? Habe schon gegoogelt aber leider kein Erfolg?

Kann mir da einer Weiterhelfen Smile thx
_________________
Theorie ist, wenn man alles weiss und nichts funktioniert.
Praxis ist, wenn alles funktioniert und keiner weiss warum.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden MSN Messenger
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 18:24    Titel: Antworten mit Zitat

Naja, eine Matrix ist nichts weiter als eine 2D-Repräsentation von Daten, daher kann man sie schön als 2D-Array auffassen. Wenn du nicht die D3DX-Funktionen, sondern eigene Matrixfunktionen verwenden willst, musst du nix weiter machen, als die eigentliche Matrix für D3D in eine 'D3DMatrix' überführen und diese dem Device übergeben, dafür ist 'SetTransform' zuständig. ;)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Florian
Super JLI'ler


Alter: 36
Anmeldedatum: 20.06.2003
Beiträge: 302

Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 18:30    Titel: Antworten mit Zitat

Thx Greven für die Erklärung
Aber wie kann ich nun diese Orthogonale Matrix erstellen die ich dort übergeben sollte.
Bisher habe ich nur Rotation Matrix usw erstellt.
Wie im Tutorial von Patrick http://old.germangamedev.de/index.php?site=article&id=5 sehr gut beschrieben ist.
Aber wie sieht nun der Aufbau einer Orthogonalen Matrix aus?
_________________
Theorie ist, wenn man alles weiss und nichts funktioniert.
Praxis ist, wenn alles funktioniert und keiner weiss warum.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden MSN Messenger
phlip
Mini JLI'ler



Anmeldedatum: 27.08.2005
Beiträge: 39

Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 18:49    Titel: Antworten mit Zitat

Bin auch gerade dabei eine 2D Sprite Klasse zu erstellen.
Ich hab diese Matrix benutzt.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 19:44    Titel: Antworten mit Zitat

In der Dokumentation zu D3DX steht, wie die Matirzne in D3DX Berechnet werden. DAmit kann man alle nötigen Funktionen selber schreiben.


Ich habe für jedes Sprite ienen VertexBuffer, weil jedes Srpite unterschiedliche Texturkoordinaten hat.
CPP:
   const float fTexX=0.5f/m_XSize;
   const float fTexY=0.5f/m_YSize;

Da X und YSize jedesmal unterschiedlich sien können, muss auch jedes Srpite einen eignene Buffer haben, oder?

Ich hab auch mal gehört, dass große Vertexbuffer nicht sehr effizient gemannaged werden können, ist ja auch klar, größere kann man schwerer effizient in den Speicher packne, als kleinerer, dafür hat man bei kleineren mehr aufwand. Ist warhshceinlich von GraKa zu GraKa unterschiedlich und müsste durch lange Testreiehn ermittelt werden Wink

Vertices ist IMHO ein englishces Wort, oder? Es müsste doch auch eine korrekte deutsche Pluralform geben.

Ok, die Filter hab ich ben extra nochmal getestet, das war wohl nur nötig, wenn ich diese Texturkoordinatenoptimierung ausschalte, weil dadurch die Sprites mal 1 Pixel größer odder kleiner werden, der Filter demnach aktiv wird, und alles total verschwommen erscheint.

Das beim Init die Renderstates alle gesetzt werden, hat damit zu tun, das ich eine sehr universelle Sprite klasse haben wollte. Man könnte das im Pirnzip auch in den Init teil der D3D Klasse machen, aber dann wäre die ja wieder auf Sprites ausgelegt^^. Ich glaub ihc werd versuchen das noch ein wenig zu optimiern.

2 Texturen lade ich gar nicht, wenn in der BMP Ladefunktion der Header nicht stimmt, weiß ich es kann kein bmp sein. Am Dateinamen kann man das manchmal nciht überprüfen, kann ja sien, das man allen Graifken die Endung .gfx verpasst, oder was bei mir shcon mal vorgekommen ist, man einfach nur die test.bmp lädt. Will man das Bild erstene kann man test.tga in test.bmp umbenennen und muss nichts neu kompilieren.
Ok, ich sollte vielleicht das so optimieren, das zuerst der Name gecheckt wird, und das Ergebnis davon versucht wird zu laden. Schlägt das fehl kann ich ja imemr noch die andere austesten. Das könnte in einigen Fällen ein öffnen und shcließen einer Datei ersparen.

Wie ihc alles in einem Rendercall machen soll, weiß ich nicht. Auf jeden Fall kann ich dann ja keine matirzen benutzen, weil pro Rendercall hat man nur eine Weltmatrix. Deshalb müsste ich ja alle Sprites berechnen, in einen Vertexbuffer schreiben und dann rendern. Dazu müsste ich alle Positinen zwischne speichern zusammenkkopieren und an die GraKa schicken. So muss ich jedesmal die Weltmatriz und den Vertexbuffer setzen.
Davon das Vertexbuffer setzen so langsam ist, ahb ich nichts gehört, aber kann natürlich sein.
Auf jeden Fall werden bei meiner Methode weniger Daten an die Grafikarte übertragen, weil eine Matrix kleiner ist als 2 dreiecke mit Texturkoordinaten.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 20:21    Titel: Antworten mit Zitat

Jonathan_Klein hat Folgendes geschrieben:
Ich habe für jedes Sprite ienen VertexBuffer, weil jedes Srpite unterschiedliche Texturkoordinaten hat.
CPP:
const float fTexX=0.5f/m_XSize;
const float fTexY=0.5f/m_YSize;

Da X und YSize jedesmal unterschiedlich sien können, muss auch jedes Srpite einen eignene Buffer haben, oder?

Wieso? Du kannst doch einfach die Vertex-Datensätze der Sprites hintereinander in den Puffer laden und referenzierst dann mittels Indexbuffer? Du renderst das erste Sprite mit den Datensätzen 1, 2, 3 und 4, das zweite mit 5, 6, 7 und 8 usw.


Jonathan_Klein hat Folgendes geschrieben:
Das beim Init die Renderstates alle gesetzt werden, hat damit zu tun, das ich eine sehr universelle Sprite klasse haben wollte. Man könnte das im Pirnzip auch in den Init teil der D3D Klasse machen, aber dann wäre die ja wieder auf Sprites ausgelegt^^. Ich glaub ihc werd versuchen das noch ein wenig zu optimiern.

Ich meinte eher die zahlreichen State-Changes in der Render-Methode. ;) Klar braucht jedes Sprite seine individuellen States, aber der Trick ist ja, dass man die Objekte so sortiert, dass man nach Möglichkeit alle Objekte mit gleichen Eigenschaften in einem Rutsch rendern kann. ;) Sprich die States nur dann geändert werden, wenn es unbedingt notwendig ist.


Jonathan_Klein hat Folgendes geschrieben:
2 Texturen lade ich gar nicht, wenn in der BMP Ladefunktion der Header nicht stimmt, weiß ich es kann kein bmp sein. Am Dateinamen kann man das manchmal nciht überprüfen, kann ja sien, das man allen Graifken die Endung .gfx verpasst, oder was bei mir shcon mal vorgekommen ist, man einfach nur die test.bmp lädt. Will man das Bild erstene kann man test.tga in test.bmp umbenennen und muss nichts neu kompilieren.

Um ehrlich zusein verstehe ich dich gerade nicht ganz, aber ist halt auch wieder wie mit den States, die Textur nicht in jedem Render-Aufruf eines jeden Sprites setzen, sondern nur, wenn du wirklich mit einer neuen Textur rendern willst. Dafür müssen die Sprites natürlich in der korrekten Reihenfolge sortiert vorliegen.


Jonathan_Klein hat Folgendes geschrieben:
Wie ihc alles in einem Rendercall machen soll, weiß ich nicht. Auf jeden Fall kann ich dann ja keine matirzen benutzen, weil pro Rendercall hat man nur eine Weltmatrix. Deshalb müsste ich ja alle Sprites berechnen, in einen Vertexbuffer schreiben und dann rendern. Dazu müsste ich alle Positinen zwischne speichern zusammenkkopieren und an die GraKa schicken. So muss ich jedesmal die Weltmatriz und den Vertexbuffer setzen.

Ja, das ist klar, war auch eher nur so ein Gedanke, aber ich könnte mir z.B. vorstellen, dass du eine Tile-Klasse von deiner Sprite-Klasse abgeleitet hast und dann auf diese Weise natürlich jedes Tile einzeln renderst, effektiver wäre es, den kompletten Layer in einem Rutsch zu rendern. Nur so als Beispiel, wo man da eventuell über die Zahl der Rendercalls was optimieren könnte. ;)


Jonathan_Klein hat Folgendes geschrieben:
Davon das Vertexbuffer setzen so langsam ist, ahb ich nichts gehört, aber kann natürlich sein.

Muss in D3D auch nicht zwangsläufig so sein, aber ich kann eben nur von OpenGL berichten, und dort gilt immer der Grundsatz: "So wenig States ändern wie möglich", kann gut möglich sein, dass das Setzen der diversen States in D3D sehr flott ist, was mich jedoch wundern würde, wenn sich die APIs in diesem Punkt gravierend unterscheiden.

Was an OpenGL auch sehr praktisch ist, ist der Umstand, dass man Positionsvektor, Texturkoordinaten, Farbwert etc. eines Vertex getrennt in mehreren Puffern vorliegen hat, in D3D ist das doch afaik eine Struktur und nur ein Puffer, weiß gerade nicht, inwieweit sich dadurch eventuell neue Optimierungsmöglichkeiten ergeben.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 20:40    Titel: Antworten mit Zitat

Ja, Texturkoordinaten und Positionsdaten getrennt zu amchen wäre evlt. schon sinnvoll.

Ok, eine 2d Landschaft könnte man schön rendern, indem man alle Dreieekce in einen Buffer macht und nur eine Textur hat, in der alle anderen drin sind. Problem: Wenn die Landschaft 100 mal so groß ist wie der Bidlschirm, kannst nix wegcullen. Dafür müsste man die Landschaft in kleiner Teile unterteilen, die jeweils sagen wir ienen Bildschirm groß sind, damit man ausrechnen kann welche man rendern muss und welche nicht.

Naja, ein paar Optimierungen gibt es wohl ncoh, aber ich schätze nicht umbedingt in der Sprite kalsse, die man einfahc so mal schnell verwendne können soll. Nach Texturen zu sortieren erfordert ja schon ein wenig mehr Arbeit. Aber evtltl. werde ich das ja einbauen, muss das ganze Porjekt mal gescheit Profilen.

Achja, das mit den Hintereinander in einen Vertexbuffer. Ich glaube ich hab das jetzt verstanden, man kann ja den StartVertex und die Vertexanzahl angeben. Dadurch könnte ich einen sher großen Vertexbuffer erstellen, den ich dann die ganze Zeit nutzen kann. Einziges Probel: Ich müsste den bie jedme Sprit Init neu erstellen, bzw. erweitern. Da hilft nur auf verdacht groß anlegen oder eben immer neu kopieren. Da muss man halt checken, ob längere ladezeiten sich mit kürzeren Renderzeitne rechnen (wie viel das jeweils ausmacht).
Evlt. könnte man das auch optimieren, da man nur Vertexdaten für ne andere Texturgröße braucht. Hat man also 300 mal die selbe Bidlgröße, braucht man auch nur einen Buffer, der diese Bildgröße in den Texturkoordinaten berücksichtigt.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 22:21    Titel: Antworten mit Zitat

Jonathan_Klein hat Folgendes geschrieben:
Ok, eine 2d Landschaft könnte man schön rendern, indem man alle Dreieekce in einen Buffer macht und nur eine Textur hat, in der alle anderen drin sind. Problem: Wenn die Landschaft 100 mal so groß ist wie der Bidlschirm, kannst nix wegcullen. Dafür müsste man die Landschaft in kleiner Teile unterteilen, die jeweils sagen wir ienen Bildschirm groß sind, damit man ausrechnen kann welche man rendern muss und welche nicht.

Dafür gibt's ja eigentlich den Indexbuffer, mit einem halbwegs intelligentem Cullingalgo sollte es recht easy sein in jedem Frame festzustellen, was gerendert werden muss und was nicht. Unter OpenGL ist ein Indexbuffer nichts weiter als ein Array von Integralwerten, kann also in jedem Frame sehr schnell neu zusammen gestellt werden.


Jonathan_Klein hat Folgendes geschrieben:
Naja, ein paar Optimierungen gibt es wohl ncoh, aber ich schätze nicht umbedingt in der Sprite kalsse, die man einfahc so mal schnell verwendne können soll. Nach Texturen zu sortieren erfordert ja schon ein wenig mehr Arbeit. Aber evtltl. werde ich das ja einbauen, muss das ganze Porjekt mal gescheit Profilen.

Die Sprites sind ja das Rückrat jeder gescheiten 2D-Engine, ist sicher nicht verkehrt dort rauszuholen was nur geht. ;)


Jonathan_Klein hat Folgendes geschrieben:
Achja, das mit den Hintereinander in einen Vertexbuffer. Ich glaube ich hab das jetzt verstanden, man kann ja den StartVertex und die Vertexanzahl angeben. Dadurch könnte ich einen sher großen Vertexbuffer erstellen, den ich dann die ganze Zeit nutzen kann. Einziges Probel: Ich müsste den bie jedme Sprit Init neu erstellen, bzw. erweitern. Da hilft nur auf verdacht groß anlegen oder eben immer neu kopieren. Da muss man halt checken, ob längere ladezeiten sich mit kürzeren Renderzeitne rechnen (wie viel das jeweils ausmacht).

Man kann Vertexbuffer doch locken und dynamisch erweitern, andererseits werden Sprites doch eh weitesgehend zu Beginn des Programms erstellt, von daher dürfte es relativ egal sein, wenn das etwas länger dauert. Würde ich zumindest nicht als Flaschenhals sehen.


Jonathan_Klein hat Folgendes geschrieben:
Evlt. könnte man das auch optimieren, da man nur Vertexdaten für ne andere Texturgröße braucht. Hat man also 300 mal die selbe Bidlgröße, braucht man auch nur einen Buffer, der diese Bildgröße in den Texturkoordinaten berücksichtigt.

Naja, vorrausgesetzt, du willst nicht skalieren. Bei Tilemaps wäre das z.B. der Fall, man könnte entweder ein richtig fetten Vertexbuffer mit allen Infos machen und dann per Indexbuffer jeweils die zurendernden Tiles rauspicken, oder man könnte nur ein Tile in den Vertexbuffer laden, rendern, Modelview- bzw. Worldmatrix verschieben, nächstes Tile rendern usw., allerdings dürften da die Texturkoordinaten früher oder später Probleme bereiten, da die ja von Tile zu Tile unterschiedlich sind. Ich grübel schon länger über dem Problem des Tile-Renderings und hab noch keine Lösung gefunden, die mich wirklich zufrieden stellt. Ideal wäre ja, wenn man die Menge der benötigten Daten im Grafikkartenspeicher für jede beliebige Map-Größe konstant halten könnte, das würde Tilemaps von theoretisch unendlicher Größe, ohne Nachladerei ermöglichen, aber eine Patentlösung habe ich dafür noch nicht gefunden, aber die meisten Entwickler dürfte dieses Problem sowieso nur minimal tangieren, da die Grafikkarten heutzutage so flott sind, dass sie eigentlich problemlos mal so eben ein paar Tausend Sprites rendern. ;)

Trotzdem, schön wäre an dieser Stelle, wenn es beim Rendern möglich wäre mehrere Indexbuffer anzugeben, einen für die Positionsdaten, einen für die Texturkoordinaten etc., dann könnte man sich ein "Gitter" welches Bildschirmgröße hat für die Positionsdaten in den Grafikkartenspeicher laden, ebenso könnte man die möglichen Texturkoordinaten für alle möglichen Tiles vorberechnen, diese ebenfalls in einen Puffer auf die Karte packen. Ausgewählt werden die Tiles auf der Textur durch die Koordinaten, da Tiles normalerweise eine fixe Größe haben, könnte man die schön vorberechnen und in den Vertexbuffer laden (bei einem Tilesset mit 10x10 Pixeln, ständen dann als Werte eben 0.0f/0.0f, 0.1f/0.0f, 0.2f/0.0f... 0.0f/0.1f, 0.1f/0.1f, 0.2f/0.1f... usw. im Puffer, ich hoffe man versteht worauf ich hinaus will). Zumindest OpenGL bietet da eben die Möglichkeit für jeden Aspekt eines Vertex einen eigenen Puffer zu erzeugen. Anschließend könnte man aus diesen beiden Puffern mittels 2er Indexbuffer rendern. Würde man scrollen, könnte man erst die Modelview- bzw. Worldmatrix leicht verschieben, wäre dann die Länge oder Breite eines Tiles "abgescrollt", könnte man die Matrix zurücksetzen und würde den Indexbuffer für die Texturkoordinaten ändern. Schade nur, das es meines Wissens so leider nicht möglich ist, da es beim Rendercall nur möglich ist, maximal einen Indexbuffer anzugeben und dieser zum Referenzieren in allen gebundenen Puffern verwendet wird (bzw. in D3D dürfte es ja sowieso nur einer sein, der dafür alle Daten enthält).
Also wenn da jemand 'ne klasse Idee hat, nur her damit. :) Könnte noch richtig interessant werden der Thread. ;)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 05.08.2006, 22:38    Titel: Antworten mit Zitat

Naja, wenn man viel Speicher hat, ist es wohl das schnellste die Tilemap einmal zu rendern und dann nur noch Ausschnitte zu blitten. 1024x768x32 macht ne Bildgröße von 3mb, mit 30 MB Graka Speicher (für ein 3d spiel, welches normalerweise nur wenig von den 128 bzw. 256 bzw 512 mb braucht) hat man dann schon ein paar Bildschirme voll.
Naja, aber wenns sowieso flüssig läuft, egal wie mans macht, braucht man auch nicht die 30 MB GraKaSpeicher zu belegen.

Gut, Indexbuffer lässt sich viel schneller füllen, als ein Vertexbuffer.

Gut, evtl. wäre es sehr sinnvoll, einen SpriteManager zu proggen, der automatisch Texturen verwaltet und Sprites entsprechend sortiert. Macht man den Singleton, bemerkt der User davon nur, das er ihn einmal kurz mit dem Device intitialisieren muss, und kann die Spriteklasse sonst genauso wie vorher benutzen.
Mal sehen, im Moment ist glaube ich das Hauptargument, das manche Rechner einfach kein D3D9Devcie erstellen können, keine Ahnung ob ich da falsche Werte angebe, oder ob es aus Prinzip net geht:
CPP:
bool Direct3D::Init(HWND hWnd, bool Windowed)
{
   ShutDown();//wenn schon initialisiert war, deinitialiseren!

   m_D3D=Direct3DCreate9(D3D_SDK_VERSION);
   if(NULL==m_D3D)
   {
      return false;
   }

   //PresentParams komplett setzen:
   m_PParams.BackBufferWidth=1024;
   m_PParams.BackBufferHeight=768;
   m_PParams.BackBufferFormat=D3DFMT_X8R8G8B8;
   m_PParams.BackBufferCount=2;
   m_PParams.MultiSampleType=D3DMULTISAMPLE_NONE;//antialiasing
   m_PParams.MultiSampleQuality=0;
   m_PParams.SwapEffect=D3DSWAPEFFECT_DISCARD;
   m_PParams.hDeviceWindow=hWnd;
   m_PParams.Windowed=Windowed;
   m_PParams.EnableAutoDepthStencil=true;
   m_PParams.AutoDepthStencilFormat=D3DFMT_D24S8;
   m_PParams.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
   m_PParams.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
   m_PParams.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;//vsync an/aus

   if(D3DERR_INVALIDCALL==m_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
            D3DCREATE_MIXED_VERTEXPROCESSING, &m_PParams, &m_Device))
   {
      cLog::GetInstance() << LOGE("Invlid call beim erstellen des D3D-Devices");
   }


   //eine Liste von eigentschaften die die graifkkarte unterstüzen muss, damit das spiel funktioneirt


   if(NULL==m_Device)
   {
      cLog::GetInstance() << LOGE("Device konnte nicht erstellt werden");
      MessageBox(hWnd, "Das Direct3D9 Device konnte nicht initialisiert werden.", "Fehler", MB_OK);
      
      return false;
   }
      
   
   return true;
}


Also ist ja fast alles Minimal bzw. Standardkonfiguration. Das einzige was ncoh sein könnte, wäre der lockbare Backbuffer und der Stencilbuffer. Evlt. sollte ich mal die Caps überprüfen, obwohl ich mir nicht sicher bin, das es daran liegt.

Solange ich also auf alten Grafikkarten noch kein Device bekomme, brauch ich auch nix dafür zu optimieren *g*
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> DirectX, OpenGL Alle Zeiten sind GMT
Gehe zu Seite 1, 2  Weiter
Seite 1 von 2

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum