DGL
https://delphigl.com/forum/

UBO struct mehrmals verwendet
https://delphigl.com/forum/viewtopic.php?f=20&t=11637
Seite 1 von 1

Autor:  mathias [ Sa Mär 24, 2018 21:10 ]
Betreff des Beitrags:  UBO struct mehrmals verwendet

Ich verwende die struct mit den Lichparametern 3mal.
Dieser Code funktioniert, aber das mit den 3 "uniform light? { ... }" gefällt mir nicht.
Dazu habe ich mehreres probiert.
Einmal oben bei layout, das wird nicht mal kompiliert.
Und weiter unten die 3 ausgeklammerten Zeilen, dies wird kompiliert, aber mit glUniformBlockIndex nicht gefunden.

Gibt es da eine elegantere Lösung, oder muss ich es sein lassen ?
Was ich machen könnte, ich könnte alle 3 Lichter in ein UBO nehmen, aber ich will es erst mal getrennt.
Code:
  1. #version 330
  2.  
  3. #define ambient vec3(0.2, 0.2, 0.2)
  4.  
  5. #define PI      3.1415
  6. #define Cutoff  cos(PI / 2 / 16)
  7.  
  8. in Data {
  9.   vec3 pos;
  10. } DataIn;
  11.  
  12. //layout(std140) struct   light0, light1, light2 {
  13. layout(std140) struct   Light {
  14.   bool On;
  15.   vec3 Pos;
  16.   vec3 Color;
  17.   float CutOff;
  18. };
  19.  
  20. uniform light0 {
  21.   Light light10;
  22. };
  23.  
  24. uniform light1 {
  25.   Light light11;
  26. };
  27.  
  28. uniform light2 {
  29.   Light light12;
  30. };
  31.  
  32. //uniform Light light0;
  33. //uniform Light light1;
  34. //uniform Light light2;
  35.  
  36. out vec4 outColor;  // ausgegebene Farbe
  37.  
  38. vec3 isCone(vec3 LightPos) {
  39.  
  40.   vec3 lp = LightPos;
  41.  
  42.   vec3 lightDirection = normalize(DataIn.pos - lp);
  43.   vec3 spotDirection  = normalize(-LightPos);
  44.  
  45.   float angle = dot(spotDirection, lightDirection);
  46.   angle = max(angle, 0.0);
  47.  
  48.   if(angle > Cutoff) {
  49.     return vec3(1.0);
  50.   } else {
  51.     return vec3(0.0);
  52.   }
  53. }
  54.  
  55. void main(void)
  56. {
  57.   outColor = vec4(ambient, 1.0);
  58.   if (light10.On) {
  59.     outColor.rgb  += isCone(light10.Pos) * light10.Color;
  60.   }
  61.   if (light11.On) {
  62.     outColor.rgb += isCone(light11.Pos) * light11.Color;
  63.   }
  64.   if (light12.On) {
  65.     outColor.rgb += isCone(light12.Pos) * light12.Color;
  66.   }
  67. }

