Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

22.05.2010, 23:21

[Idee] Indoor + Outdoor Konzept

Ich habe nun schon eine weile überlegt wie ich Indoor und Outdoor Rendering effektiv für große Terrain, also welche die so richtig groß sind, vereinen könnte. Dabei wollte ich gern auf möglichst einfache Techniken zurück greifen, mit denen ich auch etwas Erfahrung habe. Spontan sind mit für Outdoor nur GeoMipMapping und für Indoor Portale/Sektoren eingefallen. Beide arbeiten sehr schnell und haben glaube ich von allen Techniken die geringste CPU Last. Ich habe versucht meine Gedanken nieder zu schreiben, und würde gerne von euch (die ihr ja etwas erfahrener seit als ich) Verbesserungsvoschläge hören, falls es denn welche gibt.

#####################################################################

Outdoor-Rendering: Das Outdoor-Rendering basiert auf einen dynamischen Quadtree. Wenn man sich in der Welt bewegt, werden dem Quadtree neue Nodes hinzugefügt und nicht mehr sichtbare Objekte einer Lösch-Liste hinzugefügt. Wenn ein Objekt länger als 20 Sekunden in dieser Löschliste ist, wird es vollständig entfernt.
Jeder Leaf des Quadtrees beinhaltet genau ein Terrain-Patch mit der Größe von 33x33 Vertices auf höchstem Detail. Die Detailreduzierung findet durch Geometrical-Mipmapping statt, dabei besteht ein Patch aus einem Vertex-Buffer mit der Größe von 33x33 Vertices und fünf Index-Buffern von denen vier stück die Seitlichen Übergänge zu anderen Detailstufen bilden und einer den Zentrum des Patches bildet.
Objekte wie Bäume oder Häuser werden den jeweiligen Nodes hinzugefügt, in denen sie sich befinden. Dabei können diese Objekte auch gleichzeitig in verschiedenen Nodes eingetragen werden, sofern sie beide Nodes kreuzen, da alle zu rendernden Objekte zuerst einer Render-Liste hinzugefügt werden, welche die Objekte abhängig der Texturen und Shader … sortiert und doppelte Objekte gleichzeitig ausfiltert.

Indoor-Rendering: Das Indoor-Rendering basiert auf einem Portal-System. Dabei dürfen die Portale nur convexen Polygonen bestehen. Jedes Portal hat zwei zugehörige Sektoren (Räume). Wenn ein Portal nur ein Sektor hat wird der andere nicht vorhandene Sektor als „Outdoor-Sektor“ angesehen, welche den dynamischen Quadtree repräsentiert. Die Sektoren selbst sollten ebenfalls convex sein, müssen es aber nicht, da ein Sektor auch mehreren Bounding-Boxes als grobes Kollisionsmodell haben kann.


Outdoor- und Indoor-Rendering: Höhlen können gebildet werden indem man ein Terrain-Patch einfach weg lässt und stattdessen einfach ein Model an dieser Stelle setzt. Dabei muss man darauf achten, dass Vertices des Modells und der benachbarten Patches immer übereinstimmen. Dies lässt sich sehr einfach realisieren, da man die Detail Übergänge an den Rändern der Patches locken kann. Beispielsweise kann man dem Patch XY den oberen Detailübergang auf die höchste Detailstufe locken. Diese wird sich niemals verändern, solange man diese nicht unlockt.

Wenn man nun auf dem Terrain steht und auf ein Kloster blickt, wird das Terrain erst gegen das View Frustum geclippt und anschließend alles was vom äußeren des Klosters sichtbar ist gerendert. Danach wird das Frustum an das Portal (Tür) des Klosters angepasst und das wird dann immer wiederholt im Kloster, bis alle sichtbaren Sektoren gefunden wurden.
Wenn man im Kloster steht und nach draußen blickt, funktioniert das ganze genauso. Es wird das Frustum an das Portal angepasst und damit wird dann das Terrain gecullt.

#####################################################################
Die größten Sorgen mache ich mir über das Indoor-System. Das mit den Portal und Sektoren ist schon gut, aber wie schauts dann mit Kollision aus. Estmal brächte ich eine Technik um überhaupt heraus zu finden in welchem Sektor ich mich befinde. Da würden mir nur Octrees einfallen. Dann müsste man noch exakte Kollision in Räumen haben. Dort würden mir Octrees oder BSP einfallen, wobei ich Octrees bevorzugen würde.

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

2

23.05.2010, 00:14

Musste gerade erstmal lachen, da das wirklich 90%ig mit dem übereinstimmt, wie ich es geplant habe, und zwar in allen Punkten :-).

