Du bist nicht angemeldet.

Werbeanzeige

Anonymous

unregistriert

1

07.10.2005, 16:06

Wie sortiere ich nun am besten Objekte ?

Wie sortiere ich nun am besten die Objekte,Texturen ect am besten vor dem rendern.

Als erstes das flexible Vertex-Format. Danach die Texture, die Renderstates und dann kommt der Vertexbuffer.

Würdet ihr sagen das diese Reihenfolge korrekt ist. Was fehlt hier noch?

rewb0rn

Supermoderator

Beiträge: 2 873

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

2

07.10.2005, 16:18

Was meinst du mit sortieren? Das Übergeben der Werte an DirectX, bevor sie gerendert werden? Da fehlen dann ggf noch Indexbuffer und ein Effekt. Die Reihenfolge ist ok.

Patrick

Alter Hase

Beiträge: 1 264

Wohnort: Düren

Beruf: Fachinformatiker für Anwendungsentwicklung

  • Private Nachricht senden

3

07.10.2005, 16:34

Ich poste dazu heute abend mal was Code und nach welcher Reihenfolge man Sortieren sollte. Aber sortieren nach FVF ist Unsinn.

Anonymous

unregistriert

4

07.10.2005, 17:35

@Patrick

Warum ist das sortieren nach FVF unsinnig?

