Game Asset Management

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Game Asset Management

Beitrag von RazorX »

Servus an alle,

bislang hab ich in meinen Grafikanwendungen die verwendeten Ressourcen hart codiert, also eine simple Änderung erforderte immer eine Neukompilierung. Nun würd ich gern umsteigen auf XML basierende Konfigurationsscripts, eben für Materialen, PostProcessing, etc. Dabei stellen sich mir aber ein paar logische Hürden auf, denn ein Asset...
  • ... muss eindeutig identifizierbar sein (schreit nach UUID), ...
  • ... wird durch einen Pfad geladen und ...
  • ... und soll unabhängig von anderen existieren können.
Mein Problem ist nun das verbinden der UUID mit dem zugehörigen Pfad. Zum Beispiel kann ich im Material spezifizieren, dass ich eine Textur als Input auf Slot x setzt. Diese Textur ist durch eine UUID definiert, muss aber nicht im Material weiter erläutert sein. Das führt unausweichlich dazu, dass ich eine zentrale Datei pflegen muss, eben eine Leveldatei oder wie auch immer man es nennen möchte, in der notwenige Ressourcen einmalig deklariert werden.

Code: Alles auswählen

<level>
    <texture path="data\textures\test.dds" uuid="12345" />
    <mesh include="data\meshes\test.mesh" />
</level>
Das Mesh includiert nun wiederum ein Material:

Code: Alles auswählen

<material uuid="23456">
    <shader type="pixel">
        <file>data\shader\test.hlsl</file>
        <function>ps_main</function>
        <srv>
             <slot index=0>12345</slot>
        </srv>
    </shader>
</material>
Nun habe ich also in dem Material, was unabhängig von dem Level sein soll, eine UUID stehen die aber in einem anderem Level anders sein könnte. Eine Überlegung war den Pfad zu hashen und als ID zu verwenden, wobei die Kollisionen wohl zu häufig sein sollten und der Ansatz unbrauchbar sein sollte. Desweiteren habe ich über 64bit große IDs nachgedacht:

Hexidezimal: aa - bbbbbbbb - cccccc
  1. Asset Typ ID - z.B. 1=Textur, so könnte man mit ein bisschen Shiften ein Asset gegen eine Anfrage validieren.
  2. Asset ID - Eben z.B. ein Hash oder Random
  3. Asset SubID - Bislang erstmal uninteressant, aber fürs Speichern von modifizierten Assets zur Laufzeit
Mich würd jetzt erstmal interessieren ob der Ansatz soweit praktikabel ist und wie ich eben die genannte Beziehung UUID <=> Pfad in den Griff bekommen könnte.

Dank im vorraus
Gruß RazorX
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Game Asset Management

Beitrag von Chromanoid »

Wenn Du die Pfade entsprechend behandelst, könntest Du sie auch direkt als UIDs verwenden.
Benutzeravatar
Krishty
Establishment
Beiträge: 8237
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Game Asset Management

Beitrag von Krishty »

Genau. Als Perfektionisten-Bonus kann man dann bei der Installation oder beim ersten Start alle Pfad-IDs zu den UIDs der Dateien auf dem Installationslaufwerk patchen ;)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Game Asset Management

Beitrag von Chromanoid »

Für den Rest würde ich auch nicht unbedingt IDs verwenden sondern vernünftige Bezeichner. Sonst wird es nur kompliziert. Zumindest wenn Du keinen guten Editor hast. Wenn Du Daten aus anderen Dateien importieren willst, kannst Du ja vielleicht auch eine Art URL-Format benutzen: data/common.mat#test1
Benutzeravatar
Krishty
Establishment
Beiträge: 8237
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Game Asset Management

Beitrag von Krishty »

Aber nur für die Rohdaten während der Entwicklung! Wenn dann der Ressourcen-Compiler drüberläuft, kompiliert er die zu IDs, die bestenfalls nur noch Indizes oder Zeiger ins zentrale Dateiverzeichnis sind. Damit wäre dann auch direkt das uralte Problem gelöst, wie man die tausenden nicht benutzte Assets, die von der Entwicklung noch im Verzeichnis rumliegen, vom Release ausgeschlossen kriegt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
TDK
Beiträge: 54
Registriert: 06.04.2012, 11:15

Re: Game Asset Management

Beitrag von TDK »

Razor X, ehrlich gesagt, wieso machst du solch eine einfache Sache so kompliziert? Ich meine, du willst du keine CMS in einer einzelnen Datei haben, oder?

Mein Vorschlag:
- MD5-Checksummen für Dateipfade relativ zum Programm herstellen und zum Gegenprüfen anderer Ressourcen nutzen
- Texture Manager, der die Texturen lädt, wenn sie benötigt werden
- Material-Klassen, die ggf. Texturen anfordern und die Daten an den Shader & Co. weitergeben
- XYZ-Klassen, die diese Materialien verwenden

(Es wird dich niemand daran hindern, in den Materialien Indices auf Texturen im Texture Manager zu verwenden...)
(Bei XYZ-Klassen auf Materialien ebenso...)

