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

Aktuelle Zeit: Fr Mär 29, 2024 13:00

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



Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
BeitragVerfasst: So Sep 11, 2016 20:31 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 03, 2002 22:12
Beiträge: 2105
Wohnort: Vancouver, Canada
Programmiersprache: C++, Python
Hi,

nachdem ich mich Jahrelang vor dem finalen umstieg auf OpenGL 3 und höher im großen maße versteckt habe, brauche ich glaube ich jetzt grad mal ein klein wenig Hilfe.. :)

Meine bisherigen Erfahrungen mit OpenGL 3+ sind alle nur im Bereich von spezifischen visualisern wo ich meine modelView und projection matrix einfach via glUniform an meinen Shader übergeben habe, genauso die Licht Informationen.

Jetzt habe ich bei meiner Engine allerdings weit mehr als nur einen Objekt mit nur einem Shader.. und ich frage mich, was ist der geschickteste weg die Matritzen und Licht infos zu übergeben? Für die Matritzen kann ich mir ja noch irgendwie vorstellen das die für jeden Shader/Objekt via glUniform gesetzt werden, die Licht daten allerdings auch?

Bei OpenGL 2.0 habe ich die glLight* funktionen benutzt und im Shader darauf zugegriffen, musste also auf CPU seite das ganze nur einmal setzen pro Frame.

Gibt es Shader-Übergreifende-Uniform variablen oder so was ähnliches? Andererseits hat man ja am ende millionen von glUniform calls.. oder nicht?

Danke!
Daniela


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Sep 11, 2016 20:43 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Zitat:
Gibt es Shader-Übergreifende-Uniform variablen oder so was ähnliches? Andererseits hat man ja am ende millionen von glUniform calls.. oder nicht?
Solange, man die Lichposition/Farbe nicht ändert, muss man die Licht-Daten nicht bei jedem Render-Durchgang nei in den Shader schreiben.
Bei der Matrix, ist dies natürlich anders, die ändert meistens bei jedem Render-Durchgang.

Vielleicht kann man was mit UBOs etwas machen, aber dort ist die Anzahl stark begrenzt.

_________________
OpenGL


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Sep 12, 2016 09:56 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich habe ein UBO für die Matrizen und globales Licht. Das geht ganz gut, auch mit OpenGL 3.3 schon:

Code:
  1. #version 330 core
  2.  
  3. layout(std140) uniform MatrixBlock {
  4.    layout(row_major) mat4 proj;
  5.    layout(row_major) mat4 view;
  6.    vec4 sun_colour;
  7.    vec3 sun_direction;
  8.    vec4 sky_colour;
  9.    vec3 world_viewpoint;
  10. } mats;


Da kann man natürlich mehr reinpacken. Der Vorteil an row_major ist, dass ich da ganz einfach C++-Matrizen reinkippen kann. std140 wird gebraucht, damit man das Alignment aus C++ heraus berechnen kann und der GLSL-Compiler da nichts wegoptimieren darf. Damit kann man das UBO über mehrere Shader hinweg verwenden. Das ist ganz nett, sodass man die Daten nur einmal zu Beginn des Frames in das UBO kippt.

