Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Di Jul 29, 2025 22:44

Foren-Übersicht » DGL » Feedback
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Binden von Texturen
BeitragVerfasst: Mi Nov 17, 2004 15:00 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Hi,

Ich hab mir eine Möglichkeit überlegt, wie man komfortabel Texturen binden kann.
Ähnlich wie beim Texture-Manager von Sascha.
Dort hat mich jedoch gestört, dass die Texturen als string angesprochen werden. Ich nehme mal nicht an, dass solch eine Vorgehensweise gut für die Performance ist. Andererseits bietet sie einen großen Komfort.

Als Alternative erschien mir noch das Ansprechen über ein Array. Allerdings wollte ich die Texturen nicht über Nummern ansprechen, sondern schon über irgendeine Art Name.

Ich hab mich dann etwas vom PCode-Tutorial inspirieren lassen und spreche seitdem die Texturen so an:
Code zur Definition der Texturen:
Code:
  1. type
  2.   textypes = (gras, rock, keen, sand, snow, water, jet);
  3.  
  4. const
  5.   texpath: Array[textypes] of ShortString = ('gras.bmp',
  6.                                            'rock.bmp',
  7.                                            'keen.tga',
  8.                                            'sand.bmp',
  9.                                            'snow.bmp',
  10.                                            'water.bmp',
  11.                                            'jet.bmp');
  12.   TEX_PREFIX = 'Textures';


Laderoutine:
Code:
  1. procedure TRenderMachine.LoadTextures;
  2. var
  3.   i: textypes;
  4. begin
  5.   for i := gras to jet do
  6.   begin
  7.     Textures[i] := TglBitmap2D.Create(ExtractFilePath(Application.ExeName)+TEX_PREFIX+texpath[i]);
  8.     if Not Textures[i].HasAlpha then Textures[i].AddAlphaFromColorKey(1,0,1);
  9.     // evtl. noch andere Sachen mit der Textur machen
  10.     Textures[i].GenTexture;
  11.   end;
  12. end;


Und hier dann die Verwendung:
Code:
  1. Textures[rock].Bind;


Mögliche Definition für Textures:
Code:
  1. Textures: array [textypes] of TglBitmap;



Was haltet ihr von dieser Methode? Was gibt es noch für alternativen? Was könnte man noch optimieren? usw...

Gruß,
SpaceJunky


Zuletzt geändert von Frase am Mi Nov 17, 2004 15:16, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 15:08 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
Das Problem ist, das deine Anzahl von Texturen beschränkt ist. Mach dir doch eine TStringList mit den Texturen. Dann speicherst du am besten bei jeder Texture noch einen Zähler wie oft sie verwendet wird.
Ich habe bei mir alle Texturen in einer Liste gespeichert. Mit TTexture2D.LoadTexture lädt man eine Texture, falls sie noch nicht in der Liste ist und erhöht den Zähler. Wenn man die Texture nicht mehr braucht wird die Methode Release aufgerufen, die den Zähler erniedrigt. Falls der Referenzzähler dabei den Wert 0 erreicht, wird die Texture freigegeben und aus der List entfernt.
So werden die nötigen Texturen immer bei Bedarf geladen, ohne dass unnötige Texturen im Speicher bleiben und man muß auch nicht am Anfang oder Ende des Levels einen großen Ladevorgang durchführen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 15:23 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
LarsMiddendorf hat geschrieben:
Das Problem ist, das deine Anzahl von Texturen beschränkt ist. Mach dir doch eine TStringList mit den Texturen. Dann speicherst du am besten bei jeder Texture noch einen Zähler wie oft sie verwendet wird.
Ich habe bei mir alle Texturen in einer Liste gespeichert. Mit TTexture2D.LoadTexture lädt man eine Texture, falls sie noch nicht in der Liste ist und erhöht den Zähler. Wenn man die Texture nicht mehr braucht wird die Methode Release aufgerufen, die den Zähler erniedrigt. Falls der Referenzzähler dabei den Wert 0 erreicht, wird die Texture freigegeben und aus der List entfernt.
So werden die nötigen Texturen immer bei Bedarf geladen, ohne dass unnötige Texturen im Speicher bleiben und man muß auch nicht am Anfang oder Ende des Levels einen großen Ladevorgang durchführen.