@Spik)evil(

Hast recht da fehlt noch einiges. Ich habe jedoch gelesen das man nicht wild rumrendern sollte, sondern das ganze in eine bestimmte Ordnung bringen soll. Und das versuche ich gerade zu verstehen.

rewb0rn

Supermoderator

Beiträge: 2 873

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

5

07.10.2005, 17:37

Also da Patrick heute abend genaueres dazu sagen will, und ich bestimmt wieder irgendwas posten würde, was aus der einen oder anderen Perspektive Unfug wäre, halte ich mich lieber geschlossen :D

Anonymous

unregistriert

6

07.10.2005, 17:50

Bin auch darauf gespant was Patrick zu sagen hat. :huhu:

Patrick

Alter Hase

Beiträge: 1 264

Wohnort: Düren

Beruf: Fachinformatiker für Anwendungsentwicklung

  • Private Nachricht senden

7

07.10.2005, 19:42

Hi,

man sortiert immer nach Hauptkritieren, eben diese die Ausschlaggebend sind. Bei Grafikprogrammierung ist dieser ausschlaggebende Punkt nunmal der Bustransfer. Was am extrem längsten dauert sind Texturen über den Bus jagen und die Shadersetzung (Nein, kein FVF).

Ich gehe davon jetzt einfach mal aus das du keine Shader benutzt, da dies dann einfacher zur verdeutlichung ist.

Daher sollte man sich hier ein kluges Design austüfteln was deine sichtbaren polygone nach Texturen sortiert und dann ordentlich ausgibt.

Als erstes braucht man klassen die dafür da sind was sie repräsentieren. z.B. Material: Ein Material hat immer ein D3DMATERIAL objekt und ein Texturobjekt oder mehr (Hier nehmen wir nur ein Texturobjekt).

Dann eine Klasse für Polygone: Ein Polygon hat ein Material (Material und Textur, ergo: klasse), Vertices und Indices. In die Klasse für Polygone stopfen wir auch noch den VertexBuffer und Indexbuffer rein sowie das FVF.

So jetzt braucht man noch einen Manager.

In diesen Manager stopft man seine sichtbaren Polygone, daher erst die objekte vom typ "polygon" auf Sichtbarkeit testen und dann erst in den Manager stopfen. Je weniger reinkommen, desto schneller ist dein Programm (logisch!)

Nachdem diese drin sind wird ein Renderaufruf des Managers ausgeführt, darin wird jedoch erstmal sortiert nach Texturnamen (am besten nach std::basic_string<wchar_t> sortieren, Strings sind schneller zu vergleichen als riesige Pointerobjekte).

Nach dem sortieren wird jedes Polygon durchlaufen. Ist die gesetzte Textur die selbe wie im vorherigen Polygon, wird der Texturmanager (ja auch dafür sollte man einen haben) diese NICHT setzen, weicht der Texturname jedoch von der vorherigen Textur ab, dann wird die neue Textur über den Bus gejagt.

Da nach Texturnamen sortiert wurde, kann man mit 99% wahrscheinlichkeit davon ausgehen das kein Texturobjekt mehr als 1x über den Bus gejagt wird, was extrem viel zeit erspart.

Dann wird das D3DMATERIAL gesetzt sowie das FVF und gerendert per DrawIndexedPrimitive (oder so? jedenfalls keine UserPointer funktion!)

Am Ende wird der Manager geleert und das ganze Prozedere geht im nächsten Frame wieder von vorne los.

Egal hier Pseudocode:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    // Hilfsmakro um COM-Objekte ordentlich freizugeben.

template<typename T> inline void safeRelease (T*& object)
{
        // Ist das Object 'NULL'?

    if (object != NULL)
    {
            // Nein das Object ist noch nicht 'NULL'! Also Freigeben und

            // auf 'NULL' setzen.

        object->Release ();
        object = NULL;
    }
}

// für Freundschaften schonmal bekannt machen

class polygon;
class scenemanager;

// Klasse für Materials

class material
{
public:
        // Constructor, Copyconstructor und Destructor

    material (const ::D3DMATERIAL& material, const ::IDirect3DTexture9*& texture)
    : material_(material), texture_(texture) {}
    material (const material& other)
    : material_(other.material_), texture_(other.texture_) {}
  
    ~material (void)
    { safeRelease (texture_); }

        // Freundschaften

    friend class polygon; // Polygon hat vollzugriff auf private Elemente von material

    friend class scenemanager; // scenemanager hat vollzugriff

private:
        // Materialeingenschaften

    ::D3DMATERIAL        material_; // Material von Direct3D

    ::IDirect3DTexture9* texture_;  // Texturobjekt

};



    // Klasse für Polygone

class polygon
{
public:
        // Constructor und Copyconstructor

    polygon (unsigned long fvf, unsigned long num_vertices, unsigned long num_indices, 
             const ::vertex* vertices_, unsigned long* indices_, const ::material& mat)
    : fvf_(fvf), num_vertices_(num_vertices), num_indices_(num_indices), vertices_(vertices), indices_(indices), material_(mat)
    {
        // CreateVertexBuffer und CreateIndexBuffer ausführen

    }

    polygon (const polygon& other)
    : fvf_(other.fvf_), num_vertices_(other.num_vertices_), num_indices_(other.num_indices_), 
    vertices_(other.vertices_), indices_(other.indices_), material_(other.material_)
    {
        // CreateVertexBuffer und CreateIndexBuffer ausführen

    }

    ~polygon (void)
    {
            // Aufräumen nicht vergessen!

        safeRelease (vb_); // VertexBuffer

        safeRelease (ib_); // Indexbuffer

    }

        // Freundschaften

    friend class scenemanager; // Vollzugriff von scenemanager.


protected:
    unsigned long fvf_;         // Dein FVF

    unsigned long num_vertices_;// Anzahl vertices für dieses Polygon

    unsigned long num_indices_; // Anzahl indices für dieses Polygon

    ::vertex*     vertices_;    // Die Vertices des Polygons

    unsigned long*indices_;     // Die Indices des Polygons


    ::material     material_;      // Das Material


    ::IDirect3DVertexBuffer9* vb_; // VertexBuffer

    ::IDirect3DIndexBuffer9*  ib_; // IndexBuffer

};


    // Der Scenemanager. ACHTUNG: Hier wäre eine Freundschaft zu deiner D3D Klasse sehr hilfreich!

class scenemanager
{
private:
        // Con- und Destructor

    scenemanager  (void);
    scenemanager  (const scenemanager& other);
    ~scenemanager (void);

        // Es gibt nur eine Instanz. Jede Zuweisung wäre eine Selbstzuweisung.

        // Da Selbstzuweisungen selten Sinn machen, ist der op= privat

    scenemanager& operator= (const scenemanager& other);

public:
        // Diese statische Methode erzeugt die einzige Instanz.

        // Nur über diese Methode erhalten Anwender den Zugriff auf

        // die Instanz.

    inline static scenemanager& getInstance (void)
    {
            // Die Instanz wird erst beim ersten Aufruf erzeugt.

            // Endet das Programm, wird Instanz vernichtet.

        static scenemanager instance;
        return (instance);
    }

    void addPolygon (const ::polygon* poly)
    {
            // Polygon in die Liste hinzufügen

        polygon_.push_back (poly);
    }

    void renderAll (void)
    {
            // Alles sortieren!

        sortPolygons ();

            // Alle Polygone durchlaufen lassen

        for (polygon_it_ = polygon_.begin(); polygon_it_ != polygon_.end(); ++polygon_)
        {
                // Textur setzen, falls nötig (Hier sollte ein Texturmanager zum einsatz kommen!! Bringt Speed

            texturemanager::getInstance().setTexture ((*polygon_it_)->material_.texture_);

                // Dein Material setzen

            direct3d::getInstance().setMaterial ((*polygon_it_)->material_.material_);

                // Dein FVF setzen

            direct3d::getInstance().setFVF ((*polygon_it_)->fvf_);

            // VertexBuffer setzen, Indexbuffer setzen, Rendern --> Fertig!

            // [...]

        }

            // Manager für nächsten Frame fertigmachen! Ergo: alle Polygone rauswerfen

        polygon_.clear ();
    }

private:
        // Funktion zum sortieren der Polygone

    void sortPolygons (void)
    {
        // Hier nach Texturnamen sortieren.

    }

        // Das wichtigste vom Wichtigsten

    std::list<polygon*>           polygon_;    // Liste für Polygone

    std::list<polygon*>::iterator polygon_it_; // Iterator für Polygonliste

}










Benutzung:

     // Bei beginn des Programms ein Polygon erstellen

polygon poly (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_XXX, anzahl_vertices, anzahl_indices, 
              vertexpointer, indexpointer, ::material (irgendein_d3dmaterial, dein_texturobjekt));

// Hauptschleife

{
    if (sichtbar(poly))
        scenemanager::getInstance().add(&poly);

    scenemanager::getInstance().renderAll();
}


Recht easy und flott.

Nach FVF kann man auch sortieren, aber bei heutigen Grafikkarten macht das nicht mal mehr eine Nanosekunde aus, also das Wechseln das FVFs. Bei Shadern sieht das anders aus. Aber da sollte man testen was länger dauert: Texturen oder Shader. Jedoch sollte man als Faustregel annehmen das Texturen viel länger dauern als Shader. Daher erst Texturen sortieren und DANN erst Shader.

Geht halt flotter ;) So mach ich das jedenfalls in meinen Programmen und das geht mehr als Flott :D

