Posts by 2#4u

    Bis jetzt funktioniert er allerdings nicht (Ergebnis ist ein schwarzer Screen)


    Ok. Schwarzer Screen finde ich grundsätzlich mal sehr verdächtig. Wenn ihr einfach nur im Fragment-Shader mit den UVs die fboTexture sampled, kommt dann überhaupt die gerenderte Szene auf den Bildschirm? Wenn nicht, dann enhält euer FBO nicht die gerenderte Szene.



    Schritt 1 des Chapman-Tutorials wird beschrieben mit: "Get the pixel's current view space position. [...] I use a per-pixel ray to the far plane, multiplied by a per-pixel linear depth." Was heißt das genau? Ich hab auch öfters gelesen, dass man sich in diesem Zusammenhang irgendwie die Pixel-Tiefenwerte vom Z-Buffer holen muss (oder durch eine Tiefentextur), allerdings kann ich mir darunter nicht viel vorstellen.


    Das ist vermutlich der einzig schwierige Teil beim Motion-Blur.


    Was ihr derzeit in der ersten Zeile eures Fragment-Shaders macht, ist, dass ihr von der FBO Textur den Rot-Kanal sampled und mit dem viewRay multipliziert. Das ist falsch.
    Hier muss eigentlich eine Textur mit den Tiefenwerten eurer Szene gesampled werden.
    Initial müsst ihr ein FBO erstellen mit einem Color-Attachment und einem Depth-Attachment und beides in jeweilige Texturen speichern.
    Das heißt, dass im Color-Attachment dann die gerenderte Szene drinnen ist und im Depth-Attachment die nicht-linearen Tiefenwerte der Scene.
    Siehe auch: http://www.opengl-tutorial.org…ial-14-render-to-texture/
    Die Depth Texture muss beim FBO initialisieren erstellt werden, und dem FBO zugewiesen werden:

    Code
    1. glGenTextures(1, &depthBufferTexture);
    2. glBindTexture(GL_TEXTURE_2D, depthBufferTexture);
    3. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, viewportWidth, viewportHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    4. glTexParameteri(...)
    5. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthBufferTexture, 0);


    Wenn ihr die Position von den Tiefenwerten wiederherstellen wollt, dann kann ich einen Ansatz wie den folgenden empfehlen:
    http://http.developer.nvidia.com/GPUGems3/gpugems3_ch27.html




    EDIT: Wenn es einen einfacheren Ansatz als den von Chapman gibt, bin ich auch für den offen!


    Ich glaub nicht, dass es viel einfacher geht. Im Endeffekt werdet ihr vermutlich mit einem Mix von Chapman und dem GPU Gems Artikel (siehe Link oben) arbeiten.

    Erstmal, sehr gut!


    Bezüglich dem "Fragment Shader recompiled": Das ist mehr oder weniger ok, falls es nur einmalig auftritt bzw. nicht jedem Frame. Es kostet halt einmalig (typischerweise im ersten Frame) Performance, aber es ist nicht tragisch. Ursachen dafür sind so vielfältig, dass ich das ignorieren würde.


    Bezüglich VAO binden: Es ist vermutlich am einfachsten, wenn ihr immer vor dem Zeichnen das VAO bindet. In den meisten Fällen wird das reichen.

    Habt ihr einen Debug-Kontext eingebaut und wirft der irgendwelche Fehler/Informationen?



    Seit einigen Commits sieht es bei ihm plötzlich so aus:


    Das ist ja dann schon einmal eingrenzbar. Schaut euch die Unterschiede zwischen den Commits an und versucht das Problem somit auf Codezeilen zu begrenzen.
    Debug-Kontext nicht vergessen.


    Bezüglich UV-Koordinaten:
    Wiederum: Debug-Kontext? Ansonsten, prüfen ob wirklich nur eine Plane gezeichnet wird (es sollten genau 2 Dreiecke sichtbar sein, wenn ihr im Wireframe Modus rendert und im Fragment-Shader zB rot ausgebt).


    Probiert das mal und meldet euch dann mit den Ergebnissen wieder.

    Also wie vorher schon erwähnt, das funktioniert so nicht.



    Als Texturkoordinaten habe ich "in vec2 UV", also die interpolierten Werte vom Vertex Shader, und auch die Textur ist weiterhin "uniform sampler2D textureSampler".


    Die Frage war eigentlich welche Textur sich hinter dem Sampler verbirgt.
    Und ich nehme an, dass es nicht die Textur der gerenderten Szene ist, sondern einfach irgendwas (zB die Textur eines Objektes).


    Ich hab's eh schon im vorigen Post beschrieben wie der Ablauf in etwa aussieht.
    Du brauchst um das Tutorial umzusetzen Basiswissen darüber wie man eine Szene in eine Textur rendert. Einen Einstieg dazu gab es im Repetitorium; Die Folien sind im Wiki.


    Zurzeit sieht es so aus, dass ich den bisherigen Fragment Shader (also mit Diffuse, Ambient und Specular Lighting) durchlaufen lasse (als Methodenaufruf in der selben Datei) und daraufhin die Methode fuer den Lens Flare Effekt auf das Ergebnis anwende.


    Wenn ich dich richtig verstehe, dann hast du den existierenden Fragment Shader für die Beleuchtung umgeschrieben?
    Das kann nicht funktionieren.
    Vor allem was heißt dann du hast "den Lens Flare Effekt angewendet"? Auf welcher Textur arbeitest du denn und welche Texturkoordinaten benutzt du?


    Grundsätzlicher Ablauf laut dem Tutorial ist so:
    - Szene in eine Textur rendern (siehe auch FBO Tutorial)
    - Thresholding und optionales Downsamplen (d.h. kleinere Textur) (siehe zB Bloom Tutorial)
    - Die gespiegelten Ghosts erzeugen
    - Etwaige andere Effekte wie Halos, Chromatic Abberation, Dirt, Blur, ... anwenden
    - Die damit erzeugte Lens Flare Textur dann mit der gerenderten Szene wieder zusammenführen (blenden)


    Ihr habt euch da ein eher aufwändigeres Tutorial rausgesucht.
    Lens Flares sind in der Effektliste nur 0.5 Punkte wert. Das gilt dann, wenn man vor allem mit Sprites arbeitet.
    Wenn ihr wirklich nach der Anleitung vorgeht, dann gibt es mehr Punkte. Das kommt aber darauf an wieviel und was ihr da jetzt alles von dem Tutorial umsetzen wollt.


    Für 0.5 Punkte kann man ungefähr wie folgt vorgehen:
    http://www.emagix.net/academic/item/lens-flares
    (oder seht euch die Resourcen in dem Artikel an)
    Ich hab auf die Schnelle kein besseres Tutorial gefunden.

    Ok. Ich hab mir das jetzt angesehen.


    Punkt 1: Per default ist bei mir kein DoorNode in "ModelLoader::getInstance()->root->children". Das heißt "if (dn != nullptr)" ist nie erfüllt.
    -> Das hab ich mal "gefixt", indem ich testweise einen DoorNode in der ModelLoader::load hinzugefügt habe:

    Code
    1. root = [COLOR=blue]this[/COLOR]->processNode([COLOR=blue]nullptr[/COLOR], scene->mRootNode, scene);[COLOR=green]// Process ASSIMP's root node recursively[/COLOR]
    2. root->children.push_back([COLOR=#6f008a]new[/COLOR] [COLOR=#2b91af]DoorNode[/COLOR]()); [COLOR=#008000]// <- diese Zeile hinzugefügt.[/COLOR]


    Punkt 2: Dann hab ich das ganze nochmal ausprobiert und keinerlei Probleme gehabt. D.h. nachdem "action()" aufgerufen wurde, war die open Variable "true" (zu sehen im Debugger)


    Punkt 3: Um sicher zu gehen, dass "ModelLoader::getInstance()->root->children" immer die selbe Liste liefert, hab ich nach der Schleife in RenderLoop::keyCallback() nocheinmal über die gleiche Liste iteriert und geprüft, ob "open" true bleibt. Tut es.


    Ich seh das Problem nicht...

    Dumme Frage, aber seid ihr sicher, dass keyPress nur einmal aufgerufen wird?


    Bzw. habt ihr probiert das Problem zu debuggen?
    Das heißt folgenden Code debuggen:

    Im Wesentlichen ist das alles richtig.
    Was mir bei euch aufgefallen ist, ist dass ihr die Normalen im Fragment-Shader nicht normalisiert. Das ist notwendig, da interpolierte, normalisierte Normalen nicht zwangsläufig wieder eine normalisierte Normale ergeben.


    Das ist hier aber nicht euer "Problem".
    Was ihr hier sehen könnt, ist die Auswirkung des diffusen Terms des Beleuchtungsmodells.
    Nachdem die Normale der hinteren Wand sehr ähnlich zur Lichtrichtung ist, ist eure diffuse Beleuchtung sehr hoch!
    Die diffuse Beleuchtung des Bodens, der Decke und der Seitenwände ist abhängig davon wie weit diese von der Lichtquelle weg sind, denn (!!) der Einfallswinkel des Lichts wird immer flacher (zur Normale), je weiter der Punkt an der Wand weg ist.
    Bei der hinteren Wand ist es jedoch so, dass es keine (oder kaum eine) Rolle spielt wie weit die hinten ist, denn das Licht trifft dort praktisch immer steil auf.


    Der diffuse N.L Teil ist praktisch in jedem Beleuchtungsmodell enthalten, dass heißt Beleuchtungsmodell wechseln wird nix bringen.
    Was ihr machen müsst um das abzuschwächen, ist genau das was ihr eh schon angesprochen habt. Ihr müsst die Attenuation der Lichtquelle entsprechend anpassen, damit ein stimmiges Bild entsteht.
    Ohne Attenuation wird die hintere Wand genauso leuchten, auch wenn sie 2 km weit weg ist.


    Eine weitere Möglichkeit ist, weg von Point-Lights hin zu Spot-Lights zu gehen, weil der Lichtkegel dann genauer steuerbar ist und dementsprechend das Licht gar nicht in die Richtung der hinteren Wand geht. Oder ihr 'erfindet' eine andere Lichtquelle die nicht uniform abstrahlt, sondern mehr Licht nach unten (bei einer Deckenleuchte) abgibt, als zur Seite. Das könnte man machen indem man den Winkel zwischen Normale der Decke N_d (wo die Lampe hängt) und Lichtvektor -L (von Lichtquelle zu beleuchtetem Punkt) berücksichtigt und die Intensität abschwächt, je flacher der Winkel zwischen -L und N_d wird.
    Ich hab das jetzt nicht ausprobiert, aber das wäre eine Idee die mir einfällt. Spotlights und Attenuation sind aber vermutlich die besseren Ideen.


    Ambient Occlusion könnte auch ein wenig helfen in den Ecken und Kanten der Wände, aber es löst das Problem nicht.

    Ziel der LVA ist in erster Linie den Umgang mit OpenGL bzw. Shader zu erlernen. Wenn ihr Berechnungen auf die GPU zB mittels Compute-Shader auslagert, können wir bei einer konkreten Idee über Punkte reden.
    Multithreading / Synchronisierung / Parallelisierung sind zum einen ein viel zu breites (d.h. wenig konkretes) Thema und zum anderen kein Topic dieser LVA.
    Daher können wir dafür auch keine Punkte vergeben.


    Sollte es zu Performanceproblemen kommen und ihr keine Maßnahmen dagegen ergreifen möchtet (z.B. parallel for loops oder Threads) dann müsst ihr halt entsprechend weniger Gegner machen, damit es am Abgaberechner läuft.

    Ok. Ich hab mich etwas umgesehen. Es scheint so als ob das einfach so ist mit den Defaultvalues.


    Vielleicht als Hilfe für eure Implementierung: Eine Specular-Color, die Schwarz ist macht vielleicht gar keinen Sinn. Wenn ihr wollt, dass etwas wenig specular ist, dann solltet ihr nicht die Farbe verändern, sondern die shininess.

    Also ich geh auch mal davon aus, dass A,B,X,Y natürliche Zahlen sind.
    Zu lesen wäre dann die Aufgabe wie folgt:
    Für alle A existiert ein B und für alle X und für alle Y gilt:
    - dass B größer als A ist UND
    - falls X und Y größer als 1 sind FOLGT dass das Produkt X*Y nicht B ergeben darf und das Produkt nicht B + 2 ergeben darf


    Das heißt ich würde mir mal Beispiele ansehen, wo eben B > A ist und X,Y > 1 und nachsehen wieviele X,Y Kombinationen es gibt die diese Produkte ergeben.
    Das gibt dann hoffentlich ein Gefühl für das Beispiel.


    Übrigens ist theoretische Informatik bei mir schon ein paar Jahre her, das heißt, keine Garantie auf meine Interpretation hier.

    Vielleicht könnt ihr Code wie diesen einsetzen:

    Code
    1. [COLOR=blue]float[/COLOR] specular[3];
    2. [COLOR=blue]unsigned[/COLOR] [COLOR=blue]int[/COLOR] max = 3;
    3. [COLOR=blue]if[/COLOR] (aiGetMaterialFloatArray(aiMat, [COLOR=#6f008a]AI_MATKEY_COLOR_SPECULAR[/COLOR], specular, &max) == [COLOR=#6f008a]AI_SUCCESS[/COLOR])
    4. {
    5. // success
    6. }


    Ich hab diesen Code jetzt nicht getestet, aber theoretisch sollte es keinen success geben, wenn nichts vorhanden ist.

    Meine Antwort zu dem ganzen:


    @1:
    Zum Beispiel:

    Code
    1. [COLOR=blue]
    2. auto[/COLOR] translate = glm::translate(glm::mat4(), glm::[COLOR=#2b91af]vec3[/COLOR](1, 2, 3));[COLOR=blue]
    3. auto[/COLOR] operation = glm::scale(translate, glm::[COLOR=#2b91af]vec3[/COLOR](8, 9, 10));


    Wenn man soetwas macht, dann ist 'operation' eine Matrix, die zuerst skaliert und dann verschiebt. Also genau umgekehrt zu dem was man vielleicht erwartet.


    Meiner Meinung nach intuitiver kann man so arbeiten:

    Code
    1. [COLOR=blue]
    2. auto[/COLOR] eye = glm::[COLOR=#2b91af]mat4[/COLOR](); // identity matrix[COLOR=blue]
    3. auto[/COLOR] scale = glm::scale(eye, SKALIERUNGSVEKTOR);[COLOR=blue]
    4. auto[/COLOR] rotate = ... // was auch immer man hier braucht[COLOR=blue]
    5. auto[/COLOR] translate = glm::translate(eye, POSITIONSVEKTOR);
    6. modelMatrix = translate * rotate * scale;


    Das hat insgesamt ein paar mehr Rechenoperationen, aber es erschließt sich sofort wie die Matrizen zusammengehängt werden (letzte Zeile).


    @2
    Hier kommt es meiner Meinung nach darauf an wie ihr arbeiten möchtet.
    Ihr könnt natürlich so vorgehen, wie 'klj' bereits geschrieben hat. Oder falls ihr physikalisch korrekte Berechnungen durchführen möchtet, dann braucht ihr bei eurer Variante noch eine Kraft die nach innen wirkt und das Objekt auf der Kreisbahn hält.


    Aber was ihr wahrscheinlich haben wollt ist auch mit Transformationsmatrizen umsetzbar.
    Nehmen wir an ihr habt die Erde und den Mond. Der Mond soll um die Erde kreisen und die Umlaufbahn soll schräg zur Ebene sein auf der die Erde um die Sonne rotiert.
    D.h. Erde hat eine bestimmte Position p_e, Mond hat einen bestimmten Abstand (d) zur Erde und Erde hat eine bestimmte Neigung für die Bahnebene des Mondes.


    Daher:
    Translationsmatrix T für Erde mit Position p_e
    Translationsmatrix M für Mond relativ zu Erde mit zB Translationsvektor (d, 0, 0)
    Rotationsmatrix N für Neigungswinkel der Erde. Z.B. Rotation um Z-Achse des Systems mit Winkel beta.
    Rotationsmatrix R für Mond um die Erde. Z.B. Rotation um Y-Achse des Systems mit Winkel alpha.


    Die finale Position für den Mond ergibt sich dann als:
    T * N * R * M * position


    Ich leg jetzt nicht meine Hand ins Feuer, aber ich glaube es stimmt.
    Was hier passiert ist folgendes:
    1. Am Anfang ist Mond und Erde an der selben Position
    2. Der Mond wird von der Erde weggeschoben, um seine Distanz
    3. Der Mond wird um die Erde rotiert um alpha
    4. Das System Mond/Erde wird geneigt um beta
    5. Das System Mond/Erde wird positioniert auf Punkt p_e


    Für jedes Frame erhöht ihr dann den Winkel alpha, berechnet die Rotationsmatrix R und multipliziert die anderen Matrizen darauf.