Wieso ist meine Anzahl von Texturen beschränkt??? Oder meinst du die normale Hardware-Beschränkung?
Könntest du mir das mit der Stringlist und dem Zähler mal nochmal erläutern? Klingt interesant. ;) Aber ich seh schon die FpS in den Keller gehen bei der Verwendung von Stringlisten. Auch wenn es sortierte HashedStringlisten sind.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 15:24 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Sep 23, 2002 19:27
Beiträge: 5812
Programmiersprache: C++
Warum sollen StringListen denn die FPS in den Keller bringen? Im Normalfall rendert man ja eh über Displaylisten oder VBOs, und da sind die Aufrufe an eine Stringlist doch recht wenige.

Deine Methode ist halt total statisch weil du ein Set benutzt. Von daher recht unbrauchbar für Anwendungen die ihre Szenen dynamisch laden wollen.

_________________
www.SaschaWillems.de | GitHub | Twitter | GPU Datenbanken (Vulkan, GL, GLES)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 15:55 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
Zitat:
Aber ich seh schon die FpS in den Keller gehen bei der Verwendung von Stringlisten. Auch wenn es sortierte HashedStringlisten sind.


Die String Liste muß doch nur angesprochen werden, wenn eine neue Texture geladen wird. Und das passiert normalerweise nicht so häufig. Ansonsten hat man ja das Texture Object.

Viele Objekte werden ja gemeinsam benutzt und deshalb muß man beim Objekt speichern wie oft es benutzt wird, damit man es korrekt freigeben kann. Das ist nicht nur bei Texturen sondern eigentlich bei ganz vielen Objekten wie Modellen, Sounds, usw... so.

Speziell auf die Texturen bezogen kann man das so machen:

TTexture=class
private
..
refcount:Integer;
public
...
procedure AddRef;
procedure Release;
class function LoadTexture(const name:string):TTexture;
...
end;

Laden einer Texture.
-Eine Funktion die einen Texturenamen übergeben bekommt.
Die Funktion schaut nach, ob die Texture in der Liste ist. Wenn sie nicht drin ist, wird sie geladen.
Der Referenzzähler wird erhöht, weil die Texture ja jetzt einmal mehr verwendet wird.
Das Texture Object wird zurückgegeben.

Danach wird ganz normal mit dem Objekt gerarbeitet.

Freigeben einer Texture:
-Der Zähler wird erniedrigt. Wenn er jetzt bei 0 ist, dann war das die letzte Referenz und die Texture kann gelöscht werden.

So ungefähr könnte man das programmieren.

Code:
  1. procedure TTexture.AddRef;
  2. begin
  3.  inc(refcount);
  4. end;
  5.  
  6. procedure TTexture.Release;
  7. begin
  8.  dec(refcount);
  9.  if refcount<=0 then
  10.  begin
  11.   texturelist.delete(texturelist.indexof(name));
  12.   Free;
  13.  end;
  14. end;
  15.  
  16. class function TTexture.LoadTexture(const name:string):TTexture;
  17. var
  18.  i:Integer;
  19. begin
  20. i:=texturelist.indexof(name);
  21. if i=-1 then result:=TTexture.create(name) else result:=TTexture(texturelist.objects[i]);
  22. result.AddRef;
  23. end;


Eine Alternative sind die Interface Typen. Die haben automatisch einen Referenzzähler und werden von Delphi verwaltet. Man kann daher davon ausgehen, dass das Objekt automatisch gelöscht wird, wenn es keine Referenzen mehr darauf gibt.
Das Problem beim Referenzzählen ist, dass es Schwierigkeiten gibt, wenn sich Objekten gegenseitig referenzieren, aber bei diesen typischen Klassen die GL Objekte kapseln ist das üblicherweise nicht der Fall.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 15:56 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Zitat:
TextureName : THashedStringList

In dieser StringList werden die Texturennamen abgelegt, über die der Texturenmanager später die Texturen im Texturearray addressiert. Hier wird statt einer herkömmlichen TStringList eine THashedStringList verwendet, da diese bei häufigen Suchvorgängen (was bei vielen Texturenwechseln der Fall ist) und besonders bei großen Datenmengen schneller als die herkömmliche TStringList ist