Habe gerade nicht die Zeit zu schreiben, da ich heute noch was abschließen wollte, von daher mal kurz und knapp meine Differenzen:

Indoor-Rendering: Hier habe ich ausschließlich Rechtecke als Portale geplant, die bei z. Bsp. runden Türen, dann halt ggf. auch in der Wand stecken. Das hat schlicht den Vorteil, dass man die Objekte in dem Sektor, in den man hinein schaut, dann einfach gegen das aus "eigene Position -> Ecken des Rechtecks" entstehende View-Frustum cullen kann.

Outdoor: Hier hatte ich geplant, dass die Welt erst einmal in einzelne Zellen unterteilt wird (Quadtrees). Jede dieser Zellen hat eine Minimalqualität, so dass gewährleistet ist, dass bestimmte Dinge wie Gebäude, Treppen etc. nicht durch zu starkes LOD in der Landschaft versinken können. Zur Laufzeit wird dann ermittelt, welche der Zellen sich im Sichtbereich befinden und in einer XxX großen Matrix erst einmal gesammelt und deren Default-Qualitätslevel gesetzt. Anschließend werden die Qualitätslevel der einzelnen sichtbaren Zellen so erhöht, dass eine Zelle niemals mehr als 1 Level über einem ihrer sichtbaren Nachbarn liegen darf, so dass später die Ränder zu den Nachbarn gewährleistet ist, dass bei einer Kannte A -> B -> C in der höheren Auflösung durch einfaches ersetzen von B durch (A+C)/2.0 dieses dann an den niedriger aufgelösten Nachbarn passt. Nachdem die LOD-Level dann ermittelt sind, werden die Zellen, deren 3D-Geometrie-Daten sich verändern haben, entsprechend aktualisiert. Bei der Generierung wollte ich auf das recht bewährte Diamant-Gitter zurückgreifen. Bei flachen Regionen wollte ich für die Texturierung das typische XZ-Mapping nutzen, bei sehr steilen Flächen bin ich mir noch nicht ganz sicher, aber anstatt dessen dann je nach Normal-Vektor der Fläche via XY/ZY zu texturieren wäre zumindest ein Ansatz.

Bzgl. Kollision:
Ich werde Octtrees nehmen, gefolgt von Boundingbox/sphere, ggf. gefolgt von Ultra-Low-Poly-Version des Objektes.

LG
Alyx

3

23.05.2010, 00:43

Ich hatte auch erst an Rechteckigen Portalen gedacht, aber mich dann doch für convexe Portale jeglicher Art entschieden^^

Zitat

Das hat schlicht den Vorteil, dass man die Objekte in dem Sektor, in den man hinein schaut, dann einfach gegen das aus "eigene Position -> Ecken des Rechtecks" entstehende View-Frustum cullen kann.
Bei mir würde das in etwa genauso ablaufen. Vorerst werde ich einfach die ganzen Frustums sammeln. Also wenn nun im Camera Frustum ein Portal zu sehen ist, werden einfach die Planes des Portale anhand der Ecken und der Camera Position gebildet. Ob nun weitere Portale sichtbar sind mekrt man dann wenn ein Portal im letzten PortalFrustum als auch im CameraFrustum ist.

Zum testen reicht das erstmal, das ganze werde ich später dann noch optimieren.

Ich möchte halt die neuen Frustums immer so klein wie möglich halten, damit nicht unnötig eigentlich nicht sichtbare Sektoren gerendert werden.

Zum Terrain hatte ich mir eigentlich nochwas gedacht, um Indoor zu ermöglichen, und zwar das das Terrain praktisch aufgeklappt wird. Das Terrain ist ja in vielen kleineren Patches unterteilt. Nun kann ich ja einfach bei einem Patch an einer Seite die Vertices alle weiter nahc oben veschieben, und die vom angrenzenden Patch etwas weiter nach unten. Das würde einen gewollten Crack erzeugen, an deren Stelle man dann noch ein Höhleneingang platzieren könnte.

Was Kollision angeht, soll der Renderer nur mit einfachen BoundingVolumes arbeiten. Genaure Kollision, beispielsweise Spieler mit Umgebung, soll seperat stattfinden. Was mich halt noch grade ziehmlich nervt ist der Grundaufbau der Engine. Ich mein, soll ich jetzt einen DXWrapper benutzen, oder gleich direkt die dx10 Sachen benutzen. Ich möchte ja schließlich irgentwann mal fertig werden und nicht Jahrelang an der engine rumfummeln.

Eine ganz andere Sache ist wieder das Format für die Sektoren/Portale. Dort würde ich gerne auf etwas eigenes aufsetzen, weiß aber noch nicht ganz wie ich das am besten aufbauen sollte. Es soll von Hand bearbeitbar sein und möglichst übersichtlich. Ich hatte mir gedacht das ic mich ein wenig an die MD5 Syntax anlehne, das würde dann bei mir etwa so aussehen:

