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

Aktuelle Zeit: Sa Dez 21, 2024 17:20

Foren-Übersicht » Programmierung » Shader
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Fr Apr 10, 2015 15:53 
Offline
DGL Member

Registriert: Fr Mai 11, 2012 13:25
Beiträge: 229
Programmiersprache: c++, c, JavaScript
Hallo Leute,

Ich brauche eine gute Noisefunktion im Shader, also eine, die keine Muster aufweist etc.
Und zwar, um Partikeln immer wieder neue Startpositionen zuzuteilen und zwar unabhängig von ihrer momentanen Position,
und so, dass sich keine Anhäufungen bilden.

Ich habe mir mal ein paar Algorithmen angesehen, perlin und simplex sehen gut aus, es sind aber schon einige Rechenschritte.
Jetzt könnte man ja eine Noisetextur schreiben, und müsste dann für jeden Wert nur einmal fetchen.
Ist das ratsam? Da die Textur vorberechnet ist, befürchte ich, dass sich dann repetitive Muster ergeben.
Kann man das durch geeignete Koordinaten beheben, und bekommt die gleiche Qualität hin?

Das gleiche Problem sehe ich eigentlich auch bei der Berechnung im Shader.
Wie bekommt man Koordinaten, so dass das Ergebnis der Funktion nicht mit den Koordinaten korreliert ist, zumindest nicht sichtbar.

Wenn ich im Hauptprogramm per Integeroverflow mein Rauschen berechne, ist es ja was anderes, weil sich der seed ja mit jeder Berechnung ändert.
Geht das im Shader auch? Mit TransformFeedBack müsste es doch gehen oder?
Würdet ihr diese Berechnungsmethode empfehlen, oder sind Perlin und co. schöner?
Die overflowmethode wär jedenfalls wesentlich günstiger, wenn man eh schon TFFB macht.

Grüße,
VinZ

_________________
"Pixel, ich bin dein Vater."
-Darf Shader


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Apr 10, 2015 16:58 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Du kannst Simplex erstmal probieren und schauen, ob die Performance ausreicht. Wenn das nicht der Fall ist, kannst du eine Noisetexture verwenden. Die würde ich alle paar Frames (oder gar jeden Frame) auf der CPU neu generieren und hochladen (das Generieren kann man ja machen während die GPU gerade beschäftigt ist). Als Texturkoordinate kannst du dann z.B. den Partikelindex oder sowas verwenden.

viele Grüße,
Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 00:28 
Offline
DGL Member

Registriert: Fr Mai 11, 2012 13:25
Beiträge: 229
Programmiersprache: c++, c, JavaScript
Wäre ne Lösung, bei mehreren Millionen Partikeln wird die CPU das aber wohl nur so ein mal pro Sekunde schaffen, schätz ich.
Was mich auf ein weiteres Problem bringt:
Wenn es richtig viele Partikel sind, brauch ich ja auch ne riesige Textur, und dann wird das fetchen wieder langsamer.

_________________
"Pixel, ich bin dein Vater."
-Darf Shader


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 01:06 
Offline
DGL Member

Registriert: Fr Mai 11, 2012 13:25
Beiträge: 229
Programmiersprache: c++, c, JavaScript
Mir is grad aufgefallen, dass es es bei Perlin und Simplex überhaupt nicht um die Erzeugung der Zufallszahlen geht, die hier vorausgesetzt werden.
Gerade um die gehts mir aber.
Was ich also suche ist eine gute Zufallszahlenfunktion in glsl, hat zufällig jemand eine auf Lager?
Also eine Funktion, die Texturkoordinaten und Zeitkoordinate frisst und möglichst unkorellierte (scheinbar) Werte ausspuckt.

_________________
"Pixel, ich bin dein Vater."
-Darf Shader


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 09:49 
Offline
DGL Member
Benutzeravatar

Registriert: Di Sep 06, 2005 18:34
Beiträge: 362
Wohnort: Hamburg
Hey,

ich würde dir den Ansatz mit einer vorberechneten noise Textur empfehlen. Wenn du dem Shader jeden Frame z.B. die aktuelle Systemzeit mitschickst als uniform variable, kannst du die mit dem Partikelindex verrechnen (einfach addieren) und bekommst so scheinbar zufälligere Werte. Dieser Ansatz hat vor allem den Vorteil, dass er schnell umsetzbar ist und du wirst schnell sehen können ob dir die Ergebnisse ausreichen. Wenn nicht, kannst du entweder mehrere vorberechnete Texturen bereit halten aus denen du jeden Frame zufällig eine auswählst oder du kannst sie, wie Lord Horazont sagte, neu generieren.