Da hab ich einfach hineininterpretiert, dass eine möglichst schnelle Lösung zu bevorzugen ist. Und da ich bei Napalm-Bomber nur 30 fps kriege, hab ich das auf die Stringlist zurückgeführt.

Meine Methode ist tatsächlich statisch. (Im Gegensatz zu der da oben :wink: ) Was ich aber nicht unbedingt als Nachteil empfinde.

Ist halt mehr für kleine Projekte gedacht, deren Texturen statisch sein können.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 15:58 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
Die THashedStringList ist natürlich die bessere Variante wenn sie bei deiner Delphi Version dabei ist(ab 6).
Aber man braucht während des Renderns ja sowieso nie die String Liste, weil man ja optimalerweise direkt mit den Objekten arbeitet.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 16:10 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
LarsMiddendorf hat geschrieben:
Zitat:
Aber ich seh schon die FpS in den Keller gehen bei der Verwendung von Stringlisten. Auch wenn es sortierte HashedStringlisten sind.


Die String Liste muß doch nur angesprochen werden, wenn eine neue Texture geladen wird. Und das passiert normalerweise nicht so häufig. Ansonsten hat man ja das Texture Object.


Und wir bindest du die Texturen dann?
Sammelst du die TTextures in einem Array? Dann wirst du wohl über Nummern darauf zugreifen:
Code:
  1. var
  2.   Textures: array of TTexture;
  3. begin
  4.   Textures[3].Bind;
  5.   // und so weiter
  6. end;


Und wieso muss eine Stringliste angesprochen werden, wenn eine neue Textur geladen wird? Ich dachte eigentlich, dass die angesprochen wird, wenn die Textur dann gebunden wird.

LarsMiddendorf hat geschrieben:
Viele Objekte werden ja gemeinsam benutzt und deshalb muß man beim Objekt speichern wie oft es benutzt wird, damit man es korrekt freigeben kann. Das ist nicht nur bei Texturen sondern eigentlich bei ganz vielen Objekten wie Modellen, Sounds, usw... so.

:?: :?: :?:
Ich erzeuge meine Objekte immer nur einmal und gebe die dann auch nur einmal frei. (Lässt sich nicht vermeiden, wenn man nur bis 3 zählen kann :wink: ). Spaß beiseite: Was meinst du damit???


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 16:12 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
LarsMiddendorf hat geschrieben:
Die THashedStringList ist natürlich die bessere Variante wenn sie bei deiner Delphi Version dabei ist(ab 6).
Aber man braucht während des Renderns ja sowieso nie die String Liste, weil man ja optimalerweise direkt mit den Objekten arbeitet.

Mit welchen Objekten??? Seh ich den Baum vor lauter Wäldern nicht?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 16:29 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
Wenn du irgendwo eine Texture benötigst dann kannst du dir natürlich die Texture Nummer von OpenGL holen oder nimmst gleich das Objekt, das bei dir diese Texture kapselt. Auf diesem Objekt mußt du dann nur noch so eine Methoden zum Binden aufrufen. Die TextureID von OpenGL ist ja dann vermutlich in dem Objekt gespeichert und kann direkt verwendet werden.

Die String Liste benötigt man nur um Texturen nicht mehrfach zu laden.

Angenommen du hast ein 3D Model und das hat immer genau eine Texture.
Dann muß diese Texture natürlich vor dem ersten Rendern geladen werden. Man muß also in der Liste nachsehen ob die Texture bereits geladen ist und falls nicht, die Texture dann eben laden. Ich hatte in dem vorherigen Bsp vergessen die neu erstellte Texture in der Liste zu speichern.
Das 3D Modell bekommt dann nur das Textureobjekt. Wenn die Texture gebunden werden soll, muß man nicht suchen, weil man diese Texture ID von OpenGL ja mit in dem Objekt speichert.
Wenn das Model irgendwann wieder gelöscht wird, dann sollte es die Texture ja auch wieder freigeben. Das Problem ist aber, das inzwischen schon ein anderes Model die gleiche Texture angefordert haben könnte. Da man Texture nicht doppelt laden will, hat man dem anderen Model natürlich die gleiche Texture gegeben.
Damit es jetzt keine Probleme gibt, speichert man bei jeder Texture wie oft sie rausgegeben wurde. Wenn eine Texture jetzt nicht mehr benötigt wird, kann man den Zähler dann wieder einen runtersetzen. Wenn man dann 0 erreicht gibt es keine Modelle mehr die diese Texture erhalten haben und sie kann problemlos gelöscht werden.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 16:42 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Ich hab irgendwie das Gefühl, du redest über was anderes...