Quellcode

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
NumSectors = 1
NumPortals = 1

Material 0 {
    Texture0 = "Texture.tga"
    Texture1 = 0
    Texture2 = 0
    Texture3 = 0
    LayerMap = 0
}
    
// Mesh "NumVertes"
Mesh 13 {
    // Vert (VertId) (X) (Y) (Z) (Nx) (Ny) (Nz) (U) (V)
    Vert 0 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 1 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 2 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 3 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 4 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 5 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 6 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 7 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 8 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 9 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 10 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 11 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
    Vert 12 38.384 29.2 5.342 0.3847 0.463 0.273 0.12 0.33
}

// Sector (SectorId) (NumSubsets)
Sector 0 2 {
    // Subset (SubsetId) (NumTris) (Material)
    Subset 0 10 0 {
        Tri 0 27 382 38
        Tri 1 27 382 38
        Tri 2 27 382 38
        Tri 3 27 382 38
        Tri 4 27 382 38
        Tri 5 27 382 38
        Tri 6 27 382 38
        Tri 7 27 382 38
        Tri 8 27 382 38
        Tri 9 27 382 38
    }

    // Subset (SectorId) (NumTris) (Material)
    Subset 1 10 0 {
        Tri 0 27 382 38
        Tri 1 27 382 38
        Tri 2 27 382 38
        Tri 3 27 382 38
        Tri 4 27 382 38
        Tri 5 27 382 38
        Tri 6 27 382 38
        Tri 7 27 382 38
        Tri 8 27 382 38
        Tri 9 27 382 38
    }
}

// Portal (PortalId) (NumCorners) (AddedSector) (AddedSector)
// -1 als Sector bedeutet das es mit der Outdoor Szene gebunden ist
Portal 0 4 0 -1 {
    Corn 0 281.3 3994.2 384.21
    Corn 1 281.3 3994.2 384.21
    Corn 2 281.3 3994.2 384.21
    Corn 3 281.3 3994.2 384.21
}


Die Indoor Map dürfte in diesem Fall wohl nicht sehr groß sein. Wenn diese aber auch gestreamt werden sollte, kann man sie ja immernoch in mehreren Dateien aufteilen. Würde auch gerne ein bereits bestehendes Format benutzen, kenne aber leider keines. Versuch mal nach "Portal Format" zu googlen oder "Potal Map Format" ^^


Also mal ganz im ernst, ich möchte mal deine ICQ/MSN Nummer haben, zwei Köpfe mit ähnlichen Gedanken hehe xD

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »Potatoman« (23.05.2010, 11:08)


Beiträge: 774

Beruf: Student

  • Private Nachricht senden

4

23.05.2010, 11:58

Dein Outdoor-System erinnert mich auch ziemlich an das was ich bei Xrodon gemacht hab ^^ - Indoor gabs da nicht.
An was du aber vielleicht noch denken solltest, ist ob du wirklich immer alles im Speicher halten kannst - du sprachst ja von "richtig großem Terrain". Gegebennenfalls müsstest du dir dann "geometrical clipmaps" anschauen und andere Dinge was das Streaming anbelangt. Ich selbst hab da allerdings keine Erfahrung.

Ich bin selbst wieder ein wenig brüten über solche Dinge. Aber ich denke dieses Mal werde ich mir von Ogre3D helfen lassen und mich auf andere Dinge konzentrieren - auch wenn ich das mit dem Terrain, Renderaufteilung usw. unglaublich spannend und interessant finde.

5

23.05.2010, 12:23

Also ich bin auch sehr in dem Thema interessiert und ich denke, dass deine Vorgehensweise schon recht optimal ist. Was mich momentan am meisten interessiert ist, wie man so extrem riesige Terrains hinkriegt, wie z.B. in Crysis. Ich habe glaube ich irgendwo gehört, dass für die entfernten Hügel dann Sprites genommen werden, dann kommt das übliche LOD. Aber ich glaube kaum, dass das genügt um so riesige, nahezu perfekt aussehende Terrains hin zu bekommen. Und zusätzlich gibt es bei Crysis auch noch nette Indoor Levels. Vielleicht kennt ja jemand ein Paper oder ähnliches dazu.
Ich weiß es dauert viel zu lange, aber ich habe echt nur Pech. Habe mir heute mal eben im Zeigefinger Nerv und Sehne durchtrennt. Dennoch kann es nicht mehr all zu lange dauern mit dem Tutorial. Außerdem kamen auch noch Prüfungen und dergleichen dazwischen.
Klatscht die Hopper an die Wand, Deutschland ist ein Raverland! :D