_________________
Der Mensch hat neben dem Trieb der Fortpflanzung und dem zu essen und zu trinken zwei Leidenschaften: Krach zu machen und nicht zuzuhören. (Kurt Tucholsky)
Schwabbeldiwapp, hier kommt die Grütze. (Der Quästor)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 11:09 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich habe gerade mal getestet:
Code:
  1. #include <chrono>
  2. #include <cstdlib>
  3. #include <iostream>
  4. #include <vector>
  5.  
  6. typedef std::chrono::steady_clock used_clock;
  7.  
  8. int main()
  9. {
  10.     std::vector<float> data(1000000);
  11.     unsigned int seed = time(nullptr);
  12.     used_clock::time_point t0 = used_clock::now();
  13.     for (unsigned int i = 0; i < 10; i++) {
  14.         for (unsigned int j = 0; j < 1000000; j++) {
  15.             data[j] = float(rand_r(&seed)) / RAND_MAX;
  16.         }
  17.     }
  18.     used_clock::time_point t1 = used_clock::now();
  19.  
  20.     std::cout << std::chrono::duration_cast<std::chrono::duration<float, std::ratio<1> > >(t1 - t0).count() / 10. << std::endl;
  21.  
  22.     return 0;
  23. }
  24.  

Das gibt bei mir 0.012 aus (ohne jegliche Optimierungen!), also 12ms pro 1M Punkte. Wenn man das in einem Thread parallel zum Renderthread macht und einen Doublebuffer benutzt, dann bekommt man, zwar recht knapp, aber dennoch pünktlich, zu jedem Frame 1M frische Zufallsdaten. Faktisch wirds auch reichen, pro Frame nur ¼ der Noisetextur neu zu schreiben und halt wie Shaijan schon vorschlug mit einem Offset zu arbeiten. Ich würde hier aber einen rand_r() Wert für das Offset nehmen anstatt der Systemzeit, da die halt kontinuierlich wächst. Da kann man sich leicht Muster reinholen, v.a. wenn man nur einen Teil der Textur neuschreibt.

viele Grüße,
Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 11:25 
Offline
DGL Member

Registriert: Do Dez 29, 2011 19:40
Beiträge: 421
Wohnort: Deutschland, Bayern
Programmiersprache: C++, C, D, C# VB.Net
Es ist eine wichtige Unterscheidung zwischen Zufallszahl und Noise zu treffen. Eine Zufallszahl ist eine Zahl die einfach zufällig ist. Man erhält Werte die so verteilt sind:
Bild
Bild

Für viele Anwendungen ist das aber nicht gut genug. Man will nicht bloß zufällige Strukturen sondern auch einen kontinuierlichen Verlauf.
Das sieht dann zum Beispiel so aus:
Bild
Bild

Die beiden Dinge unterscheiden sich ziemlich. Für zweiteres gibt es Verfahren wie Perlin oder Simplex Noise. Oder viel einfachere Dinge, wie einfach zufällige Werte in einem Raster interpolieren und mit verschiedenen Frequenzen und Amplituden aufaddieren. (Grundkonzept)
Um Zweiteres umzusetzen braucht man aber in der Tat erstmal einfach Zufallszahlen.

Zufallsdaten als Textur würde ich eher nicht verwenden, weil es sich wiederholt. Wenn du keinen Schreibzugriff besitzt, können Hash Funktionen eine gute Basis für Zufallszahlen sein. Du hast einen nicht zufälligen Ausgangswert. Zum Beispiel gl_VertexID oder die Pixelkoordinate X und Y verrechnet. Wenn du keinen Determinus benötigst und OpenGL 4.2 zur Verfügung hast, bietet sich auch ein Atomic Counter Buffer an. Jedenfalls hast du kontinuierliche Eingangsdaten. Jetzt brauchst du nur noch eine Funktion die für kontinuierliche Eingangswerte in zufällige Ausgangswerte umwandelt.
Da gibt es viele Vorschläge dazu im Netz, ich habe in letzter Zeit das verwendet:
Code:
  1.  
  2. uint Hash(uint x)
  3. {
  4.     x ^= 0x9AAB7F34;
  5.     x += ( x << 10u );
  6.     x ^= ( x >>  6u );
  7.     x += ( x <<  3u );
  8.     x ^= ( x >> 11u );
  9.     x += ( x << 15u );
  10.     return x;
  11. }
  12. float HashFloat(uint x)
  13. {
  14.     return float(Hash(x)) * (1.0 / 4294967295.0);
  15. }