Mein "Problem" ist, dass ich möglichst komfortabel rogrammieren will (Wer will das nicht? ;)
Und daher möchte ich bei meinem Texture-Manager auch möglichst komfortabel die Textur auswählen, die ich brauche.
Also sowas wie TextureManager.BindTexture('wand-textur');
Zu diesem Zeitpunkt ist die Textur ja bereits im Speicher. Es geht mir nur darum, sie beim Namen zu nennen.
In diesem Beispiel hier muss der Textur-Manager erstmal in einer Stringliste suchen, welche Textur mit 'wand-textur' gemeint ist, damit er auch die richtige Textur aus seinem Textur-Array bindet.
Also sowas da:
Code:
  1. procedure TexMan.BindTexture(texName: string);
  2. var
  3.   Textur_Nummer_im_Textur_Array: word;
  4. begin
  5.   Textur_nummer_im_Textur_Array := Suche_die_passende_Textur_nummer (texName);
  6.   Textur_Array[Textur_Nummer_im_Texturen_Array].Bind;
  7. end;

Ich vermute aber, dass durch dieses suchen das ganze recht langsam wird.

Aber deine mit dem Zähler und der "intelligenten" Texturen-Verwaltung (Was wir grad nicht brauchen, brauchen wir nicht, und was wir brauchen laden wir uns) ist genial.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Nov 17, 2004 20:57 
Offline
DGL Member
Benutzeravatar

Registriert: Do Jun 19, 2003 10:44
Beiträge: 991
Wohnort: Karlsfeld (nahe München)
Du könnest die Texturen auch gleich in Variablen speichern, die den einen entsprechenden Namen tragen:
Code:
  1.  
  2. Textur : record Boden,Holz_Wand, Licht:Cardinal; end;
  3.  

_________________
Danke an alle, die mir (und anderen) geholfen haben.
So weit... ...so gut


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Nov 18, 2004 16:00 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Hmm. Ich will die Texturen aber in einer Schleife oder etwas ähnlichem laden.
Bei so einem record sähe das doch dann so aus:
Code:
  1. LoadTexture ('eine_datei.tga', Textur.Boden);
  2. LoadTexture ('eine_andere_Datei.tga', Textur.Holz_Wand);
  3. LoadTexture ('ganz_andere_Datei.tga', Textur.Licht);


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Nov 18, 2004 16:51 
Offline
DGL Member
Benutzeravatar

Registriert: Do Jun 19, 2003 10:44
Beiträge: 991
Wohnort: Karlsfeld (nahe München)
SpaceJunky hat geschrieben:
Bei so einem record sähe das doch dann so aus:
Code:
  1. LoadTexture ('eine_datei.tga', Textur.Boden);
  2. LoadTexture ('eine_andere_Datei.tga', Textur.Holz_Wand);
  3. LoadTexture ('ganz_andere_Datei.tga', Textur.Licht);

Genau. Und dort wird dann ganz Übersichtlich festgelegt wo welche Datei geladen wird.
Gegeben falls nutzt du dann zum Laden nicht diese Funktion sondern eine eigene welche auf Fehler reagiert und die Verzeichnisse verwaltet.
SpaceJunky hat geschrieben:
Hmm. Ich will die Texturen aber in einer Schleife oder etwas ähnlichem laden.

Mehr als dich umstimmen kann ich nicht :wink:
MfG
Flo

_________________
Danke an alle, die mir (und anderen) geholfen haben.
So weit... ...so gut


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Foren-Übersicht » DGL » Feedback


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.018s | 15 Queries | GZIP : On ]