6

23.05.2010, 13:10

Achja Crysis, wie oft hab ich die Maps im Qireframe angeschaut und Videos vom Editor gesehen.

Im prinziep baut Crysis auf Geometrical Mipmapping auf. Dieses LOD verfahren hat wohl mit abstand die geringste CPU Last. Ich habe noch eine Demo bei mir rum Schwirren, wo etwa 6 Km weites Terrain ohne Culling etc mit 60 FPS gerendert wird. Gee-Mipmapping ist wie ich finde eine der einfachsten LODs und hat das größte Potential. Außerdem läßt sich damit auch sehr gut Terrain streaming realisieren. Dabei hat man ein Quadtree, nur den RootNode. Der Root Node hat die größe des gesammten Terrain, beispielsweise 512 Km. Der Quadtree wird das rekursiv aufgebaut:


(Link)


Der Quadtree wird also Rückwärts aufgebaut. Wenn nun ein Terrain-Patch geladen wird, wird es einfach dem Quadtree hinzugefügt. Dabei werden dem Quadtree, falls nötig, neue Nodes hinzu gefügt. Dadurch kann das Terrain auf einem 32bit System schon sehr groß werden, und auch schnell geladen und gerendert werden. Der Speicherverbrauch des Quadtrees ist dabei wirklich sehr gering, vllt 2MB auf dem Ramspeicher.

Jeder Patch besteht bei mir aus 5 Elementen. 4 Seiten und das Zentrum:


(Link)


Das hat den Vorteil, dass es egal ist welche LOD Stufen aneinander liegen. Lod0 kann an lod5 anliegen. Dann wird einfach ein andere IndexBuffer an der Seite benutzt, der einen übergäng von lod0 zu lod5 ermöglicht.

Was das mit den Sprites angeht. Ich kenne bisher nur ein Spiel das dies eingebaut hat, und das ist Guildwars. Sehr schön sieht das wirklich nicht aus und ich kann mir gut vorstellen das dies eine morts Arbeit ist, sowas zu implementieren. Für Bäume und Büsche würde ich sowas schon eher anwenden!

Wenn du willst kann ich dir ja mal meine wirklich sehr unoptimierte Version schicken. Läuft aber sehr stabil und vor allem sehr schnell bei riesiger Sichtweite, und das auch noch im Wireframe mode XD

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

7

23.05.2010, 13:28

Ja gerne, dass würde mich sehr interessieren. Kannst es mir ja per eMail schicken: insane_@gmx.de
Und danke schonmal für die Erklärung! ;)
Ich weiß es dauert viel zu lange, aber ich habe echt nur Pech. Habe mir heute mal eben im Zeigefinger Nerv und Sehne durchtrennt. Dennoch kann es nicht mehr all zu lange dauern mit dem Tutorial. Außerdem kamen auch noch Prüfungen und dergleichen dazwischen.
Klatscht die Hopper an die Wand, Deutschland ist ein Raverland! :D

8

23.05.2010, 13:46

Ja habs grad raus gesucht, das ganze hab ich mir meinem Test Framework mal gemacht (sehr kaotisch, unübersichtlich), ich versuch das grad wieder zusammen zu friemeln xD

Jetzt nach dem zusammenfirmeln haben sich paar Grafikbugs eingeschlichen, ich denk ich werds einfach auf meinem aktuellen Projekt übertragen und dir dann schicken ;)

Hast du Vista/7 und ne DX10 Fähige Karte? Ansonsten mach ich das über den DX9 Renderer oder OpenGL.

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Potatoman« (23.05.2010, 13:53)


9

23.05.2010, 14:15

Jo meine Grafikkarte unterstützt DX 10 und habe Win7 mittlerweile. ;) Dass der Code chaotisch ist, ist ja nicht schlimm, es geht mir ja nur darum ein kleinen Überblick über deine verwendete Technik zu bekommen.
Ich weiß es dauert viel zu lange, aber ich habe echt nur Pech. Habe mir heute mal eben im Zeigefinger Nerv und Sehne durchtrennt. Dennoch kann es nicht mehr all zu lange dauern mit dem Tutorial. Außerdem kamen auch noch Prüfungen und dergleichen dazwischen.
Klatscht die Hopper an die Wand, Deutschland ist ein Raverland! :D

10

23.05.2010, 15:14

Ne das ist peinlich xD

Außerdem benutzt das ganze noch nicht diesen dynamischen Quadtree, und darauf baut das ganze ja schließlich auf ;)

Spätestens Morgen bekommst du ne Demo mit Code ;)

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Potatoman« (23.05.2010, 15:41)


Werbeanzeige