Autor:  Sascha Willems [ So Mär 25, 2018 10:54 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Layout gehört zum Uniform nicht zur Struct (die nicht GLSL spezifisch ist), kann man also z.B. so machen:

Code:
  1.  
  2. struct Light {
  3.     bool On;
  4.     vec3 Pos;
  5.     vec3 Color;
  6.     float CutOff;
  7. };
  8.  
  9. layout (std140) uniform LightBlock {
  10.     Light lights[3];
  11. };
  12.  
  13. void main()
  14. {
  15.     for (int i = 0; i < 3; i++) {
  16.         vec3 lColor = lights[i].Color;
  17.     }
  18. ...
  19. }
  20.  


Da der Uniform Block anonym ist kann man direkt auf die Member zugreifen.

Alternativ, z.B. wenn es mal viele Lichtquellen werden sollten, besser ein SSBO nutzen. UBOs bei NV sind max. 64k und auf AMD afaik seit einiger Zeit eh nur noch als SSBO emuliert (deshalb da keine Limitierung der Größe).

Autor:  mathias [ So Mär 25, 2018 15:55 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

So wie ich es sehe, muss ich es einzeln machen, wie in meinen Post, wen ich für jede Lichtquelle ein eigener UBO will ?
Dein Beispiel könnte ich nehmen, wen ich alle Lichtquellen in ein UBO packen will, dies wäre natürlich effizienter.

Zitat:
Alternativ, z.B. wenn es mal viele Lichtquellen werden sollten, besser ein SSBO nutzen. UBOs bei NV sind max. 64k und auf AMD afaik seit einiger Zeit eh nur noch als SSBO emuliert (deshalb da keine Limitierung der Größe).
Leider wird da mindestens OpenGL 4.3 verlangt, nur kann mein Intel-Chip nur 4.2 und für ein OpenGL 3.3 Tutorial, daher nicht brauchbar.

Aber interessant ist es trotzdem. So wie es aussieht, müsste man da auch keine Padding verwenden, um eine 16Byte Block zu füllen ?
Wen UBO auf 64KB begrenzt ist, würden immerhin 1'000 Lichtquellen reinpassen ( 4 x 16 x 1'000 = 64'000 ).
Oder kennst du ein Beispiel, in dem man an das 64KB-Limit kommt ?

Autor:  Sascha Willems [ Mo Mär 26, 2018 21:25 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

mathias hat geschrieben:
Wen UBO auf 64KB begrenzt ist, würden immerhin 1'000 Lichtquellen reinpassen ( 4 x 16 x 1'000 = 64'000 ).
Oder kennst du ein Beispiel, in dem man an das 64KB-Limit kommt ?


Die Definition deiner Lichtquellen ist sehr simpel, für echte Lichtquellen benötigt man noch weitere Parameter, dann hat man pro Quelle schnell recht viele Bytes.

Und bei einem deferred oder forward clustered Renderer können das durchaus mehrere hunderte Lichtquellen sein die sichtbar sind, da wird das mit dem UBO knapp.

SSBOs haben den großen Vorteil dass man die im Compute Shader schreiben kann, und so dann auf der GPU z.B. Culling etc. machen kann.

Autor:  mathias [ Di Mär 27, 2018 16:10 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Zitat:
Und bei einem deferred oder forward clustered Renderer können das durchaus mehrere hunderte Lichtquellen sein die sichtbar sind, da wird das mit dem UBO knapp.
Wen sie zu Laufzeit geändert werden müssen, dann ja. Wen es aber statische Lichtquellen sind, ZB Kandelaber , würde ich die Werte direkt in den Shader als Konstante reinkompilieren.
Oder mache ich da einen Denkfehler ?

Autor:  end [ Mi Mär 28, 2018 00:05 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Man macht halt immer das, was einem gerade gelegen kommt und wie es in den Speicher passt. Deine Idee mit dem "ich kompiliere die Lichtquelle statisch rein" ist halt unbrauchbar, wenn du Daten zur Laufzeit veraendern willst (weil shader neukompilieren doch etwas dauert), gds. aber brauchbar wenn die Daten halt statisch sind (aber mehr aufwand).

Ich persoenlich wuerde halt in 3.3 gar keine UBOs verwenden, sondern wenn ueberhaupt SSBOs (ueber extension vllt?) und ansonsten entweder "normal" uniform arrays nutzen oder den klassischen weg ueber texturen. Das ist sehr einfach zu implementieren und birgt den Vorteil, dass du wahrscheinlich nicht in Performancebegrenzer reinlaeufts.
(imho der weg des geringsten widerstands = bester weg)

Autor:  mathias [ Mi Mär 28, 2018 16:45 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Zitat:
Ich persoenlich wuerde halt in 3.3 gar keine UBOs verwenden, sondern wenn ueberhaupt SSBOs (ueber extension vllt?)
In einem Tutorial will ich nicht unbedingt Extensionen verwenden.

Zitat:
und ansonsten entweder "normal" uniform arrays nutzen
Meinst du damit, das ich anstelle der struct eine Array verwende ?
In etwa so ?
    Element 0-3 --> Abient
    Element 4-7 --> Diffuse
    Element 8-11 --> Specular
    Element 12 --> Shininess
Eigentlich Schade, das es kein direkter Weg mit glUniformxxx für struct gibt. :roll:

Zitat:
oder den klassischen weg ueber texturen.

Texturen ?
Was soll das gehen ?

Autor:  end [ Do Mär 29, 2018 00:20 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Ungefaehr so mit den Arrays funktioniert es auf jeden Fall, wichtig ist ja nur, dass die Daten irgendwie ankommen.

Genau wie bei Texturen, die sind schliesslich auch nur Buffer. Du kannst Daten reinschreiben und wieder im Shader auslesen...

Autor:  glAwesome [ Do Mär 29, 2018 07:31 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

mathias hat geschrieben:
Eigentlich Schade, das es kein direkter Weg mit glUniformxxx für struct gibt. :roll:

Doch, gibt es?
Code:
  1. glUniform3f(glGetUniformLocation(program, "lights[0].Color"), r, g, b);

Autor:  mathias [ Do Mär 29, 2018 17:34 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

glAwesome hat geschrieben:
mathias hat geschrieben:
Eigentlich Schade, das es kein direkter Weg mit glUniformxxx für struct gibt. :roll:

Doch, gibt es?
Code:
  1. glUniform3f(glGetUniformLocation(program, "lights[0].Color"), r, g, b);

Ist dieser Befehl nicht, um in eine einfache vec3 Uniform zu schreiben, wen man jeden Wert einzeln übergeben will ?

Dann doch lieber so:
Code:
  1.  glUniform3fv(UniformID.VecColor, 1, @Color);  // Color : TVertex3f

Autor:  glAwesome [ Do Mär 29, 2018 19:08 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Ja. Du hast natürlich Recht, dass es keinen glUniformStruct() oder sowas gibt, mit dem man ein komplettes struct auf einen Schlag mit Werten belegen kann. Ich wollte nur klarstellen, dass man durchaus Index- und Elementzugriffsoperatoren (also [] und .) in glGetUniformLocation() verwenden darf. Du brauchst nicht zwinged UBOs, nur weil eine uniform-Variable ein struct ist.

Autor:  mathias [ Do Mär 29, 2018 19:27 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Ich habe mal folgendes versucht, dies liefert -1, somit ungültig.
Code:
  1. layout (std140) uniform Material {
  2.   vec3  Mambient;   // Umgebungslicht
  3.   vec3  Mdiffuse;   // Farbe
  4.   vec3  Mspecular;  // Spiegelnd
  5.   float Mshininess; // Glanz
  6. };


Code:
  1. //    ShowMessage(IntToStr(glGetUniformBlockIndex(Shader.ID, 'Material')));
  2.     ShowMessage(IntToStr(glGetUniformLocation(Shader.ID, 'Material')));
  3.  


Dies funktioniert wie erwartet auch nicht, auch wen ich die ID mit glGetUniformBlockIndex auslese.
Code:
  1. type
  2.   TMaterial = record
  3.     ambient: TVector3f;      // Umgebungslicht
  4.     pad0: GLfloat;           // padding 4Byte
  5.     diffuse: TVector3f;      // Farbe
  6.     pad1: GLfloat;           // padding 4Byte
  7.     specular: TVector3f;     // Spiegelnd
  8.     shininess: GLfloat;      // Glanz
  9.   end;
  10. ...
  11.   mRubin.ambient := vec3(1,1,1);
  12.   glUniform1fv(Material_ID, SizeOf(mRubin), @mRubin);

Autor:  end [ Fr Mär 30, 2018 12:53 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Das liegt daran, dass die Bloecke aufgesplittet werden und dann Material.foo[0] oder so heissen. Schau dir mal an wie das aussieht indem du mit glGetActiveUniform dir alle moeglichen Uniforms anzeigen laesst inklusive Namen.
https://www.khronos.org/registry/OpenGL ... niform.xml

Autor:  mathias [ Fr Mär 30, 2018 19:35 ]
Betreff des Beitrags:  Re: UBO struct mehrmals verwendet

Das Wiki gibt es sogar in deutsch: https://wiki.delphigl.com/index.php/glGetActiveUniform

Ich habe s probiert, mit folgendem Ergebnis:
Code:
  1. procedure TForm1.MenuItem3Click(Sender: TObject);
  2. var
  3.   s: ansistring;
  4.   i, Count, len, size, typ: integer;
  5.   sl: TStringList;
  6.  
  7. begin
  8.   sl := TStringList.Create;
  9.   SetLength(s, 255);
  10.  
  11.   glGetProgramiv(Shader.ID, GL_ACTIVE_UNIFORMS, @Count);
  12.  
  13.   for i := 0 to Count - 1 do begin
  14.     glGetActiveUniform(Shader.ID, i, 255, len, size, typ, @s[1]);
  15.     sl.Add(copy(s, 0, len) + '    ' + IntToStr(typ));
  16.   end;
  17.   ShowMessage(sl.Text);
  18.   sl.Free;
  19. end;


Ausgabe:
Code:
  1. ModelMatrix    35676
  2. Matrix    35676
  3. Mshininess    5126
  4. Mspecular    35665
  5. Mdiffuse    35665
  6. Mambient    35665


Die Unifom-Blöcke, kann man auch ausgeben.
Code:
  1.   glGetProgramiv(Shader.ID, GL_ACTIVE_UNIFORM_BLOCKS, @Count);
  2.  
  3.   for i := 0 to Count - 1 do begin
  4.     glGetActiveUniformBlockName(Shader.ID, i, 255, @len, @s[1]);
  5.     sl.Add(copy(s, 0, len) + '    ' + IntToStr(typ));
  6.   end;
  7.   ShowMessage(sl.Text);

Ausgabe:
Code:
  1. Material    35665


Dies sind noch recht praktische Funktionen, wen man einen Fehler sucht.

Seite 1 von 1 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/