Nochmal zur Geschwindigkeit: Eine Funktion im Shader sollte einer Textur auch überlegen sein. Speicherzugriffe sind zunehmend auch auf der GPU der Flaschenhals. Man kann auch prognostizieren, dass der Trend zu noch langsameren Speicher geht.

@Lord Horazont
rand_r ist nicht portabel und hat für verschiedene Anwendungen weitere Probleme.
Man sollte die Zufallszahlen in C++ inzwischen am besten mit <random> generieren.
https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful


Zuletzt geändert von OpenglerF am Sa Apr 11, 2015 13:47, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 12:23 
Offline
DGL Member

Registriert: Fr Mai 11, 2012 13:25
Beiträge: 229
Programmiersprache: c++, c, JavaScript
@OpenglerF
Danke für die Klarstellung!
Zitat:
Wenn du keinen Schreibzugriff besitzt, können Hash Funktionen eine gute Basis für Zufallszahlen sein.

Aber wie ist es wenn man Schreibzugriff hat, z.B. mit TFFB, gibts da bessere Ansätze?

@Horazont
Ich bin von komplexeren Berechnungen für die Zufallszahlen ausgegangen, aber gut zu wissen, dass man mit rand() locker eine Million Werte pro Frame bekommt, man muss sie aber auch noch in den VRAM laden.

_________________
"Pixel, ich bin dein Vater."
-Darf Shader


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 12:28 
Offline
DGL Member

Registriert: Fr Mai 11, 2012 13:25
Beiträge: 229
Programmiersprache: c++, c, JavaScript
Zitat:
Eine Funktion im Shader sollte einer Textur auch überlegen sein.

Was aber ein Vorteil an der Textur sein kann, ist, dass man die Zufallszahlen mit komplexeren Berechnugen erzeugen kann, und somit ne bessere Quali bekommt, z.B. mit http://www.cplusplus.com/reference/random/mt19937/.

_________________
"Pixel, ich bin dein Vater."
-Darf Shader


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 12:36 
Offline
DGL Member

Registriert: Fr Mai 11, 2012 13:25
Beiträge: 229
Programmiersprache: c++, c, JavaScript
Shaijan hat geschrieben:
...Wenn du dem Shader jeden Frame z.B. die aktuelle Systemzeit mitschickst als uniform variable, kannst du die mit dem Partikelindex verrechnen (einfach addieren) und bekommst so scheinbar zufälligere Werte. Dieser Ansatz hat vor allem den Vorteil, dass er schnell umsetzbar ist...


Damit hab ich auch schon rumexperimentiert, das Problem ist aber, dass wenn man die Zeit einfach draufaddiert, man die Textur quasi unter den Texturkoordinaten durchzieht, dadurch wird es sehr zeitlich-räumlich korreliert, quasi wellenmäßig.

_________________
"Pixel, ich bin dein Vater."
-Darf Shader


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 13:43 
Offline
DGL Member

Registriert: Do Dez 29, 2011 19:40
Beiträge: 421
Wohnort: Deutschland, Bayern
Programmiersprache: C++, C, D, C# VB.Net
Zitat:
Aber wie ist es wenn man Schreibzugriff hat, z.B. mit TFFB, gibts da bessere Ansätze?

Was ist den TFFB? Davon habe ich noch die gehört. Ich denke, der Ansatz ist ziemlich gut. Er kann gleichverteilte Zufallszahlen mit hoher Periode erzeugen. Alle klassischen Pseudozufallsgeneratoren arbeiten leider sequentiell und sind somit kaum für Shader geeignet. In einem Compute Shader mit einer Storage Buffer Object, könntest du jeden Thread einen eigenen Zustand für den Zufallsgenerator zuweisen und so parallel arbeiten. Wenn es geht, würde ich aber davon absehen. Ich weiß nicht, welches Ziel du genau verfolgst, Hashfunktionen haben allerdings für mich bisher für alle Dinge ausgereicht.

Die Systemzeit würde ich nicht verwenden. Ich würde lieber gut generierte Zufallszahlen von der CPU verwenden. RDTSC ist auf dem x86 ein guter Startpunkt für einen Seed. Ich glaube in Linux gibt es auch irgendeine Quelle von echten Zufallszahlen. Auf neuen Prozessoren gibt es noch RdRand. Jede Menge Möglichkeiten echten Zufall zu bekommen und Werte, die nicht zeitlich korrelieren.