- Patrick, der Manager-fan

Patrick

Alter Hase

Beiträge: 1 264

Wohnort: Düren

Beruf: Fachinformatiker für Anwendungsentwicklung

  • Private Nachricht senden

8

07.10.2005, 22:07

Achja und zum Thema sortieren von Texturnamen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <string>
#include <list>
#include <algorithm>

class person 
{ 
public:
    person (std::basic_string<wchar_t> value) : name(value) {};

    std::basic_string<wchar_t> name; 
};

bool compareByName(const person& left, const person& right) 
{ 
  return left.name < right.name; 
}

int main (void)
{
    std::list<person> pers;
    std::list<person>::iterator pers_it;

    pers.push_back (person(L"alfred"));
    pers.push_back (person(L"alfonso"));
    pers.push_back (person(L"jehova"));
    pers.push_back (person(L"peter"));
    pers.push_back (person(L"alfonso"));
    pers.push_back (person(L"bernd"));
    pers.push_back (person(L"pikaboo"));
    pers.push_back (person(L"peter"));
    pers.push_back (person(L"peter"));
    pers.push_back (person(L"alfonso"));
    pers.push_back (person(L"buddha"));
    pers.push_back (person(L"jehova"));
    pers.push_back (person(L"bernd"));
    pers.push_back (person(L"alfonso"));
 
    pers.sort(compareByName);

    for (pers_it = pers.begin(); pers_it != pers.end(); ++pers_it)
    {
        std::wcout <<  pers_it->name << std::endl;
    }
    
    std::cin.get();

    return 0;
}


Das ergebnis ist wunderschön sortiert :)

Osram

Alter Hase

Beiträge: 889

Wohnort: Weissenthurm

Beruf: SW Entwickler

  • Private Nachricht senden

9

07.10.2005, 22:19

Zitat von »"Patrick"«

Bei Grafikprogrammierung ist dieser ausschlaggebende Punkt nunmal der Bustransfer.


Ähm, welchen Bus meinst Du?

Übrigens solltet Ihr mal in der DX9 Doku das Kapitel "Accurate profiling Direct3D API Calls" ansehen und darin ganz nach unten scrollen. Da ist eine nette Tabelle 8)
"Games are algorithmic entertainment."

Osram

Alter Hase

Beiträge: 889

Wohnort: Weissenthurm

Beruf: SW Entwickler

  • Private Nachricht senden

10

07.10.2005, 22:26

Zitat


am besten nach std::basic_string<wchar_t> sortieren, Strings sind schneller zu vergleichen als riesige Pointerobjekte


Zahlen sind wesentlich schneller zu vergleichen.
"Games are algorithmic entertainment."

Werbeanzeige