Details gibt’s im OpenGL-Wiki. Ein bisschen frickelig ist das Berechnen des Alignments, aber auch das ist dokumentiert (für std140 ist eine PDF verlinkt in der die Alignment-Regeln genau drin stehen).

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: Mo Sep 12, 2016 15:55 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
In die UBO packt man prinzipiell alles, was über die Shader hinweg geteilt wird und Async sein soll.
Ich würde in den UBO ledeglich die Matrizen für die Renderpipeline packen und das licht seperat liefern, da es in der Regel nur im Fragmentshader und auch nicht in jeden gebraucht wird.
UBO's werden automatisch über den Bus synchronisiert, wenn der Treiber ein perfekten Punkt sieht oder spätestens, wenn die Daten gebraucht werden.
Dieser Unterschied macht die Performance zum alten Update der Daten.
Code:
  1. class Bla
  2. {
  3. public:
  4.     void Process();
  5. private:
  6.     struct SharedTransformUniforms
  7.     {
  8.         RF_Geo::Mat4f ModelView;
  9.         RF_Geo::Mat4f ModelViewProjection;
  10.     } m_SharedTransformUniforms;
  11. ...
  12.     void UpdateCamera();
  13. };
  14.  
  15. void Renderer::UpdateCamera()
  16. {
  17.     RF_Type::Float32 forward = -1.0f;
  18.     RF_Type::Float32 up = 1.0f;
  19.     RF_Type::Float32 right = -1.0f;    
  20.  
  21.     up *= m_FPS.Delta() * 0.01f;
  22.     right *= m_FPS.Delta()* 0.01f;
  23.     forward *= m_FPS.Delta()* 0.01f;
  24.  
  25.     if(m_PressedMoveForward)
  26.         m_CameraComponents(m_ActiveCamera).m_Camera.Move(forward);
  27.     if(m_PressedMoveBackward)
  28.         m_CameraComponents(m_ActiveCamera).m_Camera.Move(-forward);
  29.     if(m_PressedStrafeLeft)
  30.         m_CameraComponents(m_ActiveCamera).m_Camera.MoveHorizontal(-right);
  31.     if (m_PressedStrafeRight)
  32.         m_CameraComponents(m_ActiveCamera).m_Camera.MoveHorizontal(right);
  33.     if(m_PressedFlyUp)
  34.         m_CameraComponents(m_ActiveCamera).m_Camera.MoveVertical(up);
  35.     if(m_PressedFlyDown)
  36.         m_CameraComponents(m_ActiveCamera).m_Camera.MoveVertical(-up);
  37.  
  38.     m_SharedTransformUniforms.ModelView = m_CameraComponents(m_ActiveCamera).m_Camera.GetMatrix();
  39.     m_SharedTransformUniforms.ModelViewProjection = m_CameraComponents(m_ActiveCamera).GetProjection() * m_SharedTransformUniforms.ModelView;
  40. // nur notwendig, wenn man mehrere nutzt
  41.     glBindBufferBase(GL_UNIFORM_BUFFER, 2, m_SharedUBO);
  42. // update signalisieren
  43.     glNamedBufferSubData(m_SharedUBO, 0, sizeof(SharedTransformUniforms), &m_SharedTransformUniforms);
  44. }
  45.  
  46. void Renderer::Process()
  47. {    
  48.     RF_Collect::SparseHashMap<RF_Type::UInt64, ZP_Comp::RendererMessage>* messageIn=&m_MessageIn;
  49.     RF_Collect::Queue<ZP_Comp::RendererMessage>* messageOut = &m_MessageOut;
  50.     GenerateNotifications();
  51.        
  52.     // Alle Nachrichten von User, Gamelogik und so weiter an die Komponenten geben(multithreaded).
  53.     if(m_MessageIn.Size() > 0)
  54.     {
  55.         RF_Algo::ForEach(m_RenderComponents, [messageIn, messageOut](RF_Collect::Array<ZP_Comp::RenderBehaviour>::EnumeratorType& Enum) {Enum->ProcessMessages(messageIn, *messageOut); });
  56.         RF_Algo::ForEach(m_CameraComponents, [messageIn, messageOut](RF_Collect::Array<ZP_Comp::CameraBehaviour>::EnumeratorType& Enum) {Enum->ProcessMessages(messageIn, *messageOut); });
  57.         m_MessageIn.Clear();
  58.         // Alle Nachrichten von den Komponenten verarbeiten(sind Nachrichten die nur auf einem bestimmten Thread laufen können z.B. OpenGL, FMod, Scaleform,...).
  59.         ProcessRequests();
  60.     }
  61.    
  62.     glClearColor(0.5, 0.5, 0.5, 1.0);
  63.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  64.     glEnable(GL_DEPTH_TEST);
  65.  
  66.     UpdateCamera();
  67.  
  68.     // Für jeden Renderpass alle Renderbefehle abholen(multithreading).
  69.     for (RF_Type::Size i = 0; i < m_Passes.Count(); ++i)
  70.     {
  71.         RF_Type::UInt64 Pass = m_Passes(i).Name;
  72.         RF_Algo::ForEach(m_RenderComponents, [Pass, messageOut](RF_Collect::Array<ZP_Comp::RenderBehaviour>::EnumeratorType& Enum) {Enum->RenderPass(Pass, *messageOut); });
  73.     }
  74.  
  75.     // Ausführen aller Renderbefehle auf den OpenGL Context gebundenen Thread.
  76.     // Dann ausführen aller anderen Befehle, um möglichst nicht auf die GPU Warten zu müssen.
  77.     ProcessRequests();
  78.    
  79.     // Auf GPU warten, wenn noch nicht fertig.
  80.     m_Canvas->SwapBuffer();
  81.     m_FPS.Update();// frametime erfassen
  82. }