Du kannst auch den Seed der Hashfunktion von der CPU aus für jeden Frame verändern. Wenn der Wert aber um den gleichen Faktor inkrementell steigt, ist der Trick icht "Seed0 + Seed1 + Seed2" zu machen, weil es sonst wieder diagonale Wellen gibt. Wenn Seed0 eins kleiner wird und Seed1 eins größer, kommt der gleiche Wert raus. Besser wird es, wenn man die Bits gegeneinander verschiebt:
"Seed0 + ((Seed1 >> 10) + (Seed1 << 22)) + ((Seed2 >> 21) + (Seed2 << 11))"


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 14:36 
Offline
DGL Member

Registriert: Fr Mai 11, 2012 13:25
Beiträge: 229
Programmiersprache: c++, c, JavaScript
Zitat:
Was ist den TFFB? Davon habe ich noch die gehört.

Transform Feedback, damit kann man aus dem Vertexshader heraus VBOs schreiben, und somit z.B. die Vertexdaten zeitlich entwickeln lassen, somit könnte man ja auch einen seed für jeden Vertex fortlaufen ändern.

Wie funktioniert das mit der Hashfunktion im Shader, so dass man für den selben Input immer andere Werte bekommt bei gleicher Rechenvorschrift (kann mir das Softwaretechnisch grad nicht vorstellen, hängt es mit der Hardware zussammen), und so dass sie tatsächlich gleichverteilt sind? Sind sie das wirklich? Und wie groß ist die Periode?

_________________
"Pixel, ich bin dein Vater."
-Darf Shader


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 15:01 
Offline
DGL Member

Registriert: Do Dez 29, 2011 19:40
Beiträge: 421
Wohnort: Deutschland, Bayern
Programmiersprache: C++, C, D, C# VB.Net
Zitat:
Transform Feedback, damit kann man aus dem Vertexshader heraus VBOs schreiben, und somit z.B. die Vertexdaten zeitlich entwickeln lassen, somit könnte man ja auch einen seed für jeden Vertex fortlaufen ändern.

Achso. Ich habe nie mit Transform Feedback gearbeitet. Compute Shader haben es irgendwie abgelöst. :wink:
In der Tat könnte man damit jeden Input Vertex einen eigenen Seed geben und den denn dann nach einem klassischen Verfahren verarbeiten. Nachteil ist, dass es zusätzlichen Speicheraufwand bringt. Außerdem musst du erstmal von irgendwo sehr viel Zufall bekommen, um alle die Zustände jeden einzelnen Vertexes zu initialisieren.

Zitat:
dass man für den selben Input immer andere Werte

Das stimmt eben nicht ;-) . Man hat anderen Input. Zum Beispiel eine andere VertexID. Die ID ist für jeden Vertex anders. Sie ist nur nicht zufällig. Durch die Hash-Funktion bildet man diese langweilige gleichmäßig steigende Zahl auf eine Ausgabe ab, die sich scheinbar zufällig ändert, wenn man den Input auch nur um 1 erhöht.

Zitat:
und so dass sie tatsächlich gleichverteilt sind?

Diese Frage kann ich leider schwer theoretisch belegen. Die Quelle der Funktion(siehe mein Link) behauptet, sie wäre gleichverteilt und das getestet zu haben. Da ich keinen Grund sehe, warum das nicht der Fall sein sollte, glaube ich das einfach mal.

Zitat:
Und wie groß ist die Periode?

Bei einer vernümpftigen Hash Funktion so groß wie die Eingabe. Also so im Bereich von 2^32, wobei sich das ja erhöhen lässt, indem man vorher eine zufällige Zahl hinzuaddiert die man "ab und zu" von der CPU aus ändert.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Apr 11, 2015 16:12 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Vinz hat geschrieben:
@Horazont
Ich bin von komplexeren Berechnungen für die Zufallszahlen ausgegangen, aber gut zu wissen, dass man mit rand() locker eine Million Werte pro Frame bekommt, man muss sie aber auch noch in den VRAM laden.

Das sollte kein Problem darstellen, denke ich. Ich hab neulich ein 2k×2k (4 Mio Punkte) Terrain gerendert und dabei die Heightmap (als 32bit floats) in jedem Frame über den Bus geschoben. Das lief auf meiner mini-nvidia (GT 520) noch flüssig ;). V.a. wenn du nur ein Viertel der Textur pro Frame überträgst solltest du da noch viel Spielraum haben.

viele Grüße,
Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


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 » Programmierung » Shader


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste


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:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.013s | 15 Queries | GZIP : On ]