Freund und Helfer ist hier std::shared_ptr<> und eine eigene Klasse zum Zählen von Referenzen auf Objekte.
Den Texture Manager brauchst du dann nur 1x pro Frame updaten, um nichtbenötigte Ressourcen freizugeben.
Und bitte erst dann, nachdem du ggf. Daten freigegeben + beansprucht hast. Damit sparst du dir unnötige Festplattenzugriffe.

Traumgeschichten bei Materialien, wie z.B. jetzt mal den Parameter XY und dann CE hinzufügen und dort wieder nicht, sind praktisch sinnlos und bringen in 99% der Fälle gar nichts, außer Performance-Einbußen. Es gibt mittlerweile Standards, die nicht festgeschrieben aber Praxis sind.

Denn was du bei der UUID-Idee nicht beachtest: Wie stellen deine Tools sicher, dass die UUID schon vergeben ist? Willst du jedes mal deinen gesamten Content durchlaufen (pro Datei), nur um eine gültige UUID zu bestimmten?
Diese Geschichte habe ich hier von einem Programm aus den Jahren 2003 - 2006. Und das Resultat ist im Bezug zur Performance und Qualität katastrophal und läuft auf viele Cache Files für nichts aus.
Benutzeravatar
Krishty
Establishment
Beiträge: 8237
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Game Asset Management

Beitrag von Krishty »

Das würde ich ablehnen weil es eine Laufzeitlösung ist. Welche Ressourcen benötigt werden kann man schon vor Ausführung des Programms bestimmen und das Ganze statisch lösen; dann einfach den Adressraum damit vollklatschen und zur Laufzeit nichts mehr ändern.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: Game Asset Management

Beitrag von RazorX »

Krishty hat geschrieben:Genau. Als Perfektionisten-Bonus kann man dann bei der Installation oder beim ersten Start alle Pfad-IDs zu den UIDs der Dateien auf dem Installationslaufwerk patchen ;)
Prinzipiell eine coole Sache, funktioniert aber nur, wenn jede Datei physisch auf dem Datenträger vorhanden ist. Wenn eine Datei nun z.B. innerhalb eines Archivs komprimiert vorliegt und diese beim Streamen dekomprimiert in den Speicher geladen werden funktioniert der Ansatz nicht mehr.
TDK hat geschrieben:Razor X, ehrlich gesagt, wieso machst du solch eine einfache Sache so kompliziert? Ich meine, du willst du keine CMS in einer einzelnen Datei haben, oder?
Naja einfache Sache ist nett gesagt, ists aber nicht. Wenn man mal deinen Ansatz in Betracht zieht, eben das Hashen mit MD5 der Dateipfade, so gibt es auch dort mit einer gewissen Wahrscheinlichkeit Probleme. Denn Hashfunktionen sind zwar darauf optimiert Kollisionen zu vermeiden, dennoch können diese auftreten. Was also, wenn ich zwei Dateien in meinem Bestand habe, die die selbe ID generieren? Ich könnte natürlich eine Überlauftabelle generieren, das löst das Problem der Speicherung, aber die Identifikation ist dann ein Ratespiel.
TDK hat geschrieben: Denn was du bei der UUID-Idee nicht beachtest: Wie stellen deine Tools sicher, dass die UUID schon vergeben ist? Willst du jedes mal deinen gesamten Content durchlaufen (pro Datei), nur um eine gültige UUID zu bestimmten?
Diese Geschichte habe ich hier von einem Programm aus den Jahren 2003 - 2006. Und das Resultat ist im Bezug zur Performance und Qualität katastrophal und läuft auf viele Cache Files für nichts aus.
Genau das ist auch das Problem was ich dabei momentan sehe. Letztlich muss ein Objekt (Datei passt momentan weniger) eindeutig identifizierbar sein. Aber auch bei Namen kann es zu Konflikten kommen, wodurch das Argument nicht zieht.


Letztlich würd ich definitiv den numerischen Ansatz bevorzugen, denn ...
  1. ... das Speichern eines Strings ist definitiv speicherintensiver (wenn dann nur wie Krishty sagte im Debug-Modus und im Release muss das ganze durch IDs ersetzt werden)
  2. ... kann man in einer numerischen Repräsentation nette Informationen unterbringen, die durch logische Operationen abgeglichen werden können (der String müsste dafür erstmal geparst werden).
Desweiteren bin ich kein Fan davon für jede Klasse einen Manager zu bauen. Letztlich sind alles, ob Texturen, Meshes, Materialen etc, Assets die zum Laden, Speichern und Freigeben keiner weiteren Behandlung bedürfen. Das bedeutet doch das ich eine zentrale Datenbank (eine asset_database) benötige, denn auch nur so kann ich sicherstellen, dass ich eindeutige IDs verwende. Auch muss nicht jeder Manager einen asynchronen Ladethread für seine zu ladenen Objekte anlegen oder auch nicht das Freigeben von nicht genutzten Ressourcen implementieren. Jedes Asset wird freigegeben wenn es im Zeitraum x nicht benötigt wurde (das muss wahrlich nicht in verschiedenen Managern implementiert werden).
Antworten