Seite 2 von 5
Re: [Projekt] Prozedurales Universum
Verfasst: 26.02.2014, 20:55
von Krishty
Die wesentlich einfachere Lösung (falls Direct3D 10 oder die entsprechende OpenGL-Version zur Verfügung stehen) sind übrigens Texture Arrays. Die funktionieren, wenn alle Texturen die selbe Größe haben (was bei dir total der Fall zu sein scheint) und sorgen für eine unabhängige Filterung der Texturen untereinander. Sie sind außerdem sehr einfach zu implementieren (keine Koordinaten manipulieren sondern einfach den Index der Textur im Array in die Vertices schreiben).
Re: [Projekt] Prozedurales Universum
Verfasst: 20.03.2014, 21:44
von sushbone
Bei dem Thema Texturkanten entfernen müsst ihr mir zu gegebenem Zeitpunkt nochmal helfen, ich kriegs noch nicht hin, das Problem habe ich zwar Verstanden, die Lösung(en) aber teils noch nicht :-)
Die Texturen stammen von einem TexturAtlas, jedes Plane besitzt die gleiche Anzahl an Vertices, jede Textur die gleiche Auflösung. Ich speichere alle Daten in Arrays (Vertice-Positionen, TriangleIndices, UV Koordinaten, Texturkoordinaten) bevor ich alles zum Mesh rendere.
Aber macht nichts, bei dem Themenbereich gibts genug Gebiete um mich auszutoben.
Daher habe ich das Thema beiseite gelegt und mich zunächst mal darum gekümmert ein einfaches Cockpit zu haben mit entsprechender Spaceship-Like Steuerung bei Schwerelosigkeit und ohne Atmosphäre. Man merkt direkt, Steuern ist fies im Weltraum mit einem Antrieb in nur eine Richtung. Ggf. muss ich das etwas vereinfachen so wie in anderen Weltraum-Spielen auch). Es gibt Freelook möglichkeit, sodaß ich das ganze einfach mit einer Oculus Rift kombinieren kann. Btw, letztere habe ich heute endlich geordert, nachdem endlich die Neuigkeit kam dass man die Oculus Rift Devkit V2 jetzt bestellen kann.
Ich suche noch ein richtig schönes X-Wing-ähnliches SpaceShip-Cockpit, hat einer von euch eine Idee wo ich ein entsprechendes Mesh herkriegen könnte?! Es muss noch nicht mal eines von einem XWing sein, hautpsache ein einigermaßen brauchbares 3D Cockpit. Ich bin kurz davor mich in Blender einzulernen, aber bis ich das hinkriege würde das sicher ewig dauern. Das bereitet mir wirklich Kopfzerbrechen. Selbst im Unity3D Assetstore findet man kaum etwas dazu.
Naja, aber dann jedenfalls hab ich mir eine Weile über das Genaugkeitsproblem den Kopf zerbrochen, und ich denke ich greife jetzt zwei Strategien auf um das Problem in den Griff zu kriegen:
1) Floating Origin
Das Problem in einem Szenario wo die Kamera durch ein zentrisches (0,0,0) floatbasiertes Koordinatensystem bewegt wird ist ja die Ungenauigkeit die bei entsprechend größerer Distanz zum Nullpunkt auftritt. Je größer die Entfernung, umso drastischer wird die Ungenauigkeit. Will ich bei der Einheit 1 unit = 1 Meter bleiben, so tritt die Ungenauigkeit leider schon bei einigen hundert Kilometern auf. Problematisch für ein Szenario wo man mehrere Planeten rendern und vor allem die Kamera dann dorthin reisen lassen möchte. Daher greife ich jetzt auf Floating Origin zurück. Die Kamera wird ab einer gewissen Distanz (in meinem Fall 6000 Units (=6 Kilometer)) wieder auf den Origin (0,0,0) zurückgesetzt, gleichzeitig aber alle Objekte der Szene gleichermaßen verschoben. Überspitzt bewegt sich nicht die Kamera fort, sondern die Welt drum herum. So bleibt die höchste Genauigkeit immer bei der Kamera, und sie fällt kontinuierlich erst bei größerer Entfernung ab - unproblematisch, weil dort die Ungenaugkeit eine geringfügigere Rolle spielt, da kaum noch sichtbar.
Durch Floating Origin geht allerdings die Information verloren "wo" sich die Kamera/Spieler gerade befindet, eben deswegen weil die Kamera nie den Wertebereich +-6000 in X,Y,Z Richtung verlassen kann. Es hilft also nicht alleine zu gucken wo sich die Kamera gerade befindet. Daher habe ich ein übergeordnetes Koordinatensystem eingeführt, in welchem ich laufend ermittle wo sich der Spieler gerade "theoretisch" befindet bzw. "befinden würde". Floating Origin kann dann ruhig auf die Kamera einfluss nehmen, ich merke mir woanders wo der Spieler gerade ist. Man sieht dies in dem Video ganz gut (bei 300 Units/Metern greift das Event, ich habs etwas früher eintreten lassen für das Video, und die Kamera wird zurückgesetzt, das eigene Koordinatensystem läuft weiter). Das gab mir dann auch die Möglichkeit größere Skalen einzuführen. In meinem Fall verwendet ich ein System welches auch wieder den Nullpunkt als Bezugspunkt nimmt, aber entsprechende Größenordnungen anbietet: Meter -> Kilometer -> Astronische Einheit -> Lichtjahr.
[youtube]Jw8prb4Yp_8[/youtube]
Erreicht der Meter-Vektor in X,Y oder Z eine Distanz von 1000, so wird der Kilometer-Vektor entsprechend um 1 erhöht und der Meter-Vektor entsprechend wieder herabgesetzt. Die Werte der Vekoren sind also in Kombination zu sehen. Gleiches mit der Astronomischen Einheit AU (1AU = 149597871 Kilometer) und Lichtjahre (1LJ = 63241.077 AE). So kann ich den Spieler durch ein extrem großes System wandern lassen. Die Idee ist nun basierend auf dieser Positionsangabe des Spielers Planeten zu generieren oder zu entfernen. Vermutlich werde ich das in einem zweiten Thread machen und bei jedem AE Wechsel eine Prüfung durchführen obs neue Planeten zu rendern gibt. Ich denke ich muss es nicht jeden Meter oder Kilometer machen, da hat sich im kosmischen Maßstab noch nicht allzuviel getan. 1AE entspricht der Entfernung Erde zu Sonne. Meine Idee ist, die Koordinaten um den Spieler herum in einem bestimmten Raster in ein SimplexNoise Algorithmus reinzuwerfen, und anhang des Ergebnis zu entscheiden ob ich an der jeweiligen Koordinate einen Planeten rendere oder nicht. Damit entsteht keine Gleichverteilung der Planeten, und vor allem ist sie nicht zufällig. Die darauffolgende Positionierung der Planeten in der Floating Origin Szene Szene wird ggf. nochmal tricky, aber an sich sollte ich mit der jeweiligen Planetenkoordinate, der berechneten Spielerkoordinate und der Position der Kamera in der FloatingOrigin Szene alle Infos haben um die richtigen Koordinaten für den Planeten in der Szene im "ScaledSpace" zu finden.
2) Unterschiedliche Skalen.
Will ich weit entfernte Objekte in Kombination mit nahen zeichnen so habe ich aber dennoch das Problem das ich einen extrem hohen Wertebereich bräuchte um alles im gleichen Maßstab zu rendern. Daher arbeite ich mich gerade in einen "Trick" ein der auch bei Kerbal Space Program zum Einsatz kam.
Mehrere Subscenes bzw. "Spaces", jeder einer eigenen Kamera. Jeder Space stellt aber die Szene in unterschiedlicher Skalierung dar (1:1, 10.000:1), und jeder Space und Kamera ist entweder und ausschließlich nur für weit entfernte oder Nahe Objekte zuständig.
InternalSpace = Raumschiffkapsel
LocalSpace = Naher Bereich, 1:1, die LocalSpace Kamera bewegt sich mit normaler Geschwindigkeit
ScaledSpace = Entfernter Bereich, Skalierung 10.000:1, d.h. alle Objekte sind um Faktor 10.000 kleinskaliert, ebenso die Enternungen untereinander und zur Kamera, ebenso die Geschwindigkeit der Kamera.
Rendert man alles zusammen so sieht man sowohl sehr nahe detailierte Objekte also auch weit entfernte. Der Trick fällt nicht auf, da man sich zu den weit entfernten Objekten langsamer bewegt. Es entsteht dadurch der Eindruck räumlicher Tiefe. Schiweirig ist die Kameras zu synchroniseren (da bin ich gerade dran), sowie die Übergänge von Planeten von LocalSpace in in ScaledSpace und vice versa hinzukriegen. Ich versuche gerade herauszufinden wie das die Entwickler in Kerbal Space Program genau gemacht haben, und was der grundsätzliche richtige Ansatz ist das in Unity umzusetzen (mehrere Szenen vs. eine Szene in unterschiedlichen Layern).
Aber in Kombination mit beiden Varianten sollte man das Thema Genaugkeit und große Skalen ganz gut in den Griff kriegen.
Punkt 2) ist aktuell meine Hauptbaustelle.
@Krishty:
Deine Sternerenderings in deinem Thread "Sterne rendern" sahen fantastisch aus. Wenn ich auf der Basis am Ende optisch irgendwo nur Ansatzweise ankomme bin ich echt happy.
Re: [Projekt] Prozedurales Universum
Verfasst: 23.03.2014, 17:58
von sushbone
Volumetrische Nebel (mittels einer Kombination aus 4 ParticleEmittern).
Im Moment habe ich gezielt einen zusammengebaut und mit den Emitter-Parametern gespielt, um ein vernuenftiges Ergebnis zu erhalten. Er muss noch etwas dunkler werden, ich hab gemerkt um so kitschiger. :-)
Idee ist die Nebel jetzt ebenso zu generieren wie Planeten oder Sonne, d.h. in Abhängigkeit der Spielerposition prüfe ich die umliegenden Gebiete und werfe die Koordinaten in ein SimplexNoise rein, das Ergebnis entscheidet ob und was gerendert wird. Ich greife dabei voraussichtlich immer auf das gleiche Grundgerüst aus, d.h. 4-5 Emitter, die aber jeweils zufällig ausgerichtet, skaliert, rotiert, sowie unterschiedliche Farb- und Alphawerte erhalten.
Interessant wird es wenn man einen der Emitter auf schwarze Farbwerte setzt. Dann entstehen leicht schemenhafte Gebiete. Ich habe einen mal an den Anfangspunkt gesetzt wo das eigene Raumschiff und der Carrier ist. Das wirkt dann schon etwas unheimlich wenn man hindurchfliegt.
Der Nebel ist in der Szene extrem groß, es dauert selbst mit hoher Geschwindigkeit eine Ewigkeit um ihn zu durchqueren.
Re: [Projekt] Prozedurales Universum
Verfasst: 10.04.2014, 20:48
von sushbone
Es geht Schritt für Schritt voran. Ich habe endlich ein schönes Cockpit, das macht das ganze schonmal wesentlich ansehnlicher.
Weiterhin habe ich in einer rohen Fassung jetzt die unterschiedlich dimensionierten Spaces (StellarSpace, ScaledSpace, LocalSpace, InternalSpace) mithilfe separater Layer gebaut. Klappt alles, alle haben separate Floating Origin Konfigurationen für separate Kameras die sich unterschiedlich schnell bewegen. Soweit so gut.
Im Moment arbeite ich an der regelmäßigen Positionierung von Asteroiden in einem separaten Thread. Meine Strategie: Immer dann wenn der Spieler eine bestimmte Distanz (aktuell einen Kilometer) zurückgelegt hat prüfe ich nach einem bestimmten Raster (bzw. festen Steps) alle umliegenden X,Y,Z Koordinaten um das Raumschiff herum ab. Jede Koordinate wird in einen SimplexNoise geworfen, kommt ein Noise Value in einer bestimmten Range heraus, so zeichne ich einen Asteroiden (sofern an dieser Koordinate nicht schon einer ist), ansonsten nicht. Ich speichere dabei die Asteroiden und deren jeweilige Koordinaten in einer Liste.
Klappt, allerdings bin ich auf ein Problem gestoßen bei dem sich gerade mein Hirn windet, ggf. wisst ihr eine einfache Lösung.
Anbei mein Bruteforce-Ansatz (als Grafik, per Code Tag wurde es unübersichtlich):
Das Problem: Nach jedem Kilometer prüfe ich zu einem Großteil Koordinaten ab die ich schoneinmal geprüft habe (unten zweidimensional illustriert). Das ist vor dem Hintergrund dass ich in drei Dimensionen (quasi einem Würfel) prüfe eine Menge unnötiger SimplexNoise-Aufrufe, die ich unbedingt vermeiden muss. Mein Ziel muss sein jeweils immer nur den in der Grafik grün markierten Bereich in einem Lauf zu prüfen.
Habt ihr eine Idee wie ich das am geschicktesten mache. Meine Idee wäre anhand der alten und neuen Position (jeweils Vector3(x,y,z) Werte) wo sich das Raumschiff befindet die X,Y,Z min/max Bereiche der Schleifen einzuschränken. Aber ich komme nicht drauf wie ich das am sinnvollsten mache?
Re: [Projekt] Prozedurales Universum
Verfasst: 11.04.2014, 09:42
von joeydee
Hier ein paar mögliche Ansätze, vielleicht ist ja was dabei:
Generell kannst du per Positionsschlüssel Werte cachen und nach Zeit, Entfernung oder Cache-Größe wieder verwerfen.
Berechnen des neuen Bereichs: diff=newVec-oldVec
In deinem Beispiel oben wäre diff.x=0 und diff.y=1
Heißt, du musst eine neue Ebene (Zeile) in Richtung +y in Entfernung r=2 vom Spieler mit der Stärke 1 berechnen.
Wenn gleichzeitig in mehr als eine Richtung gewechselt wird (mehr als eine Komponente !=0 ist), werden dabei Kanten (3D-Fall) und Ecken doppelt berechnet. Entweder in Kauf nehmen, Cachen oder per Fallunterscheidung die Bereiche anpassen. Im Prinzip ist das Ganze eine Boolean-Operation zweier AABBs (Differenz), es können bis zu 3 neue AABBs herauskommen die dir sagen, von wo bis wo du neue Werte berechnen musst. Vielleicht gibts da für Unity ja sogar ne Bibliothek, die dir die entsprechenden Bereiche fertig berechnen kann?
Wenn du deine Schleifen über das ganze aktuelle Gebiet komplett behalten willst/musst und nur neue Noise-Berechnungen an sich ausschließen willst, berechne vorher einfach die Schnittmenge der beiden AABBs (das ist die einfachere Bool-Operation gegenüber der Differenz, da nur eine einzige oder keine AABB als Ergebnis herauskommen kann), und berechne in den Schleifen nur dann einen Noise-Wert neu, wenn er NICHT aus dieser Schnittmenge stammt.
Im Prinzip kannst du das ganze dann auch wie ein Bitmap beim Scrollen ansehen und entsprechende Blitting-Funktionen schreiben (Umkopieren der Werte, neue Randpixel abfangen und neu berechnen).
Alternativ kannst du auch die Noisewerte in einem unsortierten 1D-Array zur Verfügung stellen, aber jedes Objekt (Zelle) hält neben dem Wert (Implementierung als Getter) auch die Position (Implementierung als Setter: wenn sich die Position von der alten unterscheidet, wird der Wert neu berechnet). Bei einem Rasterwechsel gehst du zuerst die aktuelle Anzeigeliste durch und wirfst zu weit entfernte Objekte raus. Dann gehst du das 1D-Array durch: wenn die Position einer Zelle in irgendeiner Richtung zu weit vom Spieler entfernt ist, wird deren Position neu gesetzt (um die Rasterweite in die entsprechende Richtung verschoben); dadurch wird der Noise-Wert dieser Zelle neu berechnet und es kann bei Bedarf ein neues Objekt in die Anzeigeliste gebracht werden. Natürlich wird zuerst die komplette neue Position der Zelle berechnet und dann nur einmal an den Setter übergeben, sonst liefe ja wieder einiges doppelt.
Ich denke, ich würde es mal mit letzterem, später evtl. noch kombiniert mit einem Cache, versuchen.
Halte uns auf dem Laufenden, ich finde dein Projekt klasse! :-)
Re: [Projekt] Prozedurales Universum
Verfasst: 13.04.2014, 11:12
von sushbone
Hi joeydee,
vielen Dank für die vielen Denkansätze. Und es hat mir weitergeholfen!
Eine Schleife über das komplette Gebiet war nicht notwendig, daher habe ich es zunächst mit der ersten Strategie, dem Einschränken des Prüfbereichs probiert. Und klappt :D . Ich musste sogar kaum eine Fallunterscheidung machen, durch einige wenige IF Operationen für die Wertebereiche die den zu prüfenden Bereich auf den notwendigen eingrenzen prüfe ich jetzt entweder den kompletten Bereich (wenn gar keine Differenz vorhanden ist (notwendig beim ersten Lauf) bzw. die Differenz zu groß ist (notwendig wenn ich mal z.B. Wurmlöcher mache ;-) ), oder eben nur den Differenzbereich zum vorherigen Lauf. Klappt, die Calls gehen ganz signifikant nach unten 8-). Siehe dazu das Video. Der erste Call war das komplette Gebiet, die folgenden dann nur noch die Differenz.
[youtube]ToT9a38ysCI[/youtube]
Daneben habe ich festgestellt, die Strategie auf SimplexNoise für die Positionierung von Objekten zu setzen klappt echt ganz gut. Ich bin mal eine zeitlang schneller durch die Gegend geflogen, und gelegentlich stößt man dann auf Formationen/Streifen von Asteroiden.
Ich denke ich werde das noch mit deinem dritten Ansatz kombinieren, nämlich die NoiseWerte in Kombination mit der Position alle zwischenzuspeichern. Denn letztlich werde ich den Noise potentiell auch noch für andere Dinge brauchen. In einem Video zu Star Citizen habe ich gesehen dass die Designer dort noch neben Asteroiden und Partikeln lokalen Nebel/Dunst erzeugen. Das ist zwar warscheinlich völlig an der Realität vorbei, erzeugt aber eine wesentlich intensivere "Dichte" und Fluggefühl.
D.h. mein nächstes Todo ist den mit deiner Hilfe jetzt optimierten Thread so umzugestalten dass er nur noch für das kontinuierliche Aktualisieren eines Noise/Positions Array verantwortlich ist (ggf. wird er dadurch nochmal einen kleinen Tick schneller), und separate Funktionen (warscheinlich auch wieder gethreaded) arbeiten dann nur noch auf dieser Liste um Asteroiden oder Dunst zu erzeugen.
Danach kommt dann das vollständig per Regelwerk prozedurale generieren von Nebeln (den in dem Video habe ich noch gezielt erzeugt um erstmal zu prüfen welche Parameter ich brauche), und dann muss ich mir Gedanken machen wie ich den Spieler auch mal schneller durch das Universum bewegen kann, sonst dauert der Flug immer doch schon sehr lange :)
Re: [Projekt] Prozedurales Universum
Verfasst: 18.04.2014, 17:45
von sushbone
So die proceduralen Nebel sind erstmal fertig. Noch etwas zu intensiv in der Farbe vielleicht, aber erstmal lass' ichs so.
Noch gilt es einen Bug bei dem Positionieren der Asteroiden zu beseitigen, danach wird die Steuerung für einen Xbox360 Kontroller angepasst.
Danach experimentiere ich mal mit sowas wie einem Hyperspeed Effekt um den Spieler schneller durchs Universum bewegen zu können. Mal schauen wie gut das in Kombination mit dem eigenen Koordinatensystem funktioniert und wie robust dieses und der Floating Origin ist wenn ich den Spieler sehr schnell durch die Welt bewege.
Wenn das fertig ist baue ich die Quadtree Planeten wieder ein. Bin gespannt wie alles in Kombination wirkt.
Re: [Projekt] Prozedurales Universum
Verfasst: 18.04.2014, 18:44
von xq
Sieht gut aus, erinnert mich an X²: The Threat. Bin gespannt auf die Planeten!
Re: [Projekt] Prozedurales Universum
Verfasst: 23.04.2014, 16:18
von sushbone
Experimente mit lokalem Dunst/Staub, Durchflug und Verlassen eines mittelstarken Bereichs
Der Effekt ist ortsabhängig und tritt nur in bestimmten Bereichen im Universum auf und hat bestimmte Intensivitäten (Unschärfe/Farbbeinflussung umliegender Objekte, Staubpartikel, Dichte und resultierende Dunkelheit im Cockpit).
Was ich gerne noch hinkriegen würde ist ein Flare/Halo-Effekt der Lichtquellen wenn man sich im Dunst/Staub befindet. Da muss ich aber erstmal rauskriegen wie....
[youtube]XHQHyA30TVQ[/youtube]
Re: [Projekt] Prozedurales Universum
Verfasst: 10.08.2014, 20:49
von sushbone
Lange Zeitg war es relativ ruhig um mein kleines Projekt gewesen, ich habe aber nicht aufgegeben.
Hintergrund war letztlich, dass sich nach einigen Hinweis Mails von OculusVR abzeichnete dass die Oculus Rift DK2 bald geliefert werden würde. Entsprechend stand ich vor der Frage wie es weitergeht.
Unity3D Pro, Unreal Engine 4 mit nativem OR Support, oder CryEngine (zwar kein OR nativer Support, aber irgendwie hinfrickelbar).
Die Unreal Engine war die einfachste und naheliegendste Variante um die Rift zu nutzen, also habe ich ein wenig Zeit damit verbracht mir die Engine mal anzuschauen. Zu gucken ob sie mir liegt und vor allem ob ich damit ähnlich gut prozeduralen Weltraum-Content erzeugen kann.
Das hat mich ein paar Wochen gekostet, und ich wurde nicht warm mit UE4. Die Blueprints finde ich grausig, und es scheint nach wie vor seine Einschränkungen zu haben bis auf Vertices/Triangles Ebene seine Meshes manuell zu generieren. Noch dazu habe ich keinen vernünftigen Weg gefunden Floating Origin zu implementieren, was ich für meine Zwecke ja brauche. Somit habe ich relativ schnell die Geduld verloren. Und bleibe jetzt letztlich bei Unity3D. So kann ich auch mit dem bisher gebauten weitermachen.
Die Oculus Rift kommt jetzt laut UPS morgen :D :D :D , und ich beginne jetzt nochmal "from-the-scratch" alles zu bauen:
a) weil ich mit der Generierung der Weltraum Inhalte nicht wirklich resourcenschonend gearbeitet habe, dazu gleich mehr.
b) weil die Asteroiden (die ich NICHT prozedural generiere, das halte ich für overkill, sondern nur prozedural verteilen will) einige Fehler hatten was das UV Mapping und die Texturierung betrifft und nicht wirklich gut waren
c) weil ich damit rechne ohnehin einige Kamera-Settings neu machen zu müssen wenn ich die Oculus Rift nutze.
Abgesehen davon, die knackigen Sachen (Floating Origin, Berechnung der Position der Objekte in einem Floating Origin setting) aus dem vorherigen Projekt waren ohnehin nicht viel Code und die kann ich direkt wieder übernehmen.
D.h. bis die Rift da ist fange ich jetzt an mich nochmal neu um die Asteroiden zu kümmern. Dank Pro mit richtigem LOD, und somit ist es mir jetzt auch möglich sie richtig schön detailiert zu machen. Die Fehler die ich in Blender gemacht hatte hab ich gefunden, hat mich ein paar Blender Tutorial gekostet :-), und nun sehen die Asteroiden amtlich aus *freu*.
Jetzt will ich mich an das prozedurale Verteilen der Asteroiden machen. Da müsst ihr mir nochmal helfen. Mein erster Ansatz war ja, kontinuierlich die 3D Koordinaten um mein Raumschiff herum in einen Simplex Noise zu werfen und am jeweiligen Ergebnis zu entscheiden ob ein Asteroid gezeichnet werden soll oder nicht. Das hat zwar grundsätzlich funktioniert weil es eine glaubhafte Verteilung der Asteroiden ergab, mal dicht, mal weniger dicht. Problem ist aber zum einen, dass ich brutal viele Simplex Noise aufrufe machen musste. Zum anderen ist der Algorithmus bei dem ich versuche zu vermeiden Koordinaten mehrfach zu prüfen bei hohen Geschwindigkeiten fehleranfällig gewesen. Daher suche ich jetzt nach einem Algorithmus der mir direkt mit einem Seed Koordinaten ausspuckt wo ich die Asteroiden platzieren muss. Mir schwebt da soetwas in der Richtung der "Strange Attractor" Algorithmen vor.
Nur dass ich eben nicht solche erkennbare Wirbel-Formationen (siehe ganz unten) brauche, Strange Attactors sind ja eher für Nebel geeignet in meinem Fall, sondern mehr "Haufen" von mal dichter mal weniger dichter Verteilung von Punkten.
Meine Idee ist in bestimmten Abständen, sagen wir alle "100.000 Kilometer", anhand der aktuellen Position mittels einem Simplex Noise Aufruf einen Seed zu ermitteln, und den dann in einen solchen Algorithmus zur Verteilung von Punkten hineinzuwerfen, um dann innerhalb dieses Radius die Asteroiden zu verteilen.
Habt ihr eine Idee in welche Richtung von Algorithmen ich da gehen könnte?
Re: [Projekt] Prozedurales Universum
Verfasst: 29.11.2014, 18:42
von sushbone
Ich bin gerade wieder an den prozeduralen Planeten dran, nachdem ich an die wichtigsten Punkte (double precision für mein Koordinatensystem und jetzt frame velocity für sehr hohe Geschwindigkeiten) einen Haken dranmachen konnte.
Die Planeten werden wieder mithilfe einer Cubesphere generiert, jede Seite ist in einem Quadtree gespeichert [=6 Quadtrees]. Also selber approach wie bei meinem ersten Versuch. Generierung von Planeten und Split und Merge mit erneutem Rendern der Planes funktioniert prinzipiell.
Ich möchte diesen Quadtree allerdings nun regelmäßig parsen und auf Basis der Distanz Kamera zum jeweiligen Quadtree Node (ergo zur Mitte der Plane) Split bzw. Merge events auslösen.
Wie würdet ihr das bewerkstellen? Ich dachte erst daran wieder per rekursiver Funktion durch den Quadtree zu gehen. Zum einen aber habe ich das Problem dass ich gerne eine IEnumerator Funktion verwenden will um per yield return die Framerate nicht zu sehr auszubremsen wenn ich den Tree parse (die Laufzeit hatte mir in meiner ersten Implementierung Probleme gemacht). Zum anderen habe ich hier und da gelesen dass im rekusiven Falle viel Memory beansprucht wird und dass das dementsprechend nicht zu empfehlen wäre (obgleich ich es immernoch für am "elegantesten halte". Wie würdet ihr das lösen?
UPDATE:
So ich habs nun doch wieder nach dem rekursiven Ansatz gemacht und erstmal auf CoRoutinen in Unity verzichtet. Bis jetzt laeuft es fluessig Framerate bleibt überraschenderweise bei angenehmen 65-70fps bei einer Überfluggeschwindigkeit von ca. 1000km/h. Allerdings verschiebe ich die Vertices noch nicht per Simplex Noise, generiere noch keine dynamische Textur und gehe noch nicht allzuzu tief in den Quadtree runter (bislang 9 Level getestet). Wird also sicherlich noch deutlich langsamer werden. Auf der anderen Seite nutze ich noch kein Culling wo wieder was rauszuholen ist, und kann immerhin das Parsen der 6 Quadtrees pro Cubeseite recht leicht separieren. Mal abwarten wo ich am Ende mit der Performance lande.
Das Problem der unterschiedlichen LOD Stufen nebeneinanderliegender Planes ignoriere ich jetzt erstmal ;). Worüber ich froh bin ist dass das ganze soweit einwandfrei in dem neuen Setting mit Floating Origin und dem neuen Koordinatensystem funktioniert. Ich kann jetzt eine procedurale Cubesphere erzeugen die ungefähr 150 mal die Größe der Erde hat, gezielt irgendwo platzieren und in mehrfacher Lichgeschwindigkeit dran vorbeifliegen.
UPDATE2:
50-60 fps wenns mit 100km/h über den Planeten geht bis quadtree Evel 16 runter. Sieht gut aus. Jetzt testen wir mal Simplex Noise, das wird sicher teuer was die Performance angeht.
Re: [Projekt] Prozedurales Universum
Verfasst: 01.12.2014, 20:53
von sushbone
Es war zu befürchten, bei einer schnellen Testimplementierung von Simplex Noise aufrufen zum Versetzen der vertices (und dann später auch für das Texturing) geht die Performance deutlichst in die Knie.
Das ist definitiv der Bottleneck. Mal sehen ob es durch Culling (Horizon und/oder Frustum) und ggf. intelligente Nutzung von IEnumerator Cooperationen besser wird. Habe mal im Unity Forum nachgefragt was man hier typischerweise machen würde und ob Coroutinen ein Ausweg sind.
Ich fürchte aber ich komme um eine Vertice-Precalulcation-Queue in einem separaten Thread vor dem Rendern in einem Unity3D Update() Thread nicht drum herum. Das hatte ich gehofft zu vermeiden, denn dann gehen die Problem ggf wieder los mit kurzen Löchern in der Oberfläche wenn noch nicht alle Children Planes gleichzeitig berechnet sind und gerendert werden können, oder ich wieder Elemente im Quadtree lösche die sich noch in der Queue zum Vorberechnen finden.
Mal gucken ggf. hat jemand im Unity Forum den anderen entscheidenden Vorschlag mithilfe von coroutinen...
Re: [Projekt] Prozedurales Universum
Verfasst: 03.12.2014, 13:18
von joeydee
Ich hatte mich vor Jahren auch mit prozeduralen Planeten und Landschaften beschäftigt, aber aus Zeitgründen nicht mehr weiterverfolgt.
Vielleicht habe ich für die Höhendaten-Erzeugung einen Ansatz. Einzelne Noise-Aufrufe um an die Höhendaten zu kommen halte ich generell für zu teuer. Zumal man für einigermaßen interessante Landschaften irgendwann mehrere komplexe Noisefunktionen überblenden müsste.
Kannst du in Unity Texturdaten im Vertexshader nutzen? Displacement-Mapping sozusagen? Dann würde ich die Textureinheit nutzen, um zusammenliegende Höhendaten parallel aus mehreren vorberechneten Texturen on-the-fly zu errechnen. Statt jedem Vertex einen einzelnen Noise-Aufruf spendieren zu müssen, beschränkt sich das dann auf Textur-Lookups. Und eine Texturgrundlage hättest du dann auch gleich.
Vorberechnete Texturen heißt nicht, das alles gleich aussieht - im Gegenteil, das sieht am Ende sogar abwechslungsreicher aus als Noise-Funktionen.
Bildlich gesprochen wäre das wie bei einem (statischen) Partikelsystem, um das Standbild einer komplexen Rauchwolke aus einer (oder mehreren) relativ simplen Textur zu erzeugen. Landschaften bzw. ihre Höhendaten sind ja auch nur "Wolken", und dass Wolken aus Partikelsystemen schon mit einfachsten Mitteln alles andere als gestempelt aussehen, dürfte bekannt sein.
Dann das System mit LOD-Charakter versehen, um jeweils lokal kleinere Detailtexturen über neue Emitter einzublenden. Sämtliche Emitter und ihre Partikel werden einfach durch Pseudorandom reproduzierbar auf einer Kugelschale platziert (ähnliches hast du ja schon gemacht), die gerade benötigte Texturberechnung für den Vertex-Lookup erfolgt dann immer aus dem Kugelmittelpunkt.
Ich hatte das leider nie mit LOD ausprogrammiert, kann also nicht sagen was dich da im Detail erwartet.
Die Landschaftserzeugung nach diesem Prinzip funktioniert aber definitiv. Anbei ein Screenshot aus einem älteren Projekt, wo man das Ergebnis anhand der Textur (das war ganz einfach die eingefärbte Heightmap) zumindest erahnen kann.
Evtl. ist der Ansatz brauchbar?
Re: [Projekt] Prozedurales Universum
Verfasst: 01.01.2015, 16:47
von sushbone
Hi joeydee,
danke für den Denkanstoß. Ich habe mein Quadtree Parsing jetzt nochmal umgebaut und optimiert, es passiert jetzt das meiste in einem eigenen Thread (Vertices, Noise und Texturdaten vorberechnen), per Status weiß der Mainthread dann wann er die vorbereiteten Daten aufgreifen und eine Plane rendern kann. Kein Stottern bzw. Frameeinbrüche mehr, soweit so gut, darauf kann ich auf jedenfall aufbauen.
Das mit den Höhendaten für die Vertices (und am Ende auch Texturen) ist in der Tat so eine Sache. Wie du sagst, für einigermaßen interessante Landschaften brauchts schon einige Oktaven. Ich nutze FBM und gehe aktuell von 2 bis ca. 20 Oktaven runter je nach erforderlichem Detailgrad/Flughöhe), nutze die Calls aber immerhin gleichzeitig für Texturen (z.B. 128x128) und greife aus dem Raster die entsprechenden Vertices (z.B. 32x32) Höhendaten raus. Das sind in der Tat dennoch viele Noise Calls (eben 128x128 pro Plane), im Moment gehts noch mit der Performance, sodaß ich noch unschlüssig bin wie ich weitermachen werde, das Ergebnis der Oberflächenstruktur gefällt mir fürs erste. Aber sollte ich soweit kommen dass ich das ganze nochmal soweit pimpen will dass Flussbetten und so dazu kommen kanns in der Tat ggf. zu lange dauern, es ist wie gesagt jetzt schon grenzwertig. Ich muss jetzt nochmal das Horizon Culling implementieren (ich finde die Webseite nicht mehr die das ganz gut erläutert hatte, Mist, da muss ich mich nochmal durch meinen alten Code (der nicht einwandfrei funktionierte) wühlen) und gucken wo ich dann mit der Performance stehen. Ich könnte mir da ggf. auch eine Kombination auf Noise und Texturen für das Abgreifen der Höhendaten vorstellen. Mal sehen. Im Moment komme ich im Tree ca. bis Nodebene 20 Runter dann kommt Unity3d und die Performance ins Trudeln. Da ich ja schon bis auf einen hohen Detailgrad der Oberfläche runter will, brauchts da noch viel Optimierng.
Frustum Culling nutze ich bereits um im nicht sichtbaren Bereich wieder auf gröberes LOD zu gehen, das alleine konnte mich aber noch nicht überzeugen. Ich glaube aus Horizon Culling kann ich mehr raussholen.
Die nächsten Baustellen sind jetzt erstmal:
1) Horizon Culling (dringend) und Pimpen der Performance, ggf. dann in der Tat einen Wechsel der Strategie für die Höhendaten.
2) Irgendwie mit den sich wiederholenden Patterns der Textur umgehen, die ich von nem Atlas abgreife. Da ich z.b. die Grastextur einmal abgreife und dann sich wiederholend über eine Grasfläche spanne sieht man die Wiederholung sehr deutlich, vor allem auch bei niedrigem LOD (= hoher Flughöhe). Vielleicht sollte ich mehre TexturAtlasse verwenden, wo die gröberen für niedriges LOD weniger Details haben.
3) Eliminieren meines alten Problems, Texturkanten durch das Filtering. Schrompf und Krishty hatten ja freundlicherweise schon Hilfestellungen gegeben, aber noch habe ich nicht geblickt wie ich das lösen kann.
4) Wasseroberfläche. Im Moment sind die Texturen, wenn noise als Ergebnis 0 (Wasserlevel) ausspuckt einfach knallblau. Nicht schön :-). Muss besser werden, mal sehen wie.
5) Planetatmosphäre, Wolken.
6) Optimieren der Flugsteuerung. Im Moment verhält sich das Raumschiff noch physikalisch korrekt mithilfe der Unity3D Engine, d.h. ein Raumschiff lässt sich unabhängig der Flugrichtung drehen, und verändert nur die Richtung wenn man auch Schub gibt. Ich merke aber das ist recht anspruchsvoll und Flughilfen wären nicht schlecht. Kennt sich einer von Euch mit den RidigBody Methoden von Unity3D aus (Rotate und AddRelativeForce), und hat eine Idee wie ich am sinnvollsten folgende Szenarien umsetzen kann? Ich muss z.B. irgendwie mithilfe der Velocity Information und Ausrichtung des Raumschiffs Gegenschübe erzeugen, um das Schiff in die richtige Richtung zu bewegen.
Auf jedenfall bin ich aber happy das es vorwärts geht, es ist schon geil ein setting zu bauen wo man mit hoher Geschwindigkeit durch ein Weltall (okay, bis jetzt noch seeeeehr leer :-) ) zu fliegen und dann auf ne procedurale Planetenoberfläche mit gemäßigter Geschwindigkeit runtergehen zu können.
Re: [Projekt] Prozedurales Universum
Verfasst: 01.01.2015, 20:46
von Krishty
Erstmal konvertierst du den Richtungsvektor ins objektlokale Koordinatensystem. Dann ist bspw. die Z-Komponente die Geschwindigkeit in Flugrichtung. Dann nimmst du die X- und Y-Komponente, multiplizierst sie mit irgendeinem Faktor, und lässt das als Gegenkraft wirken (also mit umgekehrtem Vorzeichen). Dadurch erhälst du b).
a) erreichst du, indem du diese Gegenkraft nicht im Schwerpunkt wirken lässt, sondern auf der Z-Achse verschoben. Dann entsteht ein Drehmoment, das dafür sorgt, dass das Raumschiff zur Flugrichtung strebt. (So funktioniert ja ein Pfeil – die Federn wirken nur deshalb stabilisierend, weil sie nach hinten verschoben sind.) Das sollte aber (wie in Wirklichkeit) unbedingt gedämpft werden, damit es nicht ewig oszilliert.
Das funktioniert bei mir sehr gut. Aber wie die entsprechenden Unity-Schnittstellen heißen, weiß ich nicht.
Re: [Projekt] Prozedurales Universum
Verfasst: 03.01.2015, 22:08
von AyJayKay
Du möchtest gute Physik mit Möglichkeit auf Kollision? Ich frage weil du meintest du benötigst
sushbone hat geschrieben:Rotate und AddRelativeForce
Rotate ist von der Transform komponente und versaut dir die Kollision und für a) brauchst du mit Krishty's Methode
addForceAtPosition. Beachte halt, dass da dann auch Bewegung (also nicht nur Drehung) entsteht...
Die Physicsengine wird nach FixedUpdate() mit dem gleichen Zeitabstand berechnet; Reibung, "Luftwiederstand" (rigidbody.drag) und Gravitation überschreibst du also nur mit Update(). (Will man zwar nicht wenn man sich schon einer Physicsengine bedient... ich wollts halt erwähnen :) )
Wenn du mit AddForce/Torque arbeitest dann schau auf den
ForceMode.
Re: [Projekt] Prozedurales Universum
Verfasst: 08.01.2015, 20:23
von sushbone
Ihr habt vollkommen Recht, ich sollte wenn ich schon die Physikengine nutzen dass auch konsequent machen. Außerdem ist es irgendwie auch spannender wenn man die Mechanik etwas "realitätsnaher" umsetzt als einfach direkt die Objekte zu manipulieren. Danke für die Hinweise, auch für die Unity hints!! Muss ich mich nochmal genauer reinarbeiten!
Re: [Projekt] Prozedurales Universum
Verfasst: 08.01.2015, 20:30
von sushbone
Re: [Projekt] Prozedurales Universum
Verfasst: 08.01.2015, 21:09
von Schrompf
Coolcool!
Re: [Projekt] Prozedurales Universum
Verfasst: 08.01.2015, 21:13
von xq
Versuchs doch mal mit der Kombination aus Multitexturing (Sehr hohe Kachelung) und deiner Farbtextur, das ganze dann mit Mipmapping und du dürftest einen recht schicken Effekt bekommen, sowohl aus der Nähe als auch aus der Distanz.
Oder ein "tripel"-multitexturing mit deinem farbverlauf, dann eine medium gekachelte textur und darauf eine hoch gekachelte textur (quasi 4-8 Pixel auf Textur Layer 1 entsprechen einer gesamten Textur Layer 2)
Aber ansonsten sehr cool
Grüße
Felix
Re: [Projekt] Prozedurales Universum
Verfasst: 18.05.2015, 13:15
von sushbone
So bin mal wieder am Weiterarbeiten an der Planetengeschichte. Das Texture-Bleeding-Problem habe ich mittlerweile gelöst bekommen.
Dann gab es noch einen Bug dass die Planeten "gesprungen" sind wenn sie von einem "Space" in einen anderen gewandert sind (z.B. "ScaledSpace" 1:1000000 nach "LocalSpace" 1:1) wo ich Objekte in der Skalierung verändere und repositioniere, um weite sichtbare Distanzen darstellen zu können. Lag daran dass ich die Kamerapositionen nicht korrekt berücksichtigt habe. Das geht jetzt auch.
Langsam wird es Zeit dass ich meinen Blog mit einer genaueren Beschreibung des ganzen mal schreibe.
Wichtigste Anpassung war das Threading. Die ganze Zeitlang hatte der Mainthread zwischen jedem Frame die Quadtrees parsen müssen, das ist natürlich suboptimal.
Jetzt ist die Logik folgende
1) Mainthread stößt einen Quadtree Parser Thread an (sofern dieser nicht schön läuft)
2) QuadtreeParser durchsucht alle 6 Quadtrees ob es etwas zu splitten oder mergen gibt.
3) Falls ja wird der Quadtree-Node in eine PrecalulcationQueue geworfen für die Precalulcation (Vertices, Indices, Noise, Texturen, etc).
4) Ein weiterer PrecalulcationThread prüft diese Queue. Findet er etwas, fordert er aus einem ThreadPool einen Thread für die Berechnung des jeweiligen Nodes an.
5) Der Mainthread läuft in der Zeit weiter. Er prüft ob der QuadtreeParser Thread und der PrecalulcationThread einmal komplett durchgelaufen ist. Falls ja erzeugt der Mainthread die fertigen Planes sofern es neue zu zeichnen gibt.
Bevor ich mich jetzt an die neue Texturierung mache muss ich aber noch das Culling Problem lösen, um erstmal ausreichend Geschwindigkeit auf Bodennähe zu haben. Das HorizonCulling bereitet mir langsam schlaflose Nächte, es will nicht funktionieren.
Ich möchte gerne im Quadtree bis auf Level 20-21 kommen, dann hab ich einen Detailgrad von ca. 1 Meter, was klasse wäre. Grundsätzlich klappt das auch, aber es laufen einfach zu viele unnötige Berechnungen nicht sichbarer Flächen. Freundlicherweise gab mir im iNovaestudios Forum jemand einen Tip, anbei das Bild:
Sieht jemand den Fehler in meiner Implementierung? Ungefähr ab der doppelten Radius Distanz des Planeten wertet der Algorithmus alles als nicht sichtbar, und es werden keine neuen Planes mehr gezeichnet, auch nicht die direkt vor mir. Ich find das Problem einfach nicht?!?
Code: Alles auswählen
// Returns true if testPosition is outside horizon (occluded), false if testPosition is inside horizon (not occluded)
public bool HorizonCullingAlgorithm3(Vector3 cameraPosition, Vector3 testPosition, float radius) {
float planetRadius = radius;
float cameraHeightFromOrigin = Vector3.Distance (new Vector3 (0, 0, 0), cameraPosition);
float rMin = planetRadius + planetRadius * (-0.005f); // due to algorithm: planetRadius *= 1+noisePushDown*noise; noisePushdown = 0.005f, noise = [-1,1];
float rMax = planetRadius + planetRadius * (0.005f); // due to algorithm: planetRadius *= 1+noisePushDown*noise; noisePushdown = 0.005f, noise = [-1,1];
double horizonDistance = Math.Sqrt (Math.Pow (cameraHeightFromOrigin,2) - Math.Pow (rMin,2));
double overTheHorizonDistance = Math.Sqrt (Math.Pow (rMax, 2) - Math.Pow (rMin, 2));
double radiusOfTheVisibleSphere = horizonDistance + overTheHorizonDistance;
double testPositionDistance = Vector3.Distance (testPosition, cameraPosition);
if (cameraHeightFromOrigin < rMin)
Debug.LogWarning ("HorizonCullingAlgorithm3:: Camera is below rMin!");
// A Point is visible if its distance is less than the radius of the visible sphere
if (testPositionDistance < radiusOfTheVisibleSphere)
return false; // point is not occluded
else
return true; // point is occlued
}
Bisschen Eyecandy, sieht noch nicht wesentlich anders aus als die letzten Bilder, aber wenigstens das Bleeding ist jetzt weg (die LOD-Kanten allerdings noch nicht)...
Re: [Projekt] Prozedurales Universum
Verfasst: 18.05.2015, 13:31
von Schrompf
Ziemlich cool. Jetzt braucht es Licht und Atmosphäre! :-)
Re: [Projekt] Prozedurales Universum
Verfasst: 18.05.2015, 13:35
von sushbone
Ich weiß. Aber ich werde versuchen mich vor dem Thema Shader so lange wie möglich zu drücken :lol: :lol:
Auch wenn ich für Atmosphäre und Wasser wohl nicht drum herumkomme
Re: [Projekt] Prozedurales Universum
Verfasst: 18.05.2015, 13:59
von Zudomon
Das ist schon sehr gut geworden!
Man sieht auf einigen Bildern noch Artefakte, ich denke, wo ein Detailstufenübergang zu sehen ist.
Gut wäre es, wenn du um die Bilder noch "noshowroom" drum packen würdest. Und dann nur bei den Bildern, wo du glaubst, dass die in den Showroom (also auf die Frontseite von ZFX) gehören, den tag weg lässt. So haben wir nämlich auf der Seite einen schönen Querschnitt der Projekte. (Mache ich bei meinen Screens schon die ganze Zeit so, weil sonst wären da nur noch SQ-Bilder zu sehen und das würde keinen Sinn machen :D ).
Das soll keine Kritik, sondern nur ein Tipp sein. Letztendlich kannst es natürlich machen wie du magst! :D
Re: [Projekt] Prozedurales Universum
Verfasst: 18.05.2015, 14:04
von sushbone
Ah sorry das wusste ich nicht, habs korrigiert (in der Hoffnung dass das jetzt nachträglich noch greift).
Re: [Projekt] Prozedurales Universum
Verfasst: 18.05.2015, 14:09
von Zudomon
Japp, das funktioniert nachträglich. Das ist auch das schöne daran. Wenn man dann ein "Update" postet und da aber immer noch nur die eigenen Bilder sind, dann mach ich es so, dass ich die alten Posts editiere, damit davon keine Bilder mehr zu sehen sind und dann nur noch von dem neuesten was zu sehen ist. :D
Re: [Projekt] Prozedurales Universum
Verfasst: 21.05.2015, 09:47
von joeydee
Cool, schön dass es hier weitergeht. Interessant, die Berechnung. Ich hatte mir (ohne konkretes Projekt) auch schon Gedanken gemacht, dass man das wohl so lösen müsste, aber das ist ja geradezu bestechend einfach :)
Besteht der Fehler noch?
Sieht jemand den Fehler in meiner Implementierung? Ungefähr ab der doppelten Radius Distanz des Planeten wertet der Algorithmus alles als nicht sichtbar, und es werden keine neuen Planes mehr gezeichnet, auch nicht die direkt vor mir. Ich find das Problem einfach nicht?!?
Die Kernberechnung scheint jedenfalls keinen Fehler zu haben (Achtung, die Vereinfachung in der letzten Zeile der Grafik scheint mir falsch zu sein, müsste binomisch aufgelöst werden, aber du nutzt ja die ausführliche Formel).
Gibt der Vis-Radius im beschriebenen Problemfall denn brauchbare Werte aus oder sind die schon falsch (z.B. kleiner als die Kameradistanz)?
Falls die Sphere ok ist und rMin auf jeden Fall schneidet, muss der Fehler ganz woanders liegen. Wie ist denn dein Kriterium zum Splitten eines Patches, harmoniert das mit einem Sphere-Test in allen denkbaren Fällen? Denn hier könnte es z.B. passieren, dass Testpunkte (z.B. die Mitten oder Ecken des Patches) außerhalb einer Sphere liegen, obwohl ein anderer Teil des Patches die Sphere eigentlich schneidet.
Re: [Projekt] Prozedurales Universum
Verfasst: 22.05.2015, 13:22
von sushbone
joeydee du warst ganz auf der richtigen Fährte. Ich habe mir mal alle irgendwie interessanten Werte während des Kamera-Anflugs im Debuglog ausgeben lassen, inklusive der Summe der occluded (verdeckten) und not-occluded (also sichtbaren) Patches bzw. Eckoordinaten pro Prüfzyklus aller sechs Quadtrees.
Der Culling Algorithmus hat durchgängig glaubhafte Werte ausgegeben, stutzig wurde ich allerdings als ich sah dass ab dem Moment wo die Splits plötzlich aufhörten es im Debuglog hieß der Culling Algorithmus würde nur noch 8 unterschiedliche Testkoordinaten als Input bekommen, und in Summe währen 6 Patches occluded und 0 not-occluded. Das deutete also ganz stark auf die Root Nodes hin, denn zu Beginn besteht die Sphere ja aus 6 Patches mit in Summe 8 unterschiedlichen Eckkoordinaten. Die Regeln die ich zum Splitten und Mergen verwende:
- Vorab prüfe ich die Distanz aller Eckkoordinaten zur Kamera und suche ich die Eckkoordinate die der Kamera am nächsten ist.
- Dann prüfe ich ob das aktuelle Patch verdeckt ist, indem ich alle Eckkordinaten durch das Horizon-Colling prüfe. Ist nur eine koordinate sichtbar, ist das ganze Patch sichtbar.
- Als letztes prüfe ich ob das Parent-Patch verdeckt ist, indem ich wieder alle Eckkordinaten durch das Horizon-Colling prüfe. Ist nur eine koordinate sichtbar, ist das ganze Parent-Patch sichtbar.
Split:
Wenn die Distanz nächsten Eckkoordinate zur Kamera geteilt durch 2.5 (2.5 frei ermittelte Zahl, durch Näherungstests ermittelt) kleiner ist aus der Durchmesser des Patches, und das Patch als nicht verdeckt bewertet ist,
dann, wenn es sich zusätzlich um ein Leaf handelt, führe einen Split aus (ansonsten prüfe rekursiv die Child-Nodes) weiter.
Code: Alles auswählen
if (nodeOuterVectorDistanceCamera.Min()/2.5 < quadtreeTerrain.worldSpaceDiameter && isOccluded == false) {
if (quadtreeTerrain.isLeaf == true) { SPLIT AUSFÜHREN }
Merge:
Wenn die Distanz der nächsten Eckkoordinate zur Kamera geteilt durch 2.5 größer ist als der Durchmesser des Patches, es sich nicht um ein Leaf handelt, ODER dieses Patch als auch das gröbere Parent-Patch verdeckt sind (damit das Culling greifen kann), dann führe einen Merge aus (d.h. rendere das Patch, und entferne alle Child-Patches). Hier beziehe ich das Parent-Patch mit ein, um zu verhindern dass immer ein zyklischer Split<->Merge ausgeführt wird.
Code: Alles auswählen
else if ( (nodeOuterVectorDistanceCamera.Min()/2.5 > quadtreeTerrain.worldSpaceDiameter && quadtreeTerrain.isLeaf == false)
|| ( isOccluded == true && isParentNodeOccluded == true) )
So sieht das dann komplett aus
Code: Alles auswählen
if (quadtreeTerrain.nodeLevel <= this.maximumNodeLevel) {
// Prüfe ob die Distanz der Kamera zum Quadtree durch Faktor x kleiner ist als dessen Durchmesser (falls ja, teilen)
if (nodeOuterVectorDistanceCamera.Min()/2.0 < quadtreeTerrain.worldSpaceDiameter && isOccluded == false) {
if (quadtreeTerrain.isLeaf == true) {
if (quadtreeTerrain.quadtreeState == QuadtreeState.RENDERED) {
if (currentMaximumNodelevel < quadtreeTerrain.nodeLevel) {
currentMaximumNodelevel = quadtreeTerrain.nodeLevel;
Debug.Log ("ProceduralPlanetManager::ParseQuadtreeTerrain():: New current maximum quadtree nodelevel: "+currentMaximumNodelevel);
}
// Push into queue and set calulcation for children. Do nothing more.
quadtreeTerrain.CreateChildNodes();
quadtreeTerrain.isLeaf = true;
quadtreeTerrain.childNode1.quadtreeState = QuadtreeState.AWATING_PRECALCULATION;
PreCalulcate(quadtreeTerrain.childNode1);
quadtreeTerrain.childNode2.quadtreeState = QuadtreeState.AWATING_PRECALCULATION;
PreCalulcate(quadtreeTerrain.childNode2);
quadtreeTerrain.childNode3.quadtreeState = QuadtreeState.AWATING_PRECALCULATION;
PreCalulcate(quadtreeTerrain.childNode3);
quadtreeTerrain.childNode4.quadtreeState = QuadtreeState.AWATING_PRECALCULATION;
PreCalulcate(quadtreeTerrain.childNode4);
quadtreeTerrain.quadtreeState = QuadtreeState.DEPRECATED;
// Render children and destroy parent renderings
QuadtreeTerrainSplitQueue.Add (quadtreeTerrain);
// Recurse down the tree
if (quadtreeTerrain.childNode1 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode1);
if (quadtreeTerrain.childNode2 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode2);
if (quadtreeTerrain.childNode3 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode3);
if (quadtreeTerrain.childNode4 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode4);
}
} else if (quadtreeTerrain.isLeaf == false) {
// Recurse down the tree
if (quadtreeTerrain.childNode1 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode1);
if (quadtreeTerrain.childNode2 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode2);
if (quadtreeTerrain.childNode3 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode3);
if (quadtreeTerrain.childNode4 != null) ParseQuadtreeTerrain (quadtreeTerrain.childNode4);
}
} else if ( (nodeOuterVectorDistanceCamera.Min()/2.0 > quadtreeTerrain.worldSpaceDiameter && quadtreeTerrain.isLeaf == false)
|| ( isOccluded == true && isParentNodeOccluded == true) ) {
if (quadtreeTerrain.isLeaf == false) {
if (quadtreeTerrain.quadtreeState == QuadtreeState.NEW) {
quadtreeTerrain.quadtreeState = QuadtreeState.AWATING_PRECALCULATION;
PreCalulcate(quadtreeTerrain);
quadtreeTerrain.childNode1.quadtreeState = QuadtreeState.DEPRECATED;
quadtreeTerrain.childNode2.quadtreeState = QuadtreeState.DEPRECATED;
quadtreeTerrain.childNode3.quadtreeState = QuadtreeState.DEPRECATED;
quadtreeTerrain.childNode4.quadtreeState = QuadtreeState.DEPRECATED;
// Merge children to parent
QuadtreeTerrainMergeQueue.Add(quadtreeTerrain);
}
} else if (quadtreeTerrain.isLeaf == true && quadtreeTerrain.parentNode != null) {
if (quadtreeTerrain.parentNode.quadtreeState == QuadtreeState.NEW) {
quadtreeTerrain.parentNode.quadtreeState = QuadtreeState.AWATING_PRECALCULATION;
PreCalulcate(quadtreeTerrain.parentNode);
quadtreeTerrain.quadtreeState = QuadtreeState.DEPRECATED;
// Merge children to parent
QuadtreeTerrainMergeQueue.Add(quadtreeTerrain.parentNode);
}
}
}
}
}
(wo ich mir das so gerade angucke bin ich unschlüssig ob meine Merge-Regel so 100%ig korrekt ist, das Regelwerk dazu fand ich etwas trickreicher als der Split).
Das Problem war dass ich
jeden Quadtree Node mittels Horizon Culling überprüft hatte. D.h. obwohl ich beim Anflug auf die Sphere schon einige Splits hinter mir hatte habe ich dennoch immer wieder im ersten Anlauf das Root Patch geprüft, welches natürlich irgendwann hinter dem Horizon liegt. Basierend auf meinem Regelwerk hat dann entsprechend kein Split mehr stattgefunden. Es kam also gar nicht mehr soweit dass das eigentlich relevante Leaf in Hinblick auf Split geprüft wurde, da schon beim Rootnode schluss war.
Die Korrekturen die ich gemacht habe, was die Situation verbessert hat:
- Führe nur noch bei einem Leaf einen Horizon Culling Test aus, handelt es sich nicht um ein Leaf gehe davon aus dass es nicht verdeckt ist.
- Prüfe auch die Center-Koordinate eines Patches auf Sichtbarkeit.
Allerdings ist das ganze nach wie vor nicht optimal. Die Änderung nur noch Leafs zu prüfen greift wenn ich einen Planeten anfliege. Starte ich aber direkt auf der Oberfläche, ist logischerweise das Root-Patch erstmal auch Leaf, und die Koordinaten liegen wieder hinter dem Horizon, ergo kein Split. Die Aufnahme der Center-Koordinate reduziert dieses Probem ein wenig, wenn ich nicht direkt auf der Oberfläche starte, löst es aber nicht (und ist auch eigentlich unnötig in Bezug auf die Sichtbarkeitsprüfung eines kompletten Patch im eigentlichen Sinne).
Ich hab grad keine richtige Idee wie ich das löse. Und ob nicht auch irgendwie noch ein Denkfehler im Split/Merge-Regelansatz ist, auch wenn es funktionieren tut, ggf. liegt die Lösung dass es bei Start auch der Oberfläche auch splittet in genau einer Anpassung dieser Regeln (in dem ich zum Beispiel nicht nur mit dem stumpfen 2.5 Ansatz arbeite).
Re: [Projekt] Prozedurales Universum
Verfasst: 25.05.2015, 13:01
von sushbone
Ich habe die Strategy für verschiedene Spaces, um Weltraumszenen zu machen bei denen man in großen Skalen arbeiten muss um große Objekte darzustellen, und auch weit entfernte und nahe zugleich, mal in ein Bild gepackt.
Falls das mal jemand braucht. Ich muss mal gucken ob ich das komplette zugehörige Unity3D Script mal irgendwo hochlade in nem Wiki oder so.
Re: [Projekt] Prozedurales Universum
Verfasst: 26.05.2015, 10:36
von joeydee
Super, der Thread ist jetzt schon ein klasse Nachschlagewerk :)
Was du wahrscheinlich brauchst, ist eine genauere, zumindest eine "sichere" Distanzfunktion zu einem Patch. Und zwar zur gewölbten Oberfläche, nicht zur planaren Fläche, also geht auch keine normale Distanzfunktion zu einem Polygon. Aber so ähnlich vielleicht.
Ein Ansatz wäre daher evtl.: vom Mittelpunkt aus Ebenen entlang der Kanten eines Patches aufspannen. Wenn die Kamera innerhalb des aufgespannten Volumes ist, ist die Lösung trivial (shortestDistanceToPatch=distanceToCenter - r). Wenn die Kamera außerhalb ist, Fallunterscheidungen wie beim Polygontest, den Punkt aber auf die Kugeloberfläche projizieren statt auf das Patch-Polygon.
Nicht ganz trivial, am besten nochmal den "normalen" Polygontest studieren, habe jetzt leider keinen passenden Link. Anbei aber mal ein Bild wie ich das meine.
Vielleicht gibt es da auch grundsätzlich noch eine Vereinfachung wegen der besonderen Gegebenheiten auf der Kugel.
Vielleicht kann man auch eine genäherte Distanzfunktion basteln, z.B. Spheres berechnen, die ganz sicher das gewölbte Patch einschließen aber trotzdem nicht zu viel Overhead produzieren. Ich lass das Thema mal in meinem Blickfeld.