Code:
  1. #version 420
  2. layout(location = 0) in vec3 vertex_position;
  3. layout(location = 1) in vec3 vertex_colour;
  4.  
  5. layout(std140, binding=2) uniform SharedTransformUniforms
  6. {
  7.     mat4 ModelView;
  8.     mat4 ModelViewProjection;
  9. };
  10.  
  11. out vec3 colour;
  12.  
  13. void main ()
  14. {
  15.   colour = vertex_colour;
  16.   gl_Position = ModelViewProjection * vec4(vertex_position,1);
  17. }

Ich übergebe schon die ModelViewProjection Matrix, damit die nicht im Vertex Shader immer wieder aus den einzelnen Matrizen berechnet werden muss.
Auf der CPU kostet mich das nur einmal 36 Multiplikationen und auf der GPU wären das für jedes Vertex 36 Multiplikationen und so sind es 12.

Wie Lord Horazont schon erwähnt hat, sollte man drauf achten, das die Lineare Algebra Lib die Matrizen im passenden Format im Speicher ablegt aber beim padding muss mich sich dann eher keine gedanken machen, wenn man nur mit floats arbeitet.

Ich nutze binding slots, da die API viel verständlicher und schneller ist, als es über Namen aufzulösen.
Der UBO wird als letztes gebunden, weil ich das im Code sinniger empfand.
Erst baut man seine VBO und packt die in ein VAO, da kann man schon die ersten beiden binden und in der Renderloop oder beim erzeugen vom UBO tut man dann das UBO binden.

Man hat selten ein Licht, daher macht es sinn ein VBO/UBO dafür zu haben, je nach wie du dein Licht renderst(forward, forward+, deferred lighting).

Super Buch zu OpenGL4.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Sep 12, 2016 19:45 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 03, 2002 22:12
Beiträge: 2105
Wohnort: Vancouver, Canada
Programmiersprache: C++, Python
Ah, ich hatte UBOs total vergessen - danke :D

Zwei fragen habe ich allerdings noch:

  • Tak, so wie ich deinen Code verstehe setzt du die matritzen nur einmal pro frame, bzw wenn sich die Camera bewegt? Uebergibst du dann die lokale objekt matrix nochmal separat an den shader und multiplizierst diese dann im Shader? Oder missverstehe ich etwas? :)
  • Was ist denn aktuall der ideale weg die Licht informationen bei einem normalen Forward renderer an den Shader zu uebergeben? Ein UBO mit vordefinierten platz fuer X lichter und einem extra "numLights" um zu wissen wieviele lichter verwendet werden?

Danke,
Daniela


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Sep 12, 2016 20:07 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 31, 2002 19:41
Beiträge: 1276
Wohnort: Bäretswil (Schweiz)
Programmiersprache: Pascal
Zitat:
Uebergibst du dann die lokale objekt matrix nochmal separat an den shader und multiplizierst diese dann im Shader? Oder missverstehe ich etwas? :)
Nein, dieser multipliziert er mit der CPU.
Die einte Matrix wird für die Polygon-Berechnung gebraucht (gl_Position).
Die zweite, nur für die Lichtberechnung. Normalerweise, müsste mit Modellview noch mit inNormal berechnet werden.
Ich denke, in seinem minimal Shader will er nur zeigen, wie die mit den UBOs geht.

_________________
OpenGL


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Sep 12, 2016 23:19 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ja, es ist ein minimalshader, den man für statische world modelle oder instancing nutzen kann.
Normalerweise hast du noch eine normale model matrix oder position und quaternion für das positionieren aber das würde ich nicht in ein UBO packen.

Ja ich würde für ein forward renderer auch so vor gehen.
Je nach wieviele lichter du hast braucht man Optimierungen, z.b. Die objekte nach den lichtern zu sortieren, damit wenige Änderungen am UBO benötigt werden.
Aber erstmal gucken wie weit dich der Vorschlaghammer bringt.
Die matrizen per UBO bringen schon ordentlich Performance.
Wenn du da einfache 16 lichter oder so hast juckt es die Grafikkarte eher wenig.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 40 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:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.102s | 19 Queries | GZIP : On ]