Allgemeine Fragen zu JOGL2 / OpenGL3.2

Marco13

Top Contributor
Ich bastle gerade an ein paar Hilfsklassen für (mein) JOGL-Rendering-Zeug (Shader, RenderableObject, BufferObject...) und versuche, das ganze mit reinem Core-GL3.2, also mit JOGL2 zu machen.

Dazu ein paar Fragen... teilweise vielleicht ein bißchen schwammig :oops: aber auch subjektive Antworten darauf könnten interessant sein...

1.
Im Hinblick auf http://www.java-forum.org/spiele-mu...098-jogl-button-klick-problem.html#post597369 stellt sich mir die Frage, ob es legitim ist, in der "init"-Methode das GL zwischenzuspeichern, und in der "display" zu verwenden. Kann man davon ausgehen, dass das GL, das man sich beim display vom Drawable abholt, IMMER dasselbe ist, wie das, was man sich schon beim init abholen konnte? Der Doku nach müßte es eigentlich so sein, aber es ist nirgendwo verbindlich gesagt ???:L Könnte es da krachen, wenn man z.B. das Fenster vergrößert, während er gerade anfängt, "display" aufzurufen, und dort noch das "alte" GL vom vorigen init-Aufruf verwendet wird?

2.
Das GLJPanel war wohl bisher immer noch "ein bißchen beta", aber kann es sein, dass es bei JOGL2 (was ja selbst noch beta ist) dort noch größere Probleme gibt, und tendenziell häufiger mal nur ein graues Fenster zu sehen ist?

3.
Wenn ich bei JOGL2 einen Animator verwende, sehe ich nur flackernde, halb-gemalte Bilder ... ist das noch ein generelles Problem von JOGL2 (was ja noch beta ist ;)), oder kann man davon ausgehen, dass ich da irgendwo ein glFlush oder irgendein vSync vergessen/falsch eingestellt habe?

4.
Ich hab' zwar gerade die (400seitige :autsch:) OpenGL3.2 Spez offen, aber ... es ist für mich nicht ganz ersichtlich, ob es für das Binden und Setzen von Attributen Beschränkungen in bezug auf den Zeitpunkt bzw. den Kontext gibt, wo das passsieren darf. Im speziellen: Muss das Binden und Aktivieren (bei JOGL2) immer auf dem "aktuellen" GL durchgeführt werden, oder reicht es, das EINmal auf "irgendeinem" GL durchzuführen. Also, MUSS man das Zeichnen nach diesem Muster machen
Java:
void draw(GL3 gl)
{
    int x = gl.glGetAttribLocation(id, "x");
    gl.glEnableVertexAttribArray(x);
    gl.glVertexAttribPointer(x, ...);
    gl.glDrawArrays(GL.GL_TRIANGLES, 0, n);
}
oder könnte man auch sowas machen wie
Java:
void init(GL3 gl)
{
    int x = gl.glGetAttribLocation(id, "x");
    gl.glEnableVertexAttribArray(x);
    gl.glVertexAttribPointer(x, ...);
}

void draw(GL3 gl) // Aufruf ggf. mit anderem GL als 'init'....
{
    gl.glDrawArrays(GL.GL_TRIANGLES, 0, n);
}
?
Ich könnte mir vorstellen, dass letzteres NICHT geht, aber darf man das dann z.B. machen wenn man ein VAO verwendet, DAS dann in der init-Methode (unter verwendung eines bestimmten GL) füllt, und in der draw dann (mit einem anderen GL) sowas macht wie
Java:
void draw(GL3 gl) // Aufruf ggf. mit anderem GL als 'init'....
{
    gl.glBindVertexArray(vao);
    gl.glDrawArrays(GL.GL_TRIANGLES, 0, n);
}
?

(Ein präventives "Danke" an "Guest2" ;))
 
G

Guest2

Gast
Moin,

1.
Im Hinblick auf http://www.java-forum.org/spiele-mu...098-jogl-button-klick-problem.html#post597369 stellt sich mir die Frage, ob es legitim ist, in der "init"-Methode das GL zwischenzuspeichern, und in der "display" zu verwenden. Kann man davon ausgehen, dass das GL, das man sich beim display vom Drawable abholt, IMMER dasselbe ist, wie das, was man sich schon beim init abholen konnte? Der Doku nach müßte es eigentlich so sein, aber es ist nirgendwo verbindlich gesagt ???:L Könnte es da krachen, wenn man z.B. das Fenster vergrößert, während er gerade anfängt, "display" aufzurufen, und dort noch das "alte" GL vom vorigen init-Aufruf verwendet wird?

Also das gl Objekt kann grundsätzlich während der Laufzeit ungültig werden. Dies geschieht z.B. wenn ein GLCanvas zwischen Fenster und Vollbild wechselt. Bei einem GLJPanel passiert dies wohl auch schon mal einfach so. Bei einem GLWindow hab ich es noch nicht beobachtet (zumindest nicht wenn es native ist).

Allerdings wird dann nicht nur das gl Objekt ungültig, sondern der gesamte OpenGL Kontext, d.h. alle Texturen, Shader, VA, VBO, usw. sind erst mal ungültig. Würde dies also passieren während gerade die display() angestoßen wird, würde sich eh die komplette VM verabschieden, völlig unabhängig ob das gl aus der init() oder der display() kommt.

Praktisch wird also auch immer die init() neu aufgerufen, bevor die display() mit einem neuen gl angestoßen wird. Ich (persönliche Meinung) finde es deshalb legitim das gl aus der init() heraus zwischenzuspeichern. Man muss allerdings drauf achten, das bei einem erneuten init() Aufruf (durch ein GLEvent) auch wirklich alle zwischengespeicherten gl neu gesetzt werden.

So haben z.B. vieler meine "OpenGL3 Objekte" ein bind(), die ein gl Objekt benötigt. Und ich habe einfach wenig Interesse überall das gl oder das drawable mit durchzureichen (von der Wartbarkeit mal ganz zu schweigen).

(Allerdings: Ihmo sehen / sahen das die JoGL Macher das zumindest früher anders und empfehlen / empfahlen das drawable überall durchzureichen. Ihmo kommt dies aber mehr aus einem "wir schützen die Nutzer" als aus einer technischen Notwendigkeit. Ich hab das mal versucht konsequent durchzuziehen und nuja, wenn das Programm komplexer wird, gibt das eine Bindung wie Beton zwischen den Objekten)

2.
Das GLJPanel war wohl bisher immer noch "ein bißchen beta", aber kann es sein, dass es bei JOGL2 (was ja selbst noch beta ist) dort noch größere Probleme gibt, und tendenziell häufiger mal nur ein graues Fenster zu sehen ist?

Ich befürchte da kann ich nicht sonderlich weiter helfen. Bis auf heute Morgen im "JoGL Button Klick" benutz ich das selber ungern. Und ihmo kann man es auch vermeiden wenn man es wirklich will. Im Nachbarthread gab's halt JMenu und GLCanvas und das beißt sich gewaltig. Dem lesen nach sollte das GLJPanel aus JoGL2 aber stabiler als das aus JoGL1 sein (was auch immer das heißt ;) ) (und schneller soll es auch sein).

3.
Wenn ich bei JOGL2 einen Animator verwende, sehe ich nur flackernde, halb-gemalte Bilder ... ist das noch ein generelles Problem von JOGL2 (was ja noch beta ist ;)), oder kann man davon ausgehen, dass ich da irgendwo ein glFlush oder irgendein vSync vergessen/falsch eingestellt habe?

Gute frage, bei mir ist das nicht so ;) Ich hoffe also darauf, dass es kein generelles Problem ist. Und glFlush() oder besondere vSync Einstellungen hab ich auch nicht. Wobei tritt das den bei Dir auf (GLJPanel / GLCanvas / GLWindow / GLWindow native)?

(Wenn es GLWindow (egal ob native oder nicht) ist, dann geht der JoGL Animator nicht. Bei mir stirbt der dann sogar. Das liegt daran das der Animator einen eigenen Thread startet, aber das GLEvent aus demselben Thread kommen muss der auch das GLWindow erstellt hat. Da geht also nur selber machen (dafür ist das native GLWindow dann aber auch sau schnell ;) ))

(Läuft den z.B. das gl3sample00 bei Dir? (ist allerdings auch nur GLCanvas))

4.
Ich hab' zwar gerade die (400seitige :autsch:) OpenGL3.2 Spez offen, aber ... es ist für mich nicht ganz ersichtlich, ob es für das Binden und Setzen von Attributen Beschränkungen in bezug auf den Zeitpunkt bzw. den Kontext gibt, wo das passsieren darf. Im speziellen: Muss das Binden und Aktivieren (bei JOGL2) immer auf dem "aktuellen" GL durchgeführt werden, oder reicht es, das EINmal auf "irgendeinem" GL durchzuführen.

Also, ich speichere das handle immer zwischen (wenn es nicht gerade ein kskb ist). Allerdings werden bei einem neuen init() alle handles ungültig und das handle für "mv" bei Shader A ist was anderes als das handle für "mv" bei Shader B.

Genau genommen habe ich alle möglichen "Sachen" die ein handle haben können in einem enum (mv, p, v, n, ...). Wenn ich den shader linke hole ich anschließend sofort alle handles und speicher diese als map (wenn es was im aktuellen shader nicht gibt, gibt OpenGL -1 zurück und nix schlimmes passiert).

Beim binden das shaders (nur dann sind die Einträge der map gültig) könnte die map so direkt an alle "Nutzer" durchgereicht werden. Bei mir setzt der shader beim binden allerdings die map direkt in das enum, so dass alle "Nutzer" über das enum an die aktuell gültigen handles kommen.

Das sieht dann beim "Nutzer" etwa so aus:

Java:
gl.glEnableVertexAttribArray(Handles.VERTEX.getCurrentHandle()); 
gl.glVertexAttribPointer(...) 
gl.glDrawArrays(...);

Die glVertexAttribPointer() müssen (immer wieder) vor dem glDrawArray() neu gesetzt werden. Die glEnableVertexAttribArray() hingegen bleiben gültig, bis das Du neue setzt.

Die Lösung mit der Rückgabe an das enum hat zwar was verrucht statisches, hat aber auch Vorteile:

1. Es gibt nur noch eine Stelle im Code, in der die Variablenbezeichnungen der Shader auf Bezeichner im Code abbildet werden.

2. Außerhalb der init() werden nie irgendwelche Attibutlocations abgefragt.

3. Wenn es nicht gerade nur ein kskb ist, kann es passieren, dass ein einzelnes frame z.B. so erstellt wird:

Code:
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

// füllen des depth buffer
objA mit shaderV
objB mit shaderV
objC mit shaderV

// shadow volume
objB mit shaderX
objC mit shaderX

// color pass
objA mit shaderY
objB mit shaderY
objC mit shaderY

// post image pass
objA mit shaderZ

Ohne map /enum verklebt das durch die vielen handle = glGetAttribLocation(shaderID, shaderVariable) zu einem unschönen Brei. Bei der enum Lösung hingegen gilt Handles.VERTEX.getCurrentHandle() immer, egal wann, egal wo, egal wie ;)

(100%tig zufrieden bin ich damit aber trotzdem nicht. Andererseits ist OpenGL nun mal nicht Objektorientiert und irgendwo zwickt es immer ;) )

Nichtsdestotrotz bin ich bei diesem Punkt besonders gespannt zu was für einer Lösung Du da kommst ;)

(Ein präventives "Danke" an "Guest2" ;))
Sehr gerne ;)

Gruß,
Fancy
 

Marco13

Top Contributor
Dacht' ich's mir :D

Also das gl Objekt kann grundsätzlich während der Laufzeit ungültig werden. ...

Allerdings wird dann nicht nur das gl Objekt ungültig, sondern der gesamte OpenGL Kontext, d.h. alle Texturen, Shader, VA, VBO, usw. sind erst mal ungültig. ...

Das leuchtet mir jetzt nicht ganz ein. Ich hatte dann noch in besagter Sepz rumgepflügt, und dort steht:
Objects that can be shared between contexts include pixel and vertex buffer objects,
program and shader objects, renderbuffer objects, sync objects, and texture
objects

Wenn diese Objekte ungültig würden, dann würde das ja bedeuten, dass man bei jeder Fenstergrößenänderung alles neu laden, neu binden und neu initialisieren müßte ???:L (Vielleicht ist es auch ein Fehler, wenn ich von einer 1:1-Entsprechung zwischen einem ("nativen") GL-Context und einem Java GL-Objekt ausgehe?)

Das absurdeste ist aber:
Framebuffer, query, and vertex array objects are not shared.

Man kann alles sharen außer dem "obersten objekt", dem VAO, das alle VBOs zusammenfasst!? Ich hoffe, die Tatsache, dass das für mich überhaupt keinen Sinn macht hängt mit einem mangelnden Verständnis von VAOs zusammen... ???:L


So haben z.B. vieler meine "OpenGL3 Objekte" ein bind(), die ein gl Objekt benötigt. Und ich habe einfach wenig Interesse überall das gl oder das drawable mit durchzureichen (von der Wartbarkeit mal ganz zu schweigen).

Im Moment bewege ich mich mit meinen Basteleien (wie man merkt) auf ziemlich dünnem Eis - aber diese Methode gab's jetzt in meinen Hilfsklassen zum Teil auch. Jetzt ist es so, dass z.B. Buffer mit einem GL erstellt und gefüllt werden, und mit einem anderen GL dann gebunden und benutzt. Zusätzlich muss an manchen Stellen neben dem GL noch das "program" weitergereicht werden, auf das sich dann die Attributes beziehen sollen (du hattest das in einem deiner Beispiele mit einer statischen Methode gelöst... hm.)

Ich finde das Rumreichen des GLs zwar an sich auch unschön, aber es ist nunmal so: Man kann ja ohne ein GL nichts machen. Du meintest jetzt, dass das eine "Bindung wie Beton" zwischen den Objekten gibt - ich sehe da jetzt erstmal keine "Bindung", außer dass bei etlichen Methoden das "GL" als Parameter dabeisteht (wenigstens heißt die Klasse nicht "OpenGraphicsLibrary" ;)).

Ich sehe aber spontan kaum Alternativen. Die Klassen alle "GLEventListener" sein zu lassen hilft zwar ein wenig, wenn (falls) man das GL zwischenspeichern darf, aber das erkauft man sich mit dem Rumreichen des GLAutoDrawable und damit, dass es IMHO SEHR schwer (d.h. auch frickelig und fehleranfällig) ist, diese Listener wieder zu removen, wenn sie nicht mehr gebraucht werden... :(



Dem lesen nach sollte das GLJPanel aus JoGL2 aber stabiler als das aus JoGL1 sein (was auch immer das heißt ;) ) (und schneller soll es auch sein).

Ich hatte den Beitrag auf der Arbeit geschrieben :oops: und speziell die beiden Punkte vorhin nochmal probiert: Neben dem grauen Fenster erscheint bim GLJPanel (bei mir) auch noch eine kleine unbedeutende Exception: Offenbar funktioniert das GLJPanel grundsätzlich (noch) nicht mit einem reinen GL3 - zumindest haut's ihn bei mir bei
Java:
        GLProfile profile = GLProfile.get(GLProfile.GL3);
        GLCapabilities capabilities = new GLCapabilities(profile);
        final GLJPanel glComponent = new GLJPanel(capabilities);
raus:
Code:
Exception in thread "AWT-EventQueue-0" javax.media.opengl.GLException: Not a GL2 implementation
	at com.sun.opengl.impl.gl3.GL3Impl.getGL2(GL3Impl.java:6908)
	at javax.media.opengl.awt.GLJPanel$Updater.display(GLJPanel.java:573)
        ....
Das ist bestimmt dem beta-Status geschuldet... muss mal schauen wann es da eine neue Version gibt. Oder gibt's einen Trick, wie man das doch (mit einem GL3) zum Laufen kriegt?


Das mit dem Animator hat sich übrigens erledigt. Was auch immer da nicht gestimmt hat, jetzt scheint es zu funktionieren (... das besagte dünne Eis... irgendwie wirkt da vieles ziemlich undeterministisch, aber wahrscheinlich muss ich die Spez einfach noch "ein paar mal" lesen :oops: )

(Läuft den z.B. das gl3sample00 bei Dir? (ist allerdings auch nur GLCanvas))

Ja, hab's gerade mal getestet. (Auch dort kommt mit dem GLJpanel die beschriebene Exception... wenigstens ist DAS jetzt also vermutlich NICHT mein Fehler ;))


Also, ich speichere das handle immer zwischen ...
[...]
Die glVertexAttribPointer() müssen (immer wieder) vor dem glDrawArray() neu gesetzt werden. Die glEnableVertexAttribArray() hingegen bleiben gültig, bis das Du neue setzt.

So 100% konnte ich es jetzt nicht nachvollziehen, aber eine grobe Vorstellung habe ich wohl bekommen. Ich setze die AttribPointer übrigens nicht jedes mal neu, und es funktioniert - ist das jetzt Glück? Oder ist die Begründng die, dass ich das ganze an ein VAO binde, und sie dadurch erhalten bleiben? (Aber das VAO selbst dürfte ja eigentlich NICHT erhalten bleiben ... wahh :autsch: )

Die Lösung mit der Rückgabe an das enum hat zwar was verrucht statisches, hat aber auch Vorteile:

1. Es gibt nur noch eine Stelle im Code, in der die Variablenbezeichnungen der Shader auf Bezeichner im Code abbildet werden.

2. Außerhalb der init() werden nie irgendwelche Attibutlocations abgefragt.

3. Wenn es nicht gerade nur ein kskb ist, kann es passieren, dass ein einzelnes frame z.B. so erstellt wird:

[...]

(100%tig zufrieden bin ich damit aber trotzdem nicht. Andererseits ist OpenGL nun mal nicht Objektorientiert und irgendwo zwickt es immer ;) )

Ja, "zwicken" ist gut - es schlägt halt schon teilweise ziemlich durch. Das fängt beim GL an und hört bei solchen Sachen noch lange nicht auf. Das man vielese davon "einfacher" machen könnte wenn man alles statisch macht, ist klar. (Theoretisch könnte man ja auch das aktuelle GL irgendwo statisch speichern...!?). Ich habe immer so den Drang, alles noch ein bißchen abstrakter und allgemeiner machen zu wollen, und dass bei JOGL vielleicht manche Sachen, die in anderen Bereichen no-gos wären (wie statische Datenhaltung etc.) prinzipbedingt legitim und vielleicht auch sinnvoll sind steht dem irgendwie im Wege... Sozusagen ein innerer Konflikt ... der zwickt ;)
Insbesondere der erste Punkt ist mir auch aufgefallen: Im Vertex Shader steht ein unscheinbares "in vec4 soundso;", und irgendwo verschmiert im Hauptprogramm taucht der String "soundso" bei irgendwelchen getAttribLocations auf - keine Prüfung zur Compilezeit, keine Prüfung zur Laufzeit, kein Zusammenhang - bei einem Tippfehler bleibt einfach der Bildschirm schwarz :autsch: Wie man das (und die Möglichkeit, ein und dasselbe Objekt mit mehreren Shadern zu rendern) elegant lösen kann, ist die große Frage...

Nichtsdestotrotz bin ich bei diesem Punkt besonders gespannt zu was für einer Lösung Du da kommst ;)

Keine zu hohen Erwartungen bitte ;) Ich hatte seit Jahren nichts mit den neueren Entwicklungen von OpenGL zu tun, und bin gerade erst bei der Wiedereinarbeitung ... und es sind noch so viele Punkte halb- oder ganz schwammig-unklar... (Und eigentlich ist mein Ziel ja nicht "den perfekten JOGL-Renderer" zu schreiben, sondern nur ein paar private, inoffizielle Hilfsklassen, damit ich von JOCL aus leichter was mit JOGL rendern kann... :oops: )
 
G

Guest2

Gast
Objects that can be shared between contexts include pixel and vertex buffer objects, program and shader objects, renderbuffer objects, sync objects, and texture objects

Framebuffer, query, and vertex array objects are not shared.

Ihmo bezieht sich der entsprechende Abschnitt der spec ehr auf etwas wie ich es hier schon mal als kskb gezeigt habe: http://www.java-forum.org/allgemeine-java-themen/90944-jogl-mehrere-glcanvas-erstellen.html

Das sind z.B. zwei erstmal völlig voneinander unabhängige GLCanvas (eigene GLEvents, eigene Listener, eigener Animator, eigenes gl Objekt). Die haben gar nichts miteinander zu tun und "leben" für sich ganz alleine (viele meinen das sei in OpenGL gar nicht möglich, aber das kskb zeigt es. :D). Das ist auch der Grund warum es gut ist das das gl in JoGL erstmal nicht static ist (im Gegensatz zu z.B. LWJGL (ich weis nicht ob das Beispiel da überhaupt so möglich wäre)).

In dem Beispiel teilt das erste GLCanvas jedoch seinen OpenGL Kontext mit dem zweiten GLCanvas, dadurch kann das zweite die Textur des ersten mitbenutzen ohne das die Textur noch mal neu geladen werden müsste. In gewisser weise ist das ein einsparen von "konsumierbaren" Ressourcen. Bei einem framebuffer oder einem query würde dies jedoch nur begrenzt sinn machen. (Bei einem VAO müsste man drüber nachdenken, ich würde jedoch vermuten, da das VAO einen gewissen Zustand des Kontextes abbildet, es deswegen auch nur innerhalb seines OpenGL Kontextes Gültigkeit hat.)

Wenn diese Objekte ungültig würden, dann würde das ja bedeuten, dass man bei jeder Fenstergrößenänderung alles neu laden, neu binden und neu initialisieren müßte ???:L (Vielleicht ist es auch ein Fehler, wenn ich von einer 1:1-Entsprechung zwischen einem ("nativen") GL-Context und einem Java GL-Objekt ausgehe?)

Ich muss zugeben, ich habe in dem Zusammenhang vorher nie genauer über das GLJPanel nachgedacht, aber ich befürchte fast: Ja.

Technisch ist das GLJPanel ein PBuffer (fester Größe) und ein resize führt zur Zerstörung des bisherigen PBuffers. Bei einem GLCanvas ist das nicht so, da wirkt sich lediglich der Wechsel zwischen Fenster und Vollbild aus. Bei GLWindow scheint das noch am saubersten zu sein.

Eine Möglichkeit das Problem mit dem GLJPanel zu lösen, wäre den OpenGL Kontext des GLJPanel mit einem 1x1 Pixel PBuffer zu teilen und alle Resoursen in den PBuffer zu laden (dann bleiben sie konsistent). Das habe ich früher schon mal gemacht um das Problem bei einem GLCanvas zu lösen (also sollte es auch bei einem GLJPanel gehen). Aber

1. ist das langsamer
2. mich würde wundern wenn der PBuffer nicht deprecated wäre

Da mir das Problem mit dem resize vorher auch nicht bewusst war (mit dem Wechsel zum Vollbild konnte ich leben) habe ich gerade folgenden Test geschrieben:

Java:
package late.blub;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.awt.GLJPanel;

import com.sun.opengl.util.Animator;


@SuppressWarnings("serial")
public class Switch extends GLJPanel implements GLEventListener, KeyListener {

    private final GraphicsDevice graphicsDevice;

    private Dimension            dimension = null;

    private GL2                  gl        = null;

    private boolean              init      = true;
    private int                  list      = -1;


    public Switch(final GLCapabilities capabilities) {

        super(capabilities);

        graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();

        addGLEventListener(this);
        addKeyListener(this);

    }


    @Override
    public void init(final GLAutoDrawable drawable) {

        final GL2 gl = drawable.getGL().getGL2();

        if (this.gl != gl) {

            System.out.println("init: new gl object");
            this.gl = gl;

        }

        if (init) {

            System.out.println("init: new display list");

            list = gl.glGenLists(1);
            gl.glNewList(list, GL2.GL_COMPILE);
            gl.glBegin(GL.GL_TRIANGLES);
            gl.glVertex3f(0.0f, 1.0f, -1.0f);
            gl.glVertex3f(-1.0f, -1.0f, -1.0f);
            gl.glVertex3f(1.0f, -1.0f, -1.0f);
            gl.glEnd();
            gl.glEndList();

        }

    }


    @Override
    public void display(final GLAutoDrawable drawable) {

        final GL2 gl = drawable.getGL().getGL2();

        if (this.gl != gl) {

            System.out.println("display: new gl object");
            this.gl = gl;

        }

        gl.glClear(GL.GL_COLOR_BUFFER_BIT);

        gl.glCallList(list);

    }


    @Override
    public void keyPressed(final KeyEvent e) {

        // switch init of display list
        if (e.getKeyCode() == KeyEvent.VK_I) {

            init = !init;
            
            System.out.println("init of displaylist now: " + init);

        }

        // switch fullscreen
        if (e.getKeyCode() == KeyEvent.VK_F && getParent() instanceof Frame) {

            if (graphicsDevice.isFullScreenSupported()) {

                final Frame frame = (Frame) this.getParent();

                if (graphicsDevice.getFullScreenWindow() == frame) {

                    frame.dispose();
                    frame.setUndecorated(false);
                    frame.setSize(dimension);
                    graphicsDevice.setFullScreenWindow(null);

                } else {

                    dimension = frame.getSize();

                    frame.dispose();
                    frame.setUndecorated(true);
                    frame.setSize(graphicsDevice.getDisplayMode().getWidth(), graphicsDevice.getDisplayMode().getHeight());
                    graphicsDevice.setFullScreenWindow(frame);

                }

                frame.setVisible(true);
                requestFocus();

            }

        }

    }


    public static void main(final String[] args) {

        final Frame frame = new Frame();
        final GLJPanel canvas = new Switch(new GLCapabilities(GLProfile.get(GLProfile.GL2)));
        final Animator animator = new Animator(canvas);

        frame.add(canvas);
        frame.setSize(200, 200);
        frame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(final WindowEvent e) {

                new Thread(new Runnable() {
                    public void run() {

                        animator.stop();
                        System.exit(0);

                    }
                }).start();
            }
        });

        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        animator.start();

        canvas.requestFocusInWindow();

    }


    @Override public void keyReleased(final KeyEvent e) { }
    @Override public void keyTyped(final KeyEvent e) { }
    @Override public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { }
    @Override public void dispose(final GLAutoDrawable drawable) { }

}

Und es zeigt sich:

1. neue gl Objekte kommen immer mit der init()
2. wenn in der init() nicht alles neu initialisiert wird, geht die display() nach einem ordentlichen resize nicht mehr sauber (nur mit einer display liste getestet).

(Im übrigen: GLJPanel geht hier auch nicht mit 3.2 (könnte am PBuffer liegen?) und zickt auch mit GL2 mehr rum als bei JoGL1 :( )


Jetzt ist es so, dass z.B. Buffer mit einem GL erstellt und gefüllt werden, und mit einem anderen GL dann gebunden und benutzt.

Ich würde vermuten, das es das selbe gl Objekt ist ;). Du holst die Referenz auf das Objekt mit dem drawable.getGL().getGL3() zwar neu, aber mich würde wundern wenn es wirklich ein anderes wäre. Z.B. obiges Beispiel, die Displayliste ist einfach "weg" wenn ein neues gl Objekt kommt. (Der Vollständigkeit halber müsste man das aber z.B. noch mit einem VBO verifizieren)

Zusätzlich muss an manchen Stellen neben dem GL noch das "program" weitergereicht werden, auf das sich dann die Attributes beziehen sollen (du hattest das in einem deiner Beispiele mit einer statischen Methode gelöst... hm.)

Zu einem Zeitpunkt (und pro GL Kontext) kann ja immer nur ein Shader Programm aktiv sein (und damit eine einzelne shader id) und normalerweise liegt bei mir eine map dahinter in der die einzelnen Attribute des shaders liegen (man könnte den Kontext bei Multikontextanwendungen (wie z.B. gl2specific00) also auch noch in der map berücksichtigen).

Mein eigentliches Ziel ist es shader und "Nutzer" (z.B. ein VBO) vollkommen zu trennen. Da das aber ja nicht geht (glGetAttribLocation() braucht nun mal beides), greif ich im Moment zu dem enum (das verknüpft dann z.B. "v" (Variablenbezeichnung im shader) mit Handels.VERTEX (Bezeichner im Java Code) mit Handels.VERTEX.getCurrentHandle() (mit aktuellem shader gültiges Handle))

Aber, nuja ich werkel noch dran ;)

Die Klassen alle "GLEventListener" sein zu lassen hilft zwar ein wenig, wenn (falls) man das GL zwischenspeichern darf, aber das erkauft man sich mit dem Rumreichen des GLAutoDrawable und damit, dass es IMHO SEHR schwer (d.h. auch frickelig und fehleranfällig) ist, diese Listener wieder zu removen, wenn sie nicht mehr gebraucht werden... :( .)

Ja, ich mag das so in einem kskb, weil dann jede Klasse ihren Teil macht und auch ohne große Objekthierarchien übersichtlich bleibt. Aber in einer komplexeren Anwendung würde mir das auch sorgen machen.

Ich setze die AttribPointer übrigens nicht jedes mal neu, und es funktioniert - ist das jetzt Glück?

Also ich hatte schon Fälle in denen es nicht ging (war aber auch kein VAO) - vielleicht hatte ich aber auch nur Pech ;)

In der spec steht zum VAO:

The currently bound vertex array object is used for all commands which modify
vertex array state, such as VertexAttribPointer and EnableVertexAttribArray;

Insofern könnte es schon sein das man es dann nicht braucht. ;)

Sozusagen ein innerer Konflikt ... der zwickt:?)

Ja, genau das meine ich ;)

Keine zu hohen Erwartungen bitte ;) Ich hatte seit Jahren nichts mit den neueren Entwicklungen von OpenGL zu tun, und bin gerade erst bei der Wiedereinarbeitung ... und es sind noch so viele Punkte halb- oder ganz schwammig-unklar...

Das kann auch ein Vorteil sein ;). Immerhin verhindert es die Einstellung "das ging mit 2.1 schon genauso" obwohl es jetzt mit 3.2 vielleicht einen viel sauberen weg gäbe. ;)

Gruß,
Fancy
 

Marco13

Top Contributor
Ihmo bezieht sich der entsprechende Abschnitt der spec ehr auf etwas wie ich es hier schon mal als kskb gezeigt habe: http://www.java-forum.org/allgemeine-java-themen/90944-jogl-mehrere-glcanvas-erstellen.html

OK, das war nicht genau das, was ich meinte (ich bin schon froh wenn ich meinen Kram mit EINEM Canvas zum Laufen kriege :D ) : Ich dachte, dass auch bei einem GLCanvas eine Größenänderung bewirkt, dass man ein neues GL (und damit einen neuen "nativen" Context) bekommt - das stimmt aber nicht... jetzt hab' ich's aber nochmal getestet, und das GL-Objekt bleibt bei einem Canvas immer gleich.... (Vielleicht hatte ich den Effekt irgendwann mal bei einem GLJPanel bemerkt, und einfach angenommen, dass es beim Canvas genauso ist :oops: )

Ich muss zugeben, ich habe in dem Zusammenhang vorher nie genauer über das GLJPanel nachgedacht, aber ich befürchte fast: Ja.

Technisch ist das GLJPanel ein PBuffer (fester Größe) und ein resize führt zur Zerstörung des bisherigen PBuffers. Bei einem GLCanvas ist das nicht so, da wirkt sich lediglich der Wechsel zwischen Fenster und Vollbild aus. ...
[....]
Da mir das Problem mit dem resize vorher auch nicht bewusst war (mit dem Wechsel zum Vollbild konnte ich leben) habe ich gerade folgenden Test geschrieben:
[...]
Und es zeigt sich:

1. neue gl Objekte kommen immer mit der init()
2. wenn in der init() nicht alles neu initialisiert wird, geht die display() nach einem ordentlichen resize nicht mehr sauber (nur mit einer display liste getestet).

OK. Im Klartext heißt das für mich, dass man das GLJPanel "vorerst vergessen" kann :( bis die JOGL-Leute das so umgebaut haben, dass es auch mit GL3.2 Core funktioniert, und bei einem Resize nicht alle Daten verliert. Es ist zwar klar, dass sowas wie JOGL bei so einer dramatischen Umstellung wie der von GL3 auf 3.2 nicht sofort alle Aspekte abdeckt, aber hoffentlich wird zumindest der Punkt noch bald erledigt - für eine andere Bibliothek brauche ich ein GLJPanel....
Aber bis dahin kann ich auch GLCanvas verwenden, für meine Einarbeitung und die JOCL-Samples macht das keinen so großen Unterschied. (Abgesehen davon, dass ich eins der Beispiele gerade sowieso von JOGL auf Swing umgestellt habe, weil GL3.2 kein glDrawPixels mehr kennt :autsch: ... naja... ist gleich 200 Zeilen kürzer, und noch genauso schnell...)



Ich würde vermuten, das es das selbe gl Objekt ist ;)
Ja, davon kann man (jetzt) ausgehen - meine Annahme, es seien (spätestens nach einer Größenänderung) unterschiedliche Objekte hing mit obigem Irrtum zum Verhalten des GLCanvas bei Größenänderungen zusammen...


Zu einem Zeitpunkt (und pro GL Kontext) kann ja immer nur ein Shader Programm aktiv sein (und damit eine einzelne shader id) und normalerweise liegt bei mir eine map dahinter in der die einzelnen Attribute des shaders liegen (man könnte den Kontext bei Multikontextanwendungen (wie z.B. gl2specific00) also auch noch in der map berücksichtigen).

Mein eigentliches Ziel ist es shader und "Nutzer" (z.B. ein VBO) vollkommen zu trennen. Da das aber ja nicht geht (glGetAttribLocation() braucht nun mal beides), greif ich im Moment zu dem enum (das verknüpft dann z.B. "v" (Variablenbezeichnung im shader) mit Handels.VERTEX (Bezeichner im Java Code) mit Handels.VERTEX.getCurrentHandle() (mit aktuellem shader gültiges Handle))

Ja, diese Trennung wollte ich eigentlich auch erreichen: Man hat "irgendein" Renderbares Objekt, und "irgendeinen" Renderer, und kann dann Rendern - aber der Renderer (oder Shader) ist ja immer spezifisch dafür, WELCHE Informationen das Objekt enthält (Normalen? Vertex Colors?...), und zusätzlich noch, unter welchem Namen er diese Informationen zu finden glaubt... Ich glaub' ich muss da noch einiges strukturieren (zuerst: Im Kopf!) bis da überhaupt was vernünftiges rauskommen kann. (Am Ende merkt man dann vielleicht doch: Eine Map in einem Singleton ist das beste! - aber vorher erstmal drüber nachdenken...)



In der spec steht zum VAO:
[...]
Insofern könnte es schon sein das man es dann nicht braucht. ;)
Ja, solche Sachen finde ich (wenn man sich so frisch einarbeitet) ziemlich schwer nachzuvollziehen: Welche "commands" sind das denn nun ("such as..." sind nur Beispiele)? Was heißt "modify" (ist eine Abfrage eine Modifikation, oder gilt das nur bei QBits?) ... Einzelne Aspekte sind in der Spez so detailliert beschrieben, dass sie nur von einem Mathematiker stammen können, aber das "Big Picture" und einige "orthogonale" Ideen und Aspekte sind bei mir bisher noch nicht so ganz angekommen. (*verträumt auf's Redbook im Regal rüberschiel*) ;)


Das kann auch ein Vorteil sein ;). Immerhin verhindert es die Einstellung "das ging mit 2.1 schon genauso" obwohl es jetzt mit 3.2 vielleicht einen viel sauberen weg gäbe. ;)

Ja, teilweise glaube ich auch, dass es schwierig sein könnte, wenn man sich intensiv mit 2.1 beschäftigt hat, und jetzt bei 3.2 alles "so ähnlich" geht, aber mit Detailunterschieden. Für mich ist das wenigstens alles GANZ neu ... (*jubel, freu* ;))
 
G

Guest2

Gast
OK. Im Klartext heißt das für mich, dass man das GLJPanel "vorerst vergessen" kann :( bis die JOGL-Leute das so umgebaut haben, dass es auch mit GL3.2 Core funktioniert, und bei einem Resize nicht alle Daten verliert. Es ist zwar klar, dass sowas wie JOGL bei so einer dramatischen Umstellung wie der von GL3 auf 3.2 nicht sofort alle Aspekte abdeckt, aber hoffentlich wird zumindest der Punkt noch bald erledigt - für eine andere Bibliothek brauche ich ein GLJPanel....

Ich würde das auch hoffen, aber wenn es ein wirklich wichtiges Projekt ist, würde ich an Deiner stelle auch rechtzeitig eine Alternativlösung andenken. Imho haben sich die schwarzen Wolken über JoGL noch nicht wirklich verzogen: JOGL is dead. Long live JOGL

Meines Wissens sind im Moment Sven Gothel und Michael Bien die einzigen "aktiven" JoGL Entwickler. Und deren github Profilen nach (Commit History for sgothel's jogl - GitHub, Commit History for mbien's jogl - GitHub (da liegt jetzt wohl "offiziell" der JoGL source code)) ist seit dem überstürzten Wechsel weg von Sun und kenai hin zu github nicht mehr wirklich viel passiert. (Ich finde es erschreckend das nun imho kein JoGL Macher mehr bei Sun arbeitet, insbesondere da JavaFX wohl Teile von JoGL verwendet :( )

Und dann gibt es noch so komische Fusionsüberlegungen mit LWJGL, irgendwie hört sich das dann nicht mehr nach einem schlanken / schnellen / direkten binding an :( .

Bei mir führte das schon so weit, das ich als prov of concept ein eigenes pure OpenGL 3.2 binding geschrieben habe (letztendlich nur ein Generator der die spec einliest und jni ausspuckt). (Ist sozusagen mein Notnagel ;) )

Aber ich hoffe ganz stark das sich JoGL wieder aufrappelt!

(Wobei das GLJPanel unabhängig davon problematisch bleibt, ich wüsste nämlich keine Lösung um OpenGL auflösungsunabhängig und anwendungstransparent auf eine Swing Komponente zu legen :( (was aber natürlich nicht heißt das es keine geben kann ;) ))

Ja, diese Trennung wollte ich eigentlich auch erreichen: Man hat "irgendein" Renderbares Objekt, und "irgendeinen" Renderer, und kann dann Rendern - aber der Renderer (oder Shader) ist ja immer spezifisch dafür, WELCHE Informationen das Objekt enthält (Normalen? Vertex Colors?...), und zusätzlich noch, unter welchem Namen er diese Informationen zu finden glaubt... Ich glaub' ich muss da noch einiges strukturieren (zuerst: Im Kopf!) bis da überhaupt was vernünftiges rauskommen kann.

Ich wünsch Dir viel Glück dabei! :D

verträumt auf's Redbook im Regal rüberschiel

Die guten alten Zeiten ;)


Viele Grüße,
Fancy
 

Marco13

Top Contributor
Ich würde das auch hoffen, aber wenn es ein wirklich wichtiges Projekt ist, würde ich an Deiner stelle auch rechtzeitig eine Alternativlösung andenken. Imho haben sich die schwarzen Wolken über JoGL noch nicht wirklich verzogen: JOGL is dead. Long live JOGL

Ja, den Thread hatte ich auch gesehen, aber bin daraus irgendwie nicht so ganz schlau geworden - genaugenommen wirft er (noch) mehr Fragen auf...

Meines Wissens sind im Moment Sven Gothel und Michael Bien die einzigen "aktiven" JoGL Entwickler. Und deren github Profilen nach (Commit History for sgothel's jogl - GitHub, Commit History for mbien's jogl - GitHub (da liegt jetzt wohl "offiziell" der JoGL source code)) ist seit dem überstürzten Wechsel weg von Sun und kenai hin zu github nicht mehr wirklich viel passiert. (Ich finde es erschreckend das nun imho kein JoGL Macher mehr bei Sun arbeitet, insbesondere da JavaFX wohl Teile von JoGL verwendet :( )

Auch das ist mir aufgefallen: Hatte geschaut, ob sich seit der letzten "release" beim GLJPanel was getan hat, aber das letzte checkin ist >2 Monate alt. Man kann ja niemandem einen Vorwurf machen, schließlich machen das alle (beide) in ihrer Freizeit, aber beunruhigend ist es schon. Also, schade eben. Und wie Sun mit JavaFX und JOGL und den Überschneidungen dazwischen (und den com.sun.*-Teilen von JOGL) weiter verfährt ist auch nirgendwo ersichtlich - aus einer Quelle habe ich gehört, dass Sun JOGL komplett droppen will...

Und dann gibt es noch so komische Fusionsüberlegungen mit LWJGL, irgendwie hört sich das dann nicht mehr nach einem schlanken / schnellen / direkten binding an :( .

Es gibt ja verschiedene Bibliotheken, die Anbindungen von OpenGL an Java bieten (und ich hatte mit damals javagl.de wegen überschäumender Ambitionen reserviert... aber jetzt hat das mit meinem Hartz4 doch nicht geklappt, und schon gehen jeden Tag 8 Stunden für Arbeit drauf :( ). Eigentlich glaube ich, dass man mit JNA da ein paar ganz schöne Sachen machen könnte, und soweit ich weiß hat Olivier mit seinem JNAerator ( Ché zOlive JNAerator ) da auch schon einiges gemacht. Aber die direkte 1:1-Übersetzung von JOGL fand ich halt schön....

Bei mir führte das schon so weit, das ich als prov of concept ein eigenes pure OpenGL 3.2 binding geschrieben habe (letztendlich nur ein Generator der die spec einliest und jni ausspuckt). (Ist sozusagen mein Notnagel ;) )
Ach so, so ein lächerlicher kleiner Generator nur :joke: *räusper* Ja, schade dass an JOGL nur so wenige Leute aktiv arbeiten *bis zur Heiserkeit räusper* ;)


Aber ich hoffe ganz stark das sich JoGL wieder aufrappelt!
Ja... : Aber die direkte 1:1-Übersetzung von JOGL finde ich halt schön.... (besser ;))


(Wobei das GLJPanel unabhängig davon problematisch bleibt, ich wüsste nämlich keine Lösung um OpenGL auflösungsunabhängig und anwendungstransparent auf eine Swing Komponente zu legen :( (was aber natürlich nicht heißt das es keine geben kann ;) ))
Ich bin ja manchmal ein bißchen naiv und so, aber ... Man kann doch mit FBO und Co in eine Textur rendern!? Und eigentlich muß man doch nur noch die Textur (also einen Datenblock, der RGB Pixel speichert) auf den Bildschirm bringen!? Da müßte man ... vielleicht mit VolatileImage oder sowas... doch was machen können?
Ich hatte ja so eine JOCL-Demo, wo in ein PBO geschrieben und das dan mit glDrawPixels gezeichnet wurde - jetzt wird halt in den int-Array eines BufferedImage.TYPE_INT_RGB reingeschrieben, und das dann stupide mit Swing gezeichnet. Natürlich kann das nicht so schnell sein wie bei einem GLCanvas (Bei mir war da wohl die Berechnung des Mandelbrot-Fraktals der begrenzende Faktor ;) ) aber so einen Datenblock am Stück kopieren müßte doch eigentlich recht schnell gehen, speziell mit ein bißchen mehr ... Eingriff in die Tiefen von Swing (das auch auch OpenGL-beschleunigt rendern kann!) ... da müßte doch was zu machen sein...?
 
G

Guest2

Gast
aus einer Quelle habe ich gehört, dass Sun JOGL komplett droppen will...

Ich hoffe es nicht, aber ich befürchte es fast. :(
Hoffentlich bleibt es als Community Projekt wenigstens lebensfähig.


Ja... : Aber die direkte 1:1-Übersetzung von JOGL finde ich halt schön.... (besser ;))

Definitiv! ;). Imho ist es auch das was JoGL ausmacht, deswegen bin ich auch von den Fusionsüberlegungen mit LWJGL wenig begeistert :(.


Ach so, so ein lächerlicher kleiner Generator nur :joke: *räusper* Ja, schade dass an JOGL nur so wenige Leute aktiv arbeiten *bis zur Heiserkeit räusper* ;)

Lol, klingt wohl dramatischer als es ist ;). Wenn man von http://www.opengl.org/registry/api/gl.spec ausgeht, ist dazu nicht viel mehr nötig als ein search and replace der Datentypen.

Aber eigentlich hast Du ja recht, hab gerade mal einen kurzen Blick in die GLJPanel geworfen und nuja, ich glaube jetzt geht GL3 :D.

http://too-late.de/snippets/GLJPanel.java

Das waren allerdings auch nur ein paar kleine Trivialitäten warum das noch nicht lief.

Muss ich noch mal genauer drüber nachdenken und testen, anschließend werde ich es wohl mal als Patch Vorschlag auf jogl - Java Bindings for OpenGL posten.

Wäre natürlich auch super, wenn Du das mal bei Dir ausprobieren könntest ;).
(Die Änderungen sind auch im Quelltext markiert ("patch (need review):"))


Ich bin ja manchmal ein bißchen naiv und so, aber ... Man kann doch mit FBO und Co in eine Textur rendern!? Und eigentlich muß man doch nur noch die Textur (also einen Datenblock, der RGB Pixel speichert) auf den Bildschirm bringen!? Da müßte man ... vielleicht mit VolatileImage oder sowas... doch was machen können?

Der Vorteil vom PBuffer ist einfach das der seinen eigenen OpenGL Kontext erzeugt. Das FBO hingegen ist selbst "teil" eines Kontextes (in dem eben auch der Nutzer werkelt).
Würde sich aber vermutlich trotzdem lohnen mal intensiver drüber nachzudenken ;)

Wenn ich das richtig sehe, gibt es im GLJPanel code auch "etwas" mit einem FBO. Aktiviert wird das wenn die Anwendung mit -Dsun.java2d.opengl=true gestartet wird. Aber:

1. Imho ist das alles noch JoGL1 code (stürzt hier mit JoGL2 direkt ab, ne Klasse fehlt sogar :()

2. Bei JoGL1 bleibt das Panel durchsichtig, aber die Anwendung läuft. Allerdings führt ein resize auch zu einem neuen gl Objekt und damit vermutlich wohl auch zu einem neuen OpenGL Kontext.


Alternativ hatte ich vorher allerdings auch noch das Problem, dass das GLJPanel nicht immer die volle Breite des Panel ausgezeichnet hat. Daraufhin habe ich im Quelltext noch ein workaround dazu eingebaut und dabei festgestellt das, wenn man den PBuffer "groß genug" wählt und das resize des PBuffer unterdrückt, der OpenGL Kontext erhalten bleibt. Allerdings ist dies auch wesentlich langsamer, da die Anwendung die ganze Zeit in einer zu hohen Auflösung rechnet (und dann per BufferedImage wieder runter skaliert wird)(z.B. das gl3sample00 bleibt aber flüssig / mehr hab ich auch nicht probiert).


Gruß,
Fancy
 

Marco13

Top Contributor
Lol, klingt wohl dramatischer als es ist ;). Wenn man von http://www.opengl.org/registry/api/gl.spec ausgeht, ist dazu nicht viel mehr nötig als ein search and replace der Datentypen.

OK, sowas ist natürlich praktisch ... einerseits... wenn da nicht dieser Kommentar dabei stünde "(Yes, these databases should be moved to a modern XML-based format. Patience.)" ... Öhm ... wie flexibel ist dein Generator? :D

Aber eigentlich hast Du ja recht, hab gerade mal einen kurzen Blick in die GLJPanel geworfen und nuja, ich glaube jetzt geht GL3 :D.

http://too-late.de/snippets/GLJPanel.java

Das waren allerdings auch nur ein paar kleine Trivialitäten warum das noch nicht lief.

Muss ich noch mal genauer drüber nachdenken und testen, anschließend werde ich es wohl mal als Patch Vorschlag auf jogl - Java Bindings for OpenGL posten.

Wäre natürlich auch super, wenn Du das mal bei Dir ausprobieren könntest ;).
(Die Änderungen sind auch im Quelltext markiert ("patch (need review):"))

Ja, dass dort eigentlich "nur" getGL2 steht, und man das (im besten Fall) "nur" durch getGL3 ersetzen müßte, hatte ich auch gesehen ... nur bingt es ja nicht sooo viel, wenn das nicht im build ist. Aber ich werd's bei Gelegenheit mal testen (bin gerade am falschen Rechner), vielleicht kann das ja dann in die nächste beta... wann auch immer die kommt ???:L

Der Vorteil vom PBuffer ist einfach das der seinen eigenen OpenGL Kontext erzeugt. Das FBO hingegen ist selbst "teil" eines Kontextes (in dem eben auch der Nutzer werkelt).
Würde sich aber vermutlich trotzdem lohnen mal intensiver drüber nachzudenken ;)

Insbesondere hatte ich mich gefragt, ob man einen "unsichtbaren" (0x0 pixel großen :D) OpenGL-Context erstellen kann....


Wenn ich das richtig sehe, gibt es im GLJPanel code auch "etwas" mit einem FBO. Aktiviert wird das wenn die Anwendung mit -Dsun.java2d.opengl=true gestartet wird. Aber:

1. Imho ist das alles noch JoGL1 code (stürzt hier mit JoGL2 direkt ab, ne Klasse fehlt sogar :()

2. Bei JoGL1 bleibt das Panel durchsichtig, aber die Anwendung läuft. Allerdings führt ein resize auch zu einem neuen gl Objekt und damit vermutlich wohl auch zu einem neuen OpenGL Kontext.

So weit hatte ich mich dann nicht durch den Code gepflügt... und die Kenntnisse rund um FBO, PBuffer & Co rum fehlen mir da halt auch einfach.
Zumindest erklärt das alles, warum ich bei Swogl das Problem hatte, dass nach jeder Größenänderung die Texturen neu initialisiert werden mußten (das baut sich jetzt Stück für Stück im Kopf zusammen :D)



Alternativ hatte ich vorher allerdings auch noch das Problem, dass das GLJPanel nicht immer die volle Breite des Panel ausgezeichnet hat. Daraufhin habe ich im Quelltext noch ein workaround dazu eingebaut und dabei festgestellt das, wenn man den PBuffer "groß genug" wählt und das resize des PBuffer unterdrückt, der OpenGL Kontext erhalten bleibt. Allerdings ist dies auch wesentlich langsamer, da die Anwendung die ganze Zeit in einer zu hohen Auflösung rechnet (und dann per BufferedImage wieder runter skaliert wird)(z.B. das gl3sample00 bleibt aber flüssig / mehr hab ich auch nicht probiert).
OK, aber spätestens wenn man 2 Monitore hat und da die volle Größe nimmt wird das wohl ziemlich schwierig... Es ist auch klar, dass der Umweg über ein BufferedImage nicht das gelbe vom Ei sein kann, weil man da ja effektiv den Speicher von der Grafikkarte einmal über smämtliche Busse ins BufferedImage kopiert, das dann effektiv doch wieder in den Grafikspeicher schreibt... aber für "bessere" Alternativen müßte man sich da wohl ziemlich weit reinlesen, und u.U. viel Zeit inverstieren... Der Anspruch, dass das dann auf allen OSen und Grafikkarten läuft ist schon ziemlich hoch...
 
G

Guest2

Gast
OK, sowas ist natürlich praktisch ... einerseits... wenn da nicht dieser Kommentar dabei stünde "(Yes, these databases should be moved to a modern XML-based format. Patience.)" ... Öhm ... wie flexibel ist dein Generator? :D

Em, nuja, sagen wir mal: Es war ja nur ein prove of concept :D.

Aber ich fände es gut wenn es das als xml geben würde, dann würde der Generator nämlich fast zur Trivialität verkommen (manchmal hab ich es eben gerne einfach ;) ).

Ja, dass dort eigentlich "nur" getGL2 steht, und man das (im besten Fall) "nur" durch getGL3 ersetzen müßte, hatte ich auch gesehen ... nur bingt es ja nicht sooo viel, wenn das nicht im build ist. Aber ich werd's bei Gelegenheit mal testen (bin gerade am falschen Rechner), vielleicht kann das ja dann in die nächste beta... wann auch immer die kommt ???:L

Ja, das ist eine gute Frage. Michael Bien hat mal angedeutet (Catch 22 for jogl) das die JoGL Builds wohl mittlerweile über seinen Hudson (Dashboard [Hudson]) laufen. Insofern könnte es zumindest sein das es relativ schnell in die nightlys reinkommt. Mal abwarten was da kommt ;).


OK, aber spätestens wenn man 2 Monitore hat und da die volle Größe nimmt wird das wohl ziemlich schwierig... Es ist auch klar, dass der Umweg über ein BufferedImage nicht das gelbe vom Ei sein kann, weil man da ja effektiv den Speicher von der Grafikkarte einmal über smämtliche Busse ins BufferedImage kopiert, das dann effektiv doch wieder in den Grafikspeicher schreibt... aber für "bessere" Alternativen müßte man sich da wohl ziemlich weit reinlesen, und u.U. viel Zeit inverstieren... Der Anspruch, dass das dann auf allen OSen und Grafikkarten läuft ist schon ziemlich hoch...

Ich befürchte es leider auch :(

Gruß,
Fancy
 

Marco13

Top Contributor
Habe das angepasste GLJPanel mal getestet, es scheint (für eine einfache Testanwendung) zu funktionieren. Muss es bei Gelegenheit mal in der "Zielumgebung" (d.h. in Swogl) testen.

Das Forum und den "jausoft" Blog verfolge ich zwar einigermaßen mit, aber wirklich viele Infos zur Zukunft von JOGL gibt's da auch nicht... :(
 
G

Guest2

Gast
Ich gehe inzwischen auch davon aus das es in den meisten Fällen so funktionieren sollte (es gibt noch ein SoftwareBackend und ein J2DOGLBackend im GLJPanel, ka. wie es da aussieht und ob das überhaupt noch "aktiver" code ist (bei mir läuft er nicht)).

Habs am Wochenende im Nachbarforum gepostet. Bin mal gespannt ob da seitens der Entwickler ne Reaktion zu kommt.

Gruß,
Fancy
 

Marco13

Top Contributor
Jetzt noch mal was ganz grundsätzliches: Gibt es irgendwelche Informationen über die Beziehung zwischen dem GL, das man von einem GLAutoDrawable bekommt und dem GL, das man von GLContext.getCurrentGL bekommt? Oder zur Beziehung zwischen dem GLContext den man mit GLContext.getCurrent bekommt und einem "nativen" OpenGL Context? Und wie ist das, wenn man (mit GLJPanel, oder auch beim GLCanvas beim Unschalten zwischen Fenster und Vollbild) einen neuen "Kontext" bekommt (ob das nun ein neuer nativer Kontext, ein neuer GLContext, oder ein neues GL ist...) : Werden alle Buffers, die in dem "alten" Kontext angelegt, gemappt, gebunden oder sonstwie verarbeitet wurden dann gelöscht... oder kann man sich damit ein "Grafikkartenspeicherleck" einhandeln? (Ich bin kurz davor, einfach alles 'static' zu machen :( )

EDIT: Kam da eigentlich eine Reaktion (bzw. deines letzten Beitrags)?
 
G

Guest2

Gast
Moin,

Jetzt noch mal was ganz grundsätzliches: Gibt es irgendwelche Informationen über die Beziehung zwischen dem GL, das man von einem GLAutoDrawable bekommt und dem GL, das man von GLContext.getCurrentGL bekommt? Oder zur Beziehung zwischen dem GLContext den man mit GLContext.getCurrent bekommt und einem "nativen" OpenGL Context?

gute Frage ;), hab das GLContext.getCurrentGL() vorher auch noch nie genutzt. Im JavaDoc steht ja lediglich:

http://download.java.net/media/jogl/jogl-2.x-docs/javax/media/opengl/GLContext.html#getCurrentGL() hat gesagt.:
Returns the GL object bound to this thread current context. If no context is current, throw an GLException.

In den ersten Versuchen gerade, scheint es wohl tatsächlich immer das selbe GL zurückzugeben, das man auch durch das GLAutoDrawable bekommt. Beim Multikontext (2x GLJPanel) und beim nativen GLWindow scheint es auch zu gehen.


Und wie ist das, wenn man (mit GLJPanel, oder auch beim GLCanvas beim Unschalten zwischen Fenster und Vollbild) einen neuen "Kontext" bekommt (ob das nun ein neuer nativer Kontext, ein neuer GLContext, oder ein neues GL ist...) : Werden alle Buffers, die in dem "alten" Kontext angelegt, gemappt, gebunden oder sonstwie verarbeitet wurden dann gelöscht... oder kann man sich damit ein "Grafikkartenspeicherleck" einhandeln?

Sagen wir, ich hoffe, dass das alles wieder gelöscht wird ;). Nachdem was ich bisher vom GLCanvas und GLJPanel gesehen hab und mit dem was ich noch von meinen OpenGL Versuchen in C weis, würde ich vermuten das da nichts passieren dürfte.

Beim GLCanvas hätte man ja noch die Möglichkeit über das dispose() aufzuräumen, aber beim GLJPanel ist der Kontext ja einfach weg.

Zum Testen hab ich gerade mal folgendes ausprobiert (vollkommen fernab allen sinnvollen :D ):

Java:
package late.gl.jogl2.base;

import java.awt.Frame;
import java.nio.FloatBuffer;
import java.util.Random;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import javax.media.opengl.fixedfunc.GLPointerFunc;
import javax.media.opengl.glu.GLU;

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.BufferUtil;

public class Test implements GLEventListener {

    private static final Random random    = new Random(System.currentTimeMillis());
    private static final int    vboSize   = 100000;

    private final Object        monitor   = new Object();

    private volatile int        initCount = 0;
    private int                 vboHandle = 0;

    private GL2                 gl;
    private GLU                 glu;


    @Override
    public void init(final GLAutoDrawable drawable) {

        synchronized (monitor) {

            System.out.println("init: " + initCount);

            gl = drawable.getGL().getGL2();
            glu = new GLU();

            final FloatBuffer buffer = BufferUtil.newFloatBuffer(vboSize);

            for (int i = 0; i < buffer.capacity(); i++)
                buffer.put(random.nextFloat() - 0.5f);

            buffer.rewind();

            final int[] vboHandleBuffer = new int[1];
            gl.glGenBuffers(1, vboHandleBuffer, 0);
            vboHandle = vboHandleBuffer[0];

            gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboHandle);
            gl.glBufferData(GL.GL_ARRAY_BUFFER, vboSize * (Float.SIZE / Byte.SIZE), buffer, GL.GL_STATIC_DRAW);
            gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

            gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);

            initCount++;

        }

    }


    @Override
    public void display(final GLAutoDrawable arg0) {

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        gl.glLoadIdentity();
        gl.glRotatef(initCount, 0, 0, 1);
        gl.glTranslatef(0.0f, 0.0f, -1.0f);

        gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboHandle);
        gl.glVertexPointer(2, GL.GL_FLOAT, 0, 0);
        gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, vboSize);
        gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

    }


    @Override
    public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, int height) {

        if (height <= 0)
            height = 1;

        gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, (float) width / (float) height, 1.0, 1000.0);
        gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
        gl.glLoadIdentity();

    }


    public static void main(final String[] args) {

        final Test main = new Test();
        final Frame frame = new Frame();
        final GLCanvas canvas = new GLCanvas();
        final Animator animator = new Animator(canvas);

        canvas.addGLEventListener(main);

        frame.add(canvas);
        frame.setSize(900, 500);
        frame.setLocationRelativeTo(null);
        animator.start();


        new Thread(new Runnable() {

            @Override
            public void run() {

                while (main.initCount < 1500) {

                    synchronized (main.monitor) {

                        frame.setVisible(true);
                        
                    }

                    try {
                        Thread.sleep(200);
                    } catch (final InterruptedException e) {

                    }

                    synchronized (main.monitor) {
                       
                        frame.setVisible(false);
                        frame.dispose();

                    }

                }

                System.exit(0);

            }
        }).start();

    }


    @Override
    public void dispose(final GLAutoDrawable drawable) {

    }

}

Und es läuft (zumindest hier) sauber bis zum Ende durch (dürfte es aber nicht wenn der Grafikkartenspeicher zwischendurch nicht aufgeräumt werden würde).


Ich bin kurz davor, einfach alles 'static' zu machen :(

Und ich hab schon ein schlechtes Gewissen wenn ich eine Map static mache. ;)

LWJGL geht ja auch so einen static Ansatz. Du musst Dir dann nur ganz sicher sein niemals ein zweites GLJPanel (als Multikontextanwendung) einbauen zu wollen, das dürfte mit dem static Ansatz dann nämlich schwer (unmöglich?) werden.


EDIT: Kam da eigentlich eine Reaktion (bzw. deines letzten Beitrags)?

Leider nein, zumindest keine von einem der beiden. Ich hab eben auf Java? Binding for the OpenGL® API: General Discussion: Will JOGL be moving back to java.net? &mdash; Project Kenai noch mal was von Michael Bien gelesen bzgl. dem Ende von kenai (auch wenn die sourcen da nicht mehr liegen, so war es doch bisher immerhin so was wie "die" Projektseite von JoGL. Nuja, jetzt scheint es so, dass es nach dem schließen von kenai (am 2.4.10) keine Projektseite mehr zu JoGL gibt (nur noch github und den hudson).

Ich finde das etwas erschreckend. :(

Gruß,
Fancy
 

Marco13

Top Contributor
gute Frage ;), hab das GLContext.getCurrentGL() vorher auch noch nie genutzt. Im JavaDoc steht ja lediglich:
Scheint als könnte man höchstens genau sagen, was das macht, indem man sich den Quellcode ansieht... :bahnhof: Wie auch immer... auch in bezug auf die Diskussion weiter oben werde ich da wohl ein bißchen umdisponieren müssen... Ist nicht leicht, GL mit OOP in Einklang zu bringen...


Sagen wir, ich hoffe, dass das alles wieder gelöscht wird ;). Nachdem was ich bisher vom GLCanvas und GLJPanel gesehen hab und mit dem was ich noch von meinen OpenGL Versuchen in C weis, würde ich vermuten das da nichts passieren dürfte.
...
Zum Testen hab ich gerade mal folgendes ausprobiert (vollkommen fernab allen sinnvollen :D ):
...
Und es läuft (zumindest hier) sauber bis zum Ende durch (dürfte es aber nicht wenn der Grafikkartenspeicher zwischendurch nicht aufgeräumt werden würde).
Hm ... deine Grafikkarte hat 150MB? Ich werd' das (an meinem "richtigen" Rechner) vielleicht auch nochmal testen, aber ... Naja, z.B. wird über sowas (soweit ich das gesehen habe) nicht mal in der GL Spezifikation explizit was gesagt.... Genaugenommen müßte er doch dann intern irgendwelche "usage-Counter" für alle Buffer haben, und die runterzählen, wenn einer "ihrer" Kontexte zerstört wird ???:L

LWJGL geht ja auch so einen static Ansatz. Du musst Dir dann nur ganz sicher sein niemals ein zweites GLJPanel (als Multikontextanwendung) einbauen zu wollen, das dürfte mit dem static Ansatz dann nämlich schwer (unmöglich?) werden.
Naja... static erzwingt ja nicht, dass es nur ein GLJPanel gibt... es sind nur diese Halbklarheiten (wann muss was gebunden und ungebunden und gelöscht werden, und wer macht das, und was ist eigentlich ein GL und was ist ein GLContext usw.) die ich gerne ausgeräumt hätte ... aber wahrscheinlich tauchen die in ähnlicher Form auch bei C/C++ auf...



Nuja, jetzt scheint es so, dass es nach dem schließen von kenai (am 2.4.10) keine Projektseite mehr zu JoGL gibt (nur noch github und den hudson).

Ich finde das etwas erschreckend. :(

Erschreckend ist ein bißchen zurückhaltend formuliert: Es gibt dann ja keine "offizielle" und "direkte" OpenGL-Anbindung für Java mehr ... Werde mir wohl früher oder später mal LWJGL ansehen (müssen), was dem wohl nach JOGL noch am nächsten kommt.... :(
 
G

Guest2

Gast
Ist nicht leicht, GL mit OOP in Einklang zu bringen...

Nein, leider ganz und gar nicht :D.


Hm ... deine Grafikkarte hat 150MB?

Ich hoffe nicht! ;) Kann aber auch sein das ich gerade auf dem Schlauch stehe, aber 100000 * 4 Byte (float) * 1500 Iterationen wären 572MB und meine Karte hat 512MB, dürfte also imho nicht passen...


Naja, z.B. wird über sowas (soweit ich das gesehen habe) nicht mal in der GL Spezifikation explizit was gesagt.... Genaugenommen müßte er doch dann intern irgendwelche "usage-Counter" für alle Buffer haben, und die runterzählen, wenn einer "ihrer" Kontexte zerstört wird ???:L

Nicht ganz. Vielleicht wird es etwas klarer wenn man sich den C Teil vor Augen führt (halb Pseudocode und nur für Windows)(Ich hab keine Ahnung ob das in JoGL genau so läuft, aber ich würde es so schreiben ;) ):

Code:
// AWT native interface voodoo um an das native handle des canvas zu kommen
JAWT_DrawingSurface* ds = awt.GetDrawingSurface(env, canvas);
JAWT_DrawingSurfaceInfo* dsi = ds->GetDrawingSurfaceInfo(ds);
JAWT_Win32DrawingSurfaceInfo* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;

// hWnd ist das window / canvas handle
HWND hWnd = dsi_win->hwnd;

// hDC ist das device context handle
HDC hDC = GetDC(hWnd);

// hRC ist unser OpenGL render Kontext
HGLRC hRC = wglCreateContext(hDC);

// den OpenGL Kontext für den aktuellen thread aktivieren
wglMakeCurrent(hDC, hRC);

// jetzt könnten OpenGL Anweisungen abgesetzt werden

Das GL Objekt in JoGL ist jetzt im Wesentlichen ein Verweis auf das hDC und das hRC. Wobei innerhalb der Methoden des GLEventListener, unter Verwendung des aktuellen GL Objektes (also hDC und hRC) vorher ggf. das wglMakeCurrent(hDC, hRC) aufgerufen wird.

So kann z.B. in der init() direkt ein glGenBuffers() aufgerufen werden. Der damit erzeugte Buffer "lebt" dann quasi im aktuellen hRC (und nirgendwo anders).

Wechselt das GLCanvas nun zwischen Fenster und Vollbild, wird das hWnd ungültig (liegt wohl an dem dispose() des frames) und damit auch das hDC sowie anschließend das hRC.

(Irgendwo im JoGL Quellcode sollte jetzt wohl auch ein wglDeleteContext() aufgerufen werden, aber keine Ahnung ob dem so ist. Ich vermute aber auch, dass der Grafikkartentreiber erkennt wenn das hDC ungültig wird und dann die Ressourcen des hRC ebenfalls freigibt)

Bildlich könnte man jetzt sagen, dass jedes hRC, eine für sich unabhängige OpenGL Statusmaschine ist. Wird das hRC ungültig, geht sein Zustand und damit auch alle seine Ressourcen (Buffer, Texturen, ...) verloren. Auch wenn OpenGL Kontext A seinen Kontext mit OpenGL Kontext B teilt, kann zwar B auf die Ressourcen von A zugreifen, aber sobald A ungültig wird, sind sie auch für B nicht mehr zu erreichen.


Naja... static erzwingt ja nicht, dass es nur ein GLJPanel gibt... es sind nur diese Halbklarheiten (wann muss was gebunden und ungebunden und gelöscht werden, und wer macht das, und was ist eigentlich ein GL und was ist ein GLContext usw.) die ich gerne ausgeräumt hätte ... aber wahrscheinlich tauchen die in ähnlicher Form auch bei C/C++ auf...

Ja, hDC / hRC und wglMakeCurrent :D.

Das Problem bei static in Multikontextanwendungen ist, das es zwei verschiedene GL Objekte gibt (also zwei hRC). Und im OpenGL Kontext A kann z.B. aktuell Shader B gebunden sein, während im OpenGL Kontext B gerade Shader C gebunden ist.
Und diese zwei verschiedenen Bindungen elegant abzubilden, ist halt schwierig wenn alles static ist.

Erschreckend ist ein bißchen zurückhaltend formuliert: Es gibt dann ja keine "offizielle" und "direkte" OpenGL-Anbindung für Java mehr ... Werde mir wohl früher oder später mal LWJGL ansehen (müssen), was dem wohl nach JOGL noch am nächsten kommt.... :(

Ja, auf LWJGL müsste ich auch mal einen genaueren Blick werfen, aber mir gefällt JoGL eigentlich vom Aufbau her wesentlich besser. Und noch hab ich JoGL nicht aufgegeben (und als letzten Notnagel hab ich ja noch den Generator (der Code in JoGL Art ausspuckt ;) )

Gruß,
Fancy
 

Marco13

Top Contributor
... * 4 Byte (float) * ...
:oops: Ohje... ;)

Nicht ganz. Vielleicht wird es etwas klarer wenn man sich den C Teil vor Augen führt (halb Pseudocode und nur für Windows)(Ich hab keine Ahnung ob das in JoGL genau so läuft, aber ich würde es so schreiben ;) ):
...

OK, genau das sind die Dinge, die ich eben überhaupt nicht kenne. Das verwendet ja aber auch schon eine Utility-Bibliothek...? Ich erinnere mich von meinen ersten OpenGL-Gehversuchen her nur an irgendwelche riesigen Structs (PIXELFORMATDESCRIPTOR und Co) und die Quintessenz: "Da, wo das WM_PAINT steht, kann man zeichnen" :D (Bin dann auch schnell auf GLUT umgeschwenkt....). Einerseits würde ich ja mal darauf vertrauen, dass JOGL das mit dem Freigeben des Speichers und der Verwaltung und so intern schon alles richtig regelt, aber solange ich nichtmal weiß, das "richtig" in diesem Fall bedeutet, fühlt sich alles, was ich mache, so ... "unfundiert" an... :oops:


Das Problem bei static in Multikontextanwendungen ist, das es zwei verschiedene GL Objekte gibt (also zwei hRC). Und im OpenGL Kontext A kann z.B. aktuell Shader B gebunden sein, während im OpenGL Kontext B gerade Shader C gebunden ist.
Und diese zwei verschiedenen Bindungen elegant abzubilden, ist halt schwierig wenn alles static ist.
Ja, "alles" war vielleicht zu pauschal - es sollte aber andeuten, dass man ja die Holzhammermethode verwenden könnte.... sinngemäß sowas wie
Java:
private static Map<GL, Bindable> allBoundStuff = ...
....
bindeAllesWasGebundenWerdenMussAn(gl);
male(gl);
unbindeAllesWieder(gl);
Aber erstens wäre das wahrscheinlich sowieso nicht wirklich (einfach so) praktikabel, und zweitens vermutlich grottenlangsam. Insbesondere sehe ich im Moment das Problem, dass man zwar z.B. irgendwelche Gometriedaten irgendwoher laden kann, die dann aufwändig vorbereiten und so, um sie dann in ein VBO zu packen - und irgendwann mittendrin stellt man unvermitelt fest: Hups, jetzt ist da ein anderes GL ... Also müßten dann ja sämtliche Daten, inklusive Texturen und Geometrie komplett neu geladen werden....???:L Ich schätze mal, da kommt man nicht drumrum. Ich werde mal zusehen, das GLEventListener#init "systematischer" in meine... "Architekturüberlegungen" mit einzubeziehen... :reflect:

Ja, auf LWJGL müsste ich auch mal einen genaueren Blick werfen, aber mir gefällt JoGL eigentlich vom Aufbau her wesentlich besser. Und noch hab ich JoGL nicht aufgegeben (und als letzten Notnagel hab ich ja noch den Generator (der Code in JoGL Art ausspuckt ;) )
Generatoren gibt's ja einige: GlueGen, JNAerator, den, den du aus dieser .spec-Datei gemacht hast... Das ist zwar ein ziemlicher Aufwand, so ein Ding dazu zu bringen, dass es "durchläuft" und alles wie gewünscht erzeugt, aber ich (mit meinem Halbwissen) glaube, eine mindestens genauso große (eher deutlich größere) Herausforderung ist es, die angesprochene Verwaltung von Kontexten usw. vernünftig, sauber und stabil hinzukriegen. Eine Liste von Methoden 1:1 nach C durchrouten ist eine Sache, aber einen Canvas beizubringen, dass er sauber, effizient und fehlerfrei OpenGL anzeigt (und das auf Windows, Linux und MacOS) erfordert wohl ziemlich tiefgreifende Kenntnisse - und spätestens, wenn es nicht "nur" ein Canvas, sondern ein (GL)JPanel sein soll, wird's ja offenbar richtig tricky....
 

Evil-Devil

Top Contributor
LWJGL geht ja auch so einen static Ansatz. Du musst Dir dann nur ganz sicher sein niemals ein zweites GLJPanel (als Multikontextanwendung) einbauen zu wollen, das dürfte mit dem static Ansatz dann nämlich schwer (unmöglich?) werden.
Naja, wann brauch man schon mehr als ein GLPanel? Und wenn doch erstellt man einen Shared Context. Dann ist das auch kein Problem. Bei einem Editor würde das dann der Fall sein. Wobei das Hauptfenster natürlich nur ein Context hätte und der Rest wie Texture Browser über die Shared Contexts laufen würde.
 
G

Guest2

Gast
Das verwendet ja aber auch schon eine Utility-Bibliothek...? Ich erinnere mich von meinen ersten OpenGL-Gehversuchen her nur an irgendwelche riesigen Structs (PIXELFORMATDESCRIPTOR und Co) und die Quintessenz: "Da, wo das WM_PAINT steht, kann man zeichnen" :D (Bin dann auch schnell auf GLUT umgeschwenkt....).

Das ist tatsächlich nur JNI und die WinAPI ;). Das Pixelformat hängt schon im hDC drin und kommt über das hWnd aus dem awt canvas. Wollte man nicht auf das awt Element zeichnen, sondern in ein neues natives Fenster, müsste man aber tatsächlich das Monsterstruct anlegen ;).
(Was oben im Wesentlichen fehlt, ist ein lock auf das Element, damit Java nicht auch noch versucht in das Element zu zeichnen.)


Ja, "alles" war vielleicht zu pauschal - es sollte aber andeuten, dass man ja die Holzhammermethode verwenden könnte.... sinngemäß sowas wie
Java:
private static Map<GL, Bindable> allBoundStuff = ...
....
bindeAllesWasGebundenWerdenMussAn(gl);
male(gl);
unbindeAllesWieder(gl);
Aber erstens wäre das wahrscheinlich sowieso nicht wirklich (einfach so) praktikabel, und zweitens vermutlich grottenlangsam.

Vom Ansatz her ist das ja gar nicht so schlecht, aber ich sehe in mindestens zwei Situationen Probleme (Wenn ich den Ansatz richtig deute, vielleicht ist das aber für Dich im Bezug auf jocl und swogl sowieso ehr unbedeutend.):

Situation 1:
Z.B.: Eine Szene mit zwei Kugeln, eine soll aussehen wie Holz, die andere wie ein Wassertropfen. Im Pseudocode sähe das ungefähr so aus:

Code:
bind bump mapping shader
bind holzkugel vbo
glVertexPointer()
glDrawArrays()

bind displacement mapping shader
bind wassertropfen vbo
glVertexPointer()
glDrawArrays()

Das was gebunden wird, hängt also vom Objekt ab das gerade gezeichnet werden soll, dazu könnte man die Map um eine Liste erweitern, z.B. auf:

Code:
Map<GL, List<Bindable>>


Situation 2:
Z.B.: Ein Ego Shooter mit shadow volume:

Code:
//pass 1, fill zBuffer
glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
bind pass thru shader (we need only z values)
bind and draw [floor, player, buildings, sky dome]

//pass 2, build shadow volumes
bind fbo
bind shadow volume shader (geometry extruder) 
glDepthMask(false);
glDepthFunc(GL.GL_GREATER);
bind and draw [player, buildings] (with GL_TRIANGLES_ADJACENCY) (no floor and sky dome!)
glDepthFunc(GL.GL_LEQUAL);
glDepthMask(true);

//pass 3, color
bind color shader
bind fbo_texture
bind and draw [floor, player, buildings, sky dome]

Das was gebunden werden muss, hängt also auch noch vom aktuellen render pass ab, dazu könnte man die Map um eine weitere Map erweitern, z.B. auf:

Code:
Map<GL, Map<Pass, List<Bindable>>>

Über dem Konstrukt würden jetzt aber eine menge Methoden / Threads rumrutschen (z.B. wenn ein Player stirbt muss der aus der Liste), Datenhure beschreibt das dann schon ganz gut ;).
Außerdem müsste das synchronisiert werden, der GL Thread wäre aber wahrscheinlich wenig begeistert wenn er regelmäßig vor synchronized{} warten müsste.


Insbesondere sehe ich im Moment das Problem, dass man zwar z.B. irgendwelche Gometriedaten irgendwoher laden kann, die dann aufwändig vorbereiten und so, um sie dann in ein VBO zu packen - und irgendwann mittendrin stellt man unvermitelt fest: Hups, jetzt ist da ein anderes GL ... Also müßten dann ja sämtliche Daten, inklusive Texturen und Geometrie komplett neu geladen werden....???:L Ich schätze mal, da kommt man nicht drumrum.

Also wenn es ein GLJPanel sein soll, könnte man vermutlich einen PBuffer erstellen und alle VBOs in den PBuffer laden und dann den Kontext des PBuffers mit dem des GLJPanels (der intern auch wieder einen PBuffer verwendet) sharen.
Dann würde die init() des GLJPanel zwar auch regelmäßig neu aufgerufen werden, aber die großen Sachen (Texturen und VBOs) lägen fest im unsichtbaren 1x1 Pixel PBuffer.
Vom Quelltext macht es das aber auch nicht schöner. (Und ein Zugriff in einen shared Kontext ist etwas langsamer.)

Wenn man in der GUI den GL-Teil und den Swing-Teil trennen kann, wäre auch ein GLWindow eine Alternative. Wenn das native ist, wird die init() imho nur einmal aufgerufen (auch beim Wechsel zum Vollbild).

Ich werde mal zusehen, das GLEventListener#init "systematischer" in meine... "Architekturüberlegungen" mit einzubeziehen... :reflect:

Das kann so oder so nicht schaden ;).


aber ich (mit meinem Halbwissen) glaube, eine mindestens genauso große (eher deutlich größere) Herausforderung ist es, die angesprochene Verwaltung von Kontexten usw. vernünftig, sauber und stabil hinzukriegen. Eine Liste von Methoden 1:1 nach C durchrouten ist eine Sache, aber einen Canvas beizubringen, dass er sauber, effizient und fehlerfrei OpenGL anzeigt (und das auf Windows, Linux und MacOS) erfordert wohl ziemlich tiefgreifende Kenntnisse - und spätestens, wenn es nicht "nur" ein Canvas, sondern ein (GL)JPanel sein soll, wird's ja offenbar richtig tricky....

Ja, wahrscheinlich sogar. Wenn die OpenGL spec files mal als xml vorliegen, werde ich mir das noch mal genauer ansehen. Unabhängig von jogl, einfach weil ich wissen will ob ich es kann :D.


Naja, wann brauch man schon mehr als ein GLPanel? Und wenn doch erstellt man einen Shared Context. Dann ist das auch kein Problem. Bei einem Editor würde das dann der Fall sein. Wobei das Hauptfenster natürlich nur ein Context hätte und der Rest wie Texture Browser über die Shared Contexts laufen würde.

Nur weil der Kontext shared ist, heißt das aber noch nicht das in allen OpenGL Zustandsmaschinen der selbe Zustand herrscht. Selbst die höheren OpenGL Objekte werden nicht alle zwischen den Kontexten geteilt. Um die OpenGL Spec noch mal zu zitieren:

http://www.opengl.org/registry/doc/glspec32.core.20091207.pdf hat gesagt.:
Shared Objects and Multiple Contexts
[..]
Objects that can be shared between contexts include pixel and vertex buffer objects,
program and shader objects, renderbuffer objects, sync objects, and texture
objects (except for the texture objects named zero).
Framebuffer, query, and vertex array objects are not shared.


Und die sich dadurch ergebenden unterschiedlichen Zustände müssen / sollten nun mal in den eigenen Hilfsklassen abgebildet werden (zumindest wenn man mehrere Kontexte unterstützen will). Aber Marco schieb ja bereits das er eine vom gl (das ist in JoGL ein nicht statisches Objekt und für jedem Kontext anders) abhängige Map meinte, dadurch werden die unterschiedlichen Zustände der unterschiedlichen Kontexte (egal ob shared oder nicht) ja sauber abgebildet.

Gruß,
Fancy
 

Marco13

Top Contributor
Vom Ansatz her ist das ja gar nicht so schlecht, aber ich sehe in mindestens zwei Situationen Probleme (Wenn ich den Ansatz richtig deute, vielleicht ist das aber für Dich im Bezug auf jocl und swogl sowieso ehr unbedeutend.):

Situation 1:
Z.B.: Eine Szene mit zwei Kugeln, eine soll aussehen wie Holz, die andere wie ein Wassertropfen.

[...]

Das was gebunden wird, hängt also vom Objekt ab das gerade gezeichnet werden soll, dazu könnte man die Map um eine Liste erweitern, z.B. auf:

Code:
Map<GL, List<Bindable>>


Situation 2:
Z.B.: Ein Ego Shooter mit shadow volume:

[...]

Das was gebunden werden muss, hängt also auch noch vom aktuellen render pass ab, dazu könnte man die Map um eine weitere Map erweitern, z.B. auf:

Code:
Map<GL, Map<Pass, List<Bindable>>>

Erstmal allgemein: Das, was ich da angefangen hatte, hatte nichts mit Swogl zu tun - außer dem "impliziten" Zweck, (Er)kenntnisse zu erlangen, die dann auch für Swogl hilfreich sein könnten. (Eine Erkenntnis ist, dass ich bei weiteren Entwicklungen zu Swogl versuchen werde, die JOGL-Spezifität zu minimieren, so dass es notfalls auch mit anderen GL-Bindings funktionieren könnte...)

Das Beispiel mit der "Holzhammer-Methode" sollte nur suggestiv sein - mir ist klar, dass es in Wirklichkeit komplizierter ist. Die Abhängigkeit der zu bindenden Dinge vom Objekt war mir z.B. durchaus bewußt. Die Abhängigkeit zum Render-Pass weniger, aber das wäre im Prinzip mit dem "Rohbau", der da mit vielen(!) Fragezeichen versehen in meinem Kopf rumgeistert, abzudecken (das ist alles HÖCHST experimentell, und bis das durch weitere Einsichten "festgerüttelt" ist, wird es wohl noch eine Weile dauern.... :( )
Aber im Moment gibt es bei mir eine Klasse "RenderableObject". Die hat im Prinzip eine Methode "render(gl)". Was diese Methode genau macht, bleibt ihr überlassen. Zusätzlich gibt es eine Klasse, die für ein Tuple (Program, RenderableObject) auf eine Map<String, List<String>> abbildet. Mit diesen Maps werden String-Konstanten, die beim Anwender für Vertexdaten und weitere Attribute stehen, abgebildet auf die Namen im Shaderprogram. Die Attribute stehen (mit ihren Namen) im RenderableObject, und werden vor dem Rendern gebunden. Man könnte also im Pseudocode sowas sagen wie
Java:
class RenderableObject
{
    void bind(GL gl, Program program)
    {
        for (each attribute)
        {
            attribute.bind(gl);
            List<String> namesInProgram = getMap(program, RenderableObject.this)
            for (each nameInProgram)
            {
                glBindAttribLocation(...nameInProgram...);
            }
        }
    }
}
Was theoretisch sowas erlauben würden wie
Code:
putIntoMagicMap("vertices", "programInputVertices");

// putIntoMagicMap("normals", "programInputNormals");
// Nee, die Normalen sollen lieber als Farben dargestellt werden
putIntoMagicMap("normals", "programInputColors");
Das macht vielleicht keinen Sinn... aber im Prinzip ging es darum, an einer Stelle die Verbindung zwischen den Attributen im RenderableObject und den Namen, die im Program erwartet werden, herstellen zu können - ähnlich wie bei dir mit den enums. (So ganz reicht das aber noch nicht für alles, was man machen wollen könnte - das ist noch sehr vorläufig... )

Das enthält aber noch eine andere Sache: "Bindable" muss ja nicht nur eine "GL-Entität" sein, sondern kann auch etwas sein, was GL-Entitäten enthält. Bei dem Beispiel mit den Kugeln gäbe es eben zwei RenderableObjects - eins für die Holzkugel, eins für den Wassertropfen. Dass die sich ggf. Daten "teilen" könnten, sieht man ja von außen nicht. Die beiden Codeblöcke, die du dazu geschrieben hast, wären gerade das, was dort jeweils in der Render-Methode steht.

Aber wie schon angedeutet: Ich gehe davon aus, dass das nich so leicht ist - und wenn man sich es trotzdem leicht MACHT (oder das versucht) wird es (besonders wenn man so wenig Durchblick hat, wie ich im Moment) vermutlich leicht unflexibel oder eben grottig langsam.






Also wenn es ein GLJPanel sein soll, könnte man vermutlich einen PBuffer erstellen und alle VBOs in den PBuffer laden und dann den Kontext des PBuffers mit dem des GLJPanels (der intern auch wieder einen PBuffer verwendet) sharen.
[...]
Wenn man in der GUI den GL-Teil und den Swing-Teil trennen kann, wäre auch ein GLWindow eine Alternative. Wenn das native ist, wird die init() imho nur einmal aufgerufen (auch beim Wechsel zum Vollbild).

Hmja, wie man das ganze dann auf den Bildschirm bringen kann ist eben (wie angedeutet) was, wo ich noch weniger Plan habe - gerade DAS ist ja das, was durch JOGL eigentlich schön versteckt ist... Ich hätte nur vermutet, dass man, wenn man mit FBO schon in Texturen rendern kann, es doch eigentlich möglich sein müßte, (einigermaßen) "direkt" in ein BufferedImage zu rendern... Aber wo und wie man dann den nativen Kontext handlet, und wie man sicherstellt, dass der immer existiert und gültig ist und so... dazu müßte ich mich erstmal in die schon existierenden Ansätze (d.h. JOGL, oder allgemein natives Rendern in JComponents) einlesen...



... das er eine vom gl [...] abhängige Map meinte, dadurch werden die unterschiedlichen Zustände der unterschiedlichen Kontexte (egal ob shared oder nicht) ja sauber abgebildet.
... wobei ich aus OO-Sicht dort eigentlich ein Wort streichen würde.... aber ich bin mir natürlich (noch) nicht sicher, ob dieses Streichen auf Basis der "Constraints" die einem von OpenGL unumstößlich vorgegeben werden, noch gerechtfertigt wäre....
 
G

Guest2

Gast
Aber wie schon angedeutet: Ich gehe davon aus, dass das nich so leicht ist - und wenn man sich es trotzdem leicht MACHT (oder das versucht) wird es (besonders wenn man so wenig Durchblick hat, wie ich im Moment) vermutlich leicht unflexibel oder eben grottig langsam.

Also ich find den Ansatz bisher auf jeden Fall ganz gut. Ob das immer klappt und wie gut kann ich aber so auf Anhieb auch nicht sagen. :D

Was die Geschwindigkeit angeht, so ist bei mir die letzte Zeit praktisch immer der Fragmentshader der Flaschenhals (und da insbesondere die Texturzugriffe (kann auch sein das meine Grafikkarte einfach zu wenig Textureinheiten hat).

In OpenGL selber halt ich mich einfach an

1. möglichst wenig gl* Befehle
2. möglichst keine glGet* (nur in der / den init())
3. gar keine gl* würde die Nerven schonen ;)


Hmja, wie man das ganze dann auf den Bildschirm bringen kann ist eben (wie angedeutet) was, wo ich noch weniger Plan habe - gerade DAS ist ja das, was durch JOGL eigentlich schön versteckt ist... Ich hätte nur vermutet, dass man, wenn man mit FBO schon in Texturen rendern kann, es doch eigentlich möglich sein müßte, (einigermaßen) "direkt" in ein BufferedImage zu rendern... Aber wo und wie man dann den nativen Kontext handlet, und wie man sicherstellt, dass der immer existiert und gültig ist und so... dazu müßte ich mich erstmal in die schon existierenden Ansätze (d.h. JOGL, oder allgemein natives Rendern in JComponents) einlesen...

So kompliziert meinte ich das aber gar nicht. Du kannst den Kontext eines GLPBuffer durchaus einfach mit dem Kontext eines GLJPanel teilen, ohne in die untiefen absteigen zu müssen. Mal ein Beispiel:

http://too-late.de/kskb/gl2sample05.zip

Im Wesentlichen ist das ein Würfel als VBO. In der main() wird ein GLPBuffer erzeugt und dessen Kontext mit einem erzeugten GLJPanel geteilt. In der init() des PBuffer wird das VBO des Würfels erstellt und an ein Handle gehangen (die init() des PBuffer wird nur 1x aufgerufen! (Der zugehörige Kontext existiert bis zum Ende des Programms)). In der init() des GLJPanel wird lediglich das für den Würfel notwendige glEnableClientState() aufgerufen, deswegen ist es auch egal das dieses init() bei einem resize neu aufgerufen wird.

Aber:
1. jetzt hätte das RenderableObject zwei verschiedene init() Methoden
2. im Programm leben jetzt tatsächlich 2 verschiedene gl Objekte
3. shared Kontext ist langsamer

Die andere Alternative die ich meinte wäre:

Java:
final GLProfile glProfile = GLProfile.get(GLProfile.GL3);
final GLCapabilities glCapabilities = new GLCapabilities(glProfile);

final Display display = NewtFactory.createDisplay(null);
final Screen screen = NewtFactory.createScreen(display, 0);
final Window window = NewtFactory.createWindow(screen, glCapabilities); 

final GLWindow glWindow = GLWindow.create(window);

(Wichtig: GLWindow.create() alleine ist nicht native, nur mit dem NewtFactory Wust oben wird es native)

Das erzeugt ein neues Fenster, das weder Swing noch AWT ist (sondern nativ). Dafür ist es aber richtig schnell (schneller als GLCanvas und viel schneller als GLJPanel). Und die init() wird wohl auch nur einmal aufgerufen.

Aber:
1. der Animator geht nicht (das Fenster muss mit dem selben Thread erzeugt werden wie später display() aufgerufen wird).
2. man muss seine GUI halt separieren in ein reines Anzeigefenster und ein / weitere Fenster mit Steuerelementen.


Das mit dem FBO in ein BufferedImage rendern unterscheidet sich praktisch nicht vom internen PBuffer Ansatz der derzeit im GLJPanel verwendet wird. Interessanter wird es wenn Swing mit OpenGL läuft, weil ein JPanel intern ebenfalls ein FBO nutzt. Und über reflection Voodoo kann man OpenGL Befehle im Kontext des JPanel absetzen und so die Textur des PBuffer in das FBO des JPanel drücken ohne das die Grafikkarte verlassen werden muss.

Aber:
1. der Code dazu im GLJPanel ist *brrrrrr*
2. Selbermachen ist heftig, da nichts dokumentiert ist (reflection im Blindflug über die swing internas)
3. swing mit OpenGL geht nur ohne Aero und auch dann nicht wirklich stabil


... wobei ich aus OO-Sicht dort eigentlich ein Wort streichen würde.... aber ich bin mir natürlich (noch) nicht sicher, ob dieses Streichen auf Basis der "Constraints" die einem von OpenGL unumstößlich vorgegeben werden, noch gerechtfertigt wäre....

Also, ich muss zugeben, ich weis nicht so genau was Du meinst, aber ich hatte diesen Satz auch nicht so genau mit der Goldwaage ausformuliert ;)

Gruß,
Fancy
 

Marco13

Top Contributor
Also ich find den Ansatz bisher auf jeden Fall ganz gut. Ob das immer klappt und wie gut kann ich aber so auf Anhieb auch nicht sagen. :D

Das wird sich rausstellen :D Leider kann ich dabei nicht so viel planen oder vorausdenken wie ich gerne würde. Und wenn ich's versuche, kommt unerwartet jemand daher und erzählt was von Dingen, die ich nich bedacht hätte ... wie "Render-Passes" :pueh: ;) Es ist aber auch so, dass man SO viele Dinge eigentlich berücksichtigen müßte, dass ich mir auch mal überlegen muss, wie weit man da überhaupt gehen kann...

Was die Geschwindigkeit angeht, so ist bei mir die letzte Zeit praktisch immer der Fragmentshader der Flaschenhals (und da insbesondere die Texturzugriffe (kann auch sein das meine Grafikkarte einfach zu wenig Textureinheiten hat).

In OpenGL selber halt ich mich einfach an

1. möglichst wenig gl* Befehle
2. möglichst keine glGet* (nur in der / den init())
3. gar keine gl* würde die Nerven schonen ;)

OK, wenn noch sowas wie (ggf. merhere) Texturen dazukommen wird's auch von den Strukturen her nochmal aufwändiger... Ich plag' mich im Moment ja noch mit blanker Geometrie rum... Wobei ich denke, dass die Aufrufe an sich doch nicht soo schlimm sein können (naja, glGet hab' ich z.B. eh noch nie verwendet) aber ich denke das aufwändige sind die Dinge, die eigentlich während der Initialisierung gemacht werden - und von denen man versucht sein könnte, sie in die nähe des Zeichnens zu ziehen... Das bezieht sich auch darauf:

So kompliziert meinte ich das aber gar nicht. Du kannst den Kontext eines GLPBuffer durchaus einfach mit dem Kontext eines GLJPanel teilen, ohne in die untiefen absteigen zu müssen. Mal ein Beispiel:
[...]

Hab's mir mal angesehen: Abgesehen von der Initialisierungs-Magie sieht das ja eigentlich ganz übersichtlich aus. Aber ... mir fehlen irgendwie die Kenntnisse...um schon... recht "einfache" Fragen beantworten zu können... wie zum Beispiel ob das
Code:
// In initForNormalGL 
        gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY);
nicht auch einfach in der "display" gemacht werden könnte: Im Vergleich zu einem glBufferData kann so ein kleines, unscheinbares glEnable* doch nicht zeitkritisch sein, oder.... ? ???:L


Die andere Alternative die ich meinte wäre:

[...]
final GLWindow glWindow = GLWindow.create(window);
[...]
Aber:
1. der Animator geht nicht (das Fenster muss mit dem selben Thread erzeugt werden wie später display() aufgerufen wird).
2. man muss seine GUI halt separieren in ein reines Anzeigefenster und ein / weitere Fenster mit Steuerelementen.

Der Zusammenhang zum Animator erschließt sich mir da jetzt nicht ganz... Zum "Separieren" des GUI könnte man sich vielleicht Workarounds überlegen... in dem Sinne, dass man das GLWindow mit ein paar Listenern an den Swing-Frame pappt, und als Component-Ersatz verwendet (murksig, aber wenn es mehr Probleme löst, als es aufwirft... :bahnhof: ). Trotzdem wäre eine einfache und direkte Integration in Swing natürlich schöner....


Das mit dem FBO in ein BufferedImage rendern unterscheidet sich praktisch nicht vom internen PBuffer Ansatz der derzeit im GLJPanel verwendet wird. Interessanter wird es wenn Swing mit OpenGL läuft, weil ein JPanel intern ebenfalls ein FBO nutzt. Und über reflection Voodoo kann man OpenGL Befehle im Kontext des JPanel absetzen und so die Textur des PBuffer in das FBO des JPanel drücken ohne das die Grafikkarte verlassen werden muss.

Aber:
1. der Code dazu im GLJPanel ist *brrrrrr*
2. Selbermachen ist heftig, da nichts dokumentiert ist (reflection im Blindflug über die swing internas)
3. swing mit OpenGL geht nur ohne Aero und auch dann nicht wirklich stabil

Das klingt dann doch ziemlich magisch... OK, wenn man genau weiß, was man da tut, ist es vielleicht legitim, aber die potentiellen Probleme sind zu gravierend: Dass es unter Aero nicht geht... joa, das wird Sun wohl früher oder später fixen - das größere Problem ist: WENN sie das fixen, benennen sie vielleicht eine Variable um - an der API ändert sich nichts, aber die selbstgelötete GL-Anbindung haut's dann raus... Am coolsten wäre halt, wenn Sun irgendwo offiziell in der API eine Art "GL-Zugang" anbieten würde - es würde ja schon reichen, wenn sie sagen würden: "Hier habt ihr einen int, das ist ein FBO, macht damit was ihr wollt..." Aber dazu wird's wohl so schnell nicht kommen...



Also, ich muss zugeben, ich weis nicht so genau was Du meinst, aber ich hatte diesen Satz auch nicht so genau mit der Goldwaage ausformuliert ;)
Es ging um das Wort "sauber" ;)
 
G

Guest2

Gast
..., kommt unerwartet jemand daher und erzählt was von Dingen, die ich nich bedacht hätte ... wie "Render-Passes" :pueh: ;)

Ich gebe mir halt mühe, zur vollständigen Verwirrung beizutragen ;)


Es ist aber auch so, dass man SO viele Dinge eigentlich berücksichtigen müßte, dass ich mir auch mal überlegen muss, wie weit man da überhaupt gehen kann...

Ja, insbesondere da man beim OOP darauf konditioniert ist, seine Klassen so zu verfassen das sie in gewisser Form allgemeingültig sind und immer wieder verwendet werden könnten. Bei OpenGL wird es dann aber eben schnell hässlich, langsam und später stellt man auch noch fest, das doch irgendwas so nicht geht.

Vielleicht muss man einfach akzeptieren, manche Klassen nicht wiederverwenden zu können. Sondern für ein neues Projekt kopieren und mit dem Refactoringhammer passend schlagen muss. Dan wären sie zwar in jedem Projekt anders, aber eben überall relativ übersichtlich.


Im Vergleich zu einem glBufferData kann so ein kleines, unscheinbares glEnable* doch nicht zeitkritisch sein, oder.... ? ???:L

Gute Frage! ;)

Ich hab eine Aussage eines NVIDIA Mitarbeiters im Kopf der vage (im Bezug auf 3D Engine Optimierung) schrieb: Zeichnen Sie die Szene so das der OpenGL Zustand möglichst selten geändert werden muss...

Da das letztendlich auch meine Architekturüberlegungen beeinflusst, habe ich das gerade versucht zu verifizieren. Dabei hängt das wohl grundsätzlich von der darzustellenden Szene ab. Bei einem Objekt mit 240k Vertices spielt es wohl keine Rolle. Bei 10k Objekten mit 24 Vertices wahrscheinlich schon.

Ich hab das sample05 genommen und die display() so verändert das der Würfel 10k mal (jeweils leicht versetzt) gezeichnet wurde. Und dann die fps ermittelt.

Alle Zahlen in fps und über 60 Sekunden gemessen:

Code:
GLJPanel (10k VBO a 24 Vertices): 
ohne glEnable & glDisable:              88
mit glEnable & ohne glDisable:          86
mit glEnable & glDisable:               79

GLWindow (10k VBO a 24 Vertices):
ohne glEnable & glDisable:             129
mit glEnable & ohne glDisable          104
mit glEnable & glDisable:              110

Interessant finde ich den letzten Wert des GLWindow (3x nachgemessen). Ich kann mir das nur erklären, wenn der Grafikkartentreiber da anfängt irgendwas wegzuoptimieren. Ich hab die Szene dann so verändert, das nur noch 50% farbig gezeichnet wurden, der Rest ohne glColorPointer():

Code:
GLJPanel (10k VBO a 24 Vertices, 50% ohne glColorPointer): 
abwechselnd (glEnable&glDisable notwendig):          79
nacheinander (glEnable&glDisable immer):             86
nacheinander (glEnable&Disable nur wenn nötig):      88

GLWindow (10k VBO a 24 Vertices, 50% ohne glColorPointer):
abwechselnd (glEnable&glDisable notwendig):         118
nacheinander (glEnable&glDisable immer):            135
nacheinander (glEnable&Disable nur wenn nötig):     143

Beim GLJPanel scheint das alles nicht sonderlich relevant zu sein, vermutlich liegt der Flaschenhals eh beim BufferedImage. Beim GLWindow finde ich den Unterschied hingegen schon beachtlich.

Allerdings ist das alles nicht sonderlich praxisrelevant, wer zeichnet schon genau abwechselt jeweils 5k mal das selbe.

Interessanter (da vermutlich deutlich teuer) ist das umschalten zwischen verschiedenen Shadern. Sprich, besser erst alle Holzkugeln und dann also Wassertropfen zeichnen, oder einfach so wie sie in irgendeiner List<Renderable> liegen?

Also, selbe Szene jedoch zwei Shader. Einer gibt r,g,b aus, der andere g, b, r.

Code:
GLJPanel (10k VBO a 24 Vertices, 50% Shader A/B): 
abwechselnd (glUseProgram notwendig):         38
nacheinander (glUseProgram immer):            42
nacheinander (glUseProgram nur wenn nötig):   68  


GLWindow (10k VBO a 24 Vertices, 50% Shader A/B):
abwechselnd (glUseProgram notwendig):         45
nacheinander (glUseProgram immer):            51   
nacheinander (glUseProgram nur wenn nötig):   70

Die Zahlen finde ich dann schon beeindruckend.

Mein Fazit daraus ist, das die grobe Architektur schon fast durch die Minimierung der notwendigen Veränderungen des Zustands vorgegeben wird. Z.B. ganz vage so:

"gl" -> "render pass" -> "shader" -> "renderable"

Ich denke, dann könnte man die notwendigen Zustandsveränderungen minimieren, indem sie möglichst weit "oben" angesiedelt werden.

Z.B. im render pass "shadow volume" liegt lediglich ein shader "geometrie extruder" und in dem liegt eine Liste von 1k "renderable":

Code:
"shadow volume".go();

"shadow volume".go(){

	glDepthMask(false);
	glDepthFunc(GL.GL_GREATER);

	for(shader s : ["geometrie extruder"])
		s.go();

	glDepthFunc(GL.GL_LEQUAL);
	glDepthMask(true);

}

"geometrie extruder".go(){

	setFBO();
	glEnable(...);

	for(Renderable r : ["a", ...])
		r.go(); 

}

"a".go(){

	glVertexAttribPointer();
	glDrawElements();	

}

Bis hier ja ganz simpel, aber ich bin mir sicher, das wenn ich die anderen Attribute da Einbau es, doch schnell wieder hässlich wird.


Der Zusammenhang zum Animator erschließt sich mir da jetzt nicht ganz...

Der JoGL Animator startet intern einen eigenen Thread der dann regelmäßig die display() aufruft. Das darf aber nicht sein, weil das GLWindow mit dem selben Thread erzeugt werden muss, der auch später die display() aufruft. Man muss also immer irgend so was bauen:

Code:
glWindow = GLWindow.create(window);
glWindow.addGLEventListener(this);
glWindow.setVisible(true);

while (run) {            
            glWindow.display();
            Thread.yield();
}


Am coolsten wäre halt, wenn Sun irgendwo offiziell in der API eine Art "GL-Zugang" anbieten würde

Also wenn es nach mir ginge, könnten sie auch gerne direkt ein vollständiges gl Binding bieten. :D


Es ging um das Wort "sauber" ;)

;)

Gruß,
Fancy
 

Marco13

Top Contributor
Ja, insbesondere da man beim OOP darauf konditioniert ist, seine Klassen so zu verfassen das sie in gewisser Form allgemeingültig sind und immer wieder verwendet werden könnten. Bei OpenGL wird es dann aber eben schnell hässlich, langsam und später stellt man auch noch fest, das doch irgendwas so nicht geht.

Vielleicht muss man einfach akzeptieren, manche Klassen nicht wiederverwenden zu können. Sondern für ein neues Projekt kopieren und mit dem Refactoringhammer passend schlagen muss. Dan wären sie zwar in jedem Projekt anders, aber eben überall relativ übersichtlich.

Ja, überlegt habe ich das auch schon: Vielleicht IST OpenGL ja genau die API, die genau DIE Funktionalität bietet, die man braucht, d.h. vielleicht KANN man da gar keine "bequemen OO-Wrapper-Klassen" drumrumstricken, ohne dass irgendwelche Nachteile oder Unschönheiten entstehen. Aber andererseits sind so viele Sachen immer gleich, dass ich das (bisher) nicht akzeptieren kann, und immernoch davon ausgehe, dass ich die "geeignete Abstraktion" und "geeignete Schnittstelle" (nicht zuletzt wegen mangelnder Kenntnisse des "neuen" OpenGL) einfach noch nicht gefunden habe. (Das ist aber ein nicht ganz unwichtiger Punkt: Vermutlich wäre das alles viel einfacher, wenn man vorher schon 1000 GL3.2-Programme geschrieben hätte... :meld: ;)


Ich hab eine Aussage eines NVIDIA Mitarbeiters im Kopf der vage (im Bezug auf 3D Engine Optimierung) schrieb: Zeichnen Sie die Szene so das der OpenGL Zustand möglichst selten geändert werden muss...

Da das letztendlich auch meine Architekturüberlegungen beeinflusst, habe ich das gerade versucht zu verifizieren. Dabei hängt das wohl grundsätzlich von der darzustellenden Szene ab. Bei einem Objekt mit 240k Vertices spielt es wohl keine Rolle. Bei 10k Objekten mit 24 Vertices wahrscheinlich schon.

[...]

So gannnz haben sich mir die Zahlen nicht erschlossen - man kann ja ein glEnable nicht einfach weglassen (bzw. wie soll dann noch ein repräsentativer Vergleich entstehen?). Die Frage, ob man glDisable jedes mal aufrufen soll, oder ob man es einfach "an lassen" kann, weil man's spätestens beim nächsten display ja wieder einschalten würde, ist da schon eher interessant. Allerdings muss ich sagen, dass die Unterschiede sich ja alle im deutlich einstelligen Prozentbereich bewegen... Also scheint das ja nicht sooo dramatisch zu sein....


Interessanter (da vermutlich deutlich teuer) ist das umschalten zwischen verschiedenen Shadern. Sprich, besser erst alle Holzkugeln und dann also Wassertropfen zeichnen, oder einfach so wie sie in irgendeiner List<Renderable> liegen?

[...]
Die Zahlen finde ich dann schon beeindruckend.

Die Zahlen sind schon deutlicher, aber auch noch nicht soo dramatisch. Natürlich kann Grafik nie schnell genug sein, aber ... für einen "Satz von kleinen Utilities für's schnelle Erstellen einer Anwendung" ist der Unterschied zwischen 50 und 55 FPS wohl nicht so wichtig wie für einen kommerziellen 3D-shooter.


Mein Fazit daraus ist, das die grobe Architektur schon fast durch die Minimierung der notwendigen Veränderungen des Zustands vorgegeben wird. Z.B. ganz vage so:

"gl" -> "render pass" -> "shader" -> "renderable"

Ich denke, dann könnte man die notwendigen Zustandsveränderungen minimieren, indem sie möglichst weit "oben" angesiedelt werden.

Z.B. im render pass "shadow volume" liegt lediglich ein shader "geometrie extruder" und in dem liegt eine Liste von 1k "renderable":
[...]
Bis hier ja ganz simpel, aber ich bin mir sicher, das wenn ich die anderen Attribute da Einbau es, doch schnell wieder hässlich wird.

Dass man Zustandsänderungen minimieren sollte, hatte ich aber auch noch vom "alten" OpenGL im Hinterkopf. Dort ganz es AFAIK sogar Ansätze, alle Objekte systematisch (d.h. auch automatisch) so zu sortieren und zu "clustern", dass die Zustandswechsel minimiert werden (konsequent betrachtet ist das mindestens NP-hart :eek: ). Eine Schwierigkeit bei dem Versuch, "allgemeine" Klassen zu schreiben, ist eben, dass man nicht weiß, was irgendwann jemand damit machen will. Oder plakativ formuliert, und wie oben schon angedeutet: Eine API, die genau alle Funktionen von OpenGL/JOGL anbietet, kann ja eigentlich prinzipbedingt kaum einfacher sein, als OpenGL selbst ... ;)




Der JoGL Animator startet intern einen eigenen Thread der dann regelmäßig die display() aufruft. Das darf aber nicht sein, weil das GLWindow mit dem selben Thread erzeugt werden muss, der auch später die display() aufruft. Man muss also immer irgend so was bauen:

Meine erste Intuition wäre jetzt, das auf dem EDT machen zu lassen ???:L Aber das hätte wahrscheinlich auch potentielle unerwünschte Seiteneffekte...
 
G

Guest2

Gast
Vermutlich wäre das alles viel einfacher, wenn man vorher schon 1000 GL3.2-Programme geschrieben hätte... :meld: ;)

Na da haben wir ja beide noch einiges zu tun. :D


So gannnz haben sich mir die Zahlen nicht erschlossen - man kann ja ein glEnable nicht einfach weglassen (bzw. wie soll dann noch ein repräsentativer Vergleich entstehen?).

Ja, den Teil hätte ich vermutlich ausführlicher beschreiben sollen. Das "mit" und "ohne" bezog sich lediglich auf das glEnable/glDisable in der display() des cube. In der init() stand das glEnable immer, so das das optische Ergebnis schon gleich war.


konsequent betrachtet ist das mindestens NP-hart :eek:

Das wäre für die Gesamtperformance vermutlich nicht sonderlich förderlich :D.

Was für mich dahinter stand, war insbesondere die Frage wie ich meine Szene intern repräsentiere. Aus OO sicht würde ich zu folgendem tendieren:

Code:
Welt	-> Haus A 	-> Dach A
			-> Wand A
			-> Fenster A
	-> Haus B 	-> Dach B
			-> Wand B
			-> FensterB

Dann wüste das Haus wie es sich darzustellen hat, bzw. das es Dach, Wand und Fenster hat, die dann jeweils wüsten wie sie sich darzustellen haben. Die Shader würden dann an den Objekten hängen.

Die andere Alternative (und wohl auch schnellere) ist die Objekte an die Shader zu hängen:

Code:
Welt 	-> Shader "Dach"	-> Dach A
				-> Dach B
	-> Shader "Wand" 	-> Wand A
				-> Wand B
	-> Shader "Fenster" 	-> Fenster A
				-> Fenster B


Oder plakativ formuliert, und wie oben schon angedeutet: Eine API, die genau alle Funktionen von OpenGL/JOGL anbietet, kann ja eigentlich prinzipbedingt kaum einfacher sein, als OpenGL selbst ... ;)

Insbesondere wollte die Khronos Gruppe für OpenGL3 ja ursprünglich einen "objekt orientierteren" Weg einschlagen, hat das dann aber nach über einem Jahr Bedenkzeit praktisch verworfen. Vielleicht sollte man das auch als wink mit dem Vierkantrohr verstehen. ;)


Meine erste Intuition wäre jetzt, das auf dem EDT machen zu lassen ???:L Aber das hätte wahrscheinlich auch potentielle unerwünschte Seiteneffekte...

Beim GLWindow gibt es ja auch erstmal kein awt, weil es keine awt Elemente gibt. Und damit eben auch kein EDT. Praktisch muss man sich allerdings tatsächlich selbst einen EDT bauen, der dann auch die GLWindow.display() regelmäßig aufruft, sonnst knallt es an allen Ecken und Enden. Ungewöhnlich ist dann eben nur das der EDT dann auch "sein" Fenster selbst erzeugen muss (das "new GLWindow" muss also in den EDT).

GLWindow hat sowieso ein paar Überraschungen, da praktisch alle Datentypen aus com.sun.javafx.newt kommen. Mal eben einen schon vorhandenen KeyListener dranhängen ist dann nicht, selbst das KeyEvent aus com.sun.javafx.newt ist nicht mit denen aus awt verwand oder würden sich irgendwie casten lassen.

Gruß,
Fancy
 

Marco13

Top Contributor
Was für mich dahinter stand, war insbesondere die Frage wie ich meine Szene intern repräsentiere. Aus OO sicht würde ich zu folgendem tendieren:
[...]
Dann wüste das Haus wie es sich darzustellen hat, bzw. das es Dach, Wand und Fenster hat, die dann jeweils wüsten wie sie sich darzustellen haben. Die Shader würden dann an den Objekten hängen.

Die andere Alternative (und wohl auch schnellere) ist die Objekte an die Shader zu hängen:
[...]

Ja, und die Wunschlösung wäre natürlich, dass man seine Objekthierarchie "intuitiv" (also wie im ersten Beispiel) aufbauen kann, und er das ganze dann intern so umorganisiert, dass es für den Render-Kern so aussieht, als wäre es die zweite. Wenn man NUR nach dem verwendeten Shader sortieren wollte, wäre das gar nicht so aufwändig: Einmal den Szenegraph traversieren, alle Blätter in eine Map<ShaderID, List<Objekt>> legen, und die dann durchrendern. Aber bei dem Wort "Szenegraph" (und dem Gedanken an solche Dinge wie transparenzen, wo ggf. die Renderreihenfolge relevant ist) merkt man schon, dass so was lapidar dahingeschriebenes ziemlich aufwändig sein könnte...




Insbesondere wollte die Khronos Gruppe für OpenGL3 ja ursprünglich einen "objekt orientierteren" Weg einschlagen, hat das dann aber nach über einem Jahr Bedenkzeit praktisch verworfen. Vielleicht sollte man das auch als wink mit dem Vierkantrohr verstehen. ;)
Hmja... wie schon angedeutet: Es ist (für mich) schwierig, zu sagen, ob und wie man eine geeignete Trennlinie zwischen den "High-Level"-Teil und dem "Low-Level-Teil" ziehen kann. Etwas grob verallgemeinert: Man könnte einfach ganz "stupide" Klassen für alle OpenGL-Entitäten einführen: Ein Shader mit ID und SourceCode, ein Program mit Shadern, eine Klasse VertexAttribPointer mit
index, size, type, normalized, stride, pointer ( ;) )
... Das ist dann viel Aufwand, bringt aber keinen Vorteil und keine Vereinfachung.
Das andere Extrem wäre, eine komplette Szenengraph-API zu basteln, die in diesem Sinne "Renderer-Unabhängig" ist - man sagt einfach "Mach mir einen Transformknoten und häng' da die Geometrie aus dieser OBJ-Datei dran". Dann hat man aber SO wenig Kontrolle über den GL-Teil, dass man gleich Java3D nehmen kann. Mal schauen, ob man da einen geeigneten Mittelweg finden kann...



Beim GLWindow gibt es ja auch erstmal kein awt, weil es keine awt Elemente gibt. Und damit eben auch kein EDT. Praktisch muss man sich allerdings tatsächlich selbst einen EDT bauen, der dann auch die GLWindow.display() regelmäßig aufruft, sonnst knallt es an allen Ecken und Enden. Ungewöhnlich ist dann eben nur das der EDT dann auch "sein" Fenster selbst erzeugen muss (das "new GLWindow" muss also in den EDT).

GLWindow hat sowieso ein paar Überraschungen, da praktisch alle Datentypen aus com.sun.javafx.newt kommen. Mal eben einen schon vorhandenen KeyListener dranhängen ist dann nicht, selbst das KeyEvent aus com.sun.javafx.newt ist nicht mit denen aus awt verwand oder würden sich irgendwie casten lassen.

OK, damit (javafx und newt) hatte ich mich bisher noch gar nicht so auseinandergesetzt. Aber könnte man nicht (eine Dummy-Component erstellen, und dann) dem "echten" EDT die Arbeit aufhalsen, die man sonst eigentlich mit dem selbstgebauten EDT machen würde? Und selbst wenn das nicht geht, könnte man das theoretisch ja relativ leicht umgehen: Man macht sich seinen eigenen EDT, der einfach alle Events ggf. mit SwingUtilities und dispatchEvent an den echten EDT weiterreicht. Dass die Events nicht "Blutsverwandt" sind, ist dabei ja nicht so wichtig: Sie scheinen zumindest SO ähnlich zu sein, dass sie sich trivial ineinander umbauen lassen. Aber wenn ich das richtig in Erinnerung habe, ist die Frage nach der Zukunft von JOGL ja gerade in bezug auf die com.sun Packages (und gerade javafx) unklar...
 
G

Guest2

Gast
... merkt man schon, dass so was lapidar dahingeschriebenes ziemlich aufwändig sein könnte...

In der Tat. :(

Und selbst wenn das nicht geht, könnte man das theoretisch ja relativ leicht umgehen: Man macht sich seinen eigenen EDT, der einfach alle Events ggf. mit SwingUtilities und dispatchEvent an den echten EDT weiterreicht. Dass die Events nicht "Blutsverwandt" sind, ist dabei ja nicht so wichtig: Sie scheinen zumindest SO ähnlich zu sein, dass sie sich trivial ineinander umbauen lassen.

Als Fingerübung schreibe ich derzeit an einem etwas größeren GL3.2 Programm, darin Kapsel ich alle JoGL Klassen in eigene Klassen, um innerhalb des Projektes keine Verweise auf die JoGL Klassen zu haben. Darin sieht "mein GLWindow" derzeit etwa so aus:

Java:
public class GLWindow extends Component {

    private final Queue<Runnable>                        invokeLater = new ConcurrentLinkedQueue<Runnable>();

    private volatile boolean                             run         = true;
    private volatile com.sun.javafx.newt.opengl.GLWindow glWindow;


    public GLWindow(final GLProfile profile, final int width, final int height) {

        new Thread(new Runnable() {

            @Override
            public void run() {

                final javax.media.opengl.GLProfile glProfile = javax.media.opengl.GLProfile.get(profile.getID());
                final GLCapabilities glCapabilities = new GLCapabilities(glProfile);
                final Display display = NewtFactory.createDisplay(null);
                final Screen screen = NewtFactory.createScreen(display, 0);
                final Window window = NewtFactory.createWindow(screen, glCapabilities);

                final int posX = (screen.getWidth() / 2) - (width / 2);
                final int posY = (screen.getHeight() / 2) - (height / 2);

                glWindow = com.sun.javafx.newt.opengl.GLWindow.create(window);
                glWindow.setPosition(posX, posY);
                glWindow.setSize(width, height);

                while (run) {

                    final Runnable runnable = invokeLater.poll();
                    if (runnable != null)
                        runnable.run();

                    if (glWindow.isVisible())
                        glWindow.display();

                    Thread.yield();

                }

                glWindow.destroy();
                System.exit(0);

            }
        }).start();

        while (glWindow == null)
            Thread.yield();

    }
    
    [..]

    @Override
    public void addMouseMotionListener(final MouseMotionListener mouseMotionListener) {

        invokeLater.add(new Runnable() {

            @Override
            public void run() {

                glWindow.addMouseListener(new com.sun.javafx.newt.MouseListener() {


                    @Override
                    public void mouseDragged(final com.sun.javafx.newt.MouseEvent e) {

                        mouseMotionListener.mouseDragged(new MouseEvent(GLWindow.this, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getX() + glWindow.getX(), e.getY() + glWindow.getY(), e.getClickCount(), false, e.getButton()));

                    }

                    [..]
                  
                });

            }

        });
    }

    [..]

    @Override
    public void setVisible(final boolean visible) {

        invokeLater.add(new Runnable() {

            @Override
            public void run() {

                glWindow.setVisible(visible);

            }
        });

    }
    
    [..]


    public void close() {

        run = false;

    }

}

Das ist zwar nicht immer schön, läuft aber zumindest im Ergebnis geschmeidig. Wenn ich Events an den normalen awt EDT weiterleiten würde, hätte ich etwas Bauchscherzen ob das nicht evtl. zu Mircorucklern führen würde. (Um das genau sagen zu können fehlt mir aber schlicht die Kenntnis über den inneren Aufbau des normalen EDT)

Blöde ist aber z.B. das setCursor nicht existiert. Bei ner FPS Steuerung ist das wenig prickelnd den Cursor zu sehen. Andererseits kann ich mir dann wohl sparen ein Fadenkreuz zu implementieren. :D


Aber wenn ich das richtig in Erinnerung habe, ist die Frage nach der Zukunft von JOGL ja gerade in bezug auf die com.sun Packages (und gerade javafx) unklar...

Die Klassen stammen aus der Zeit als die JoGL Macher noch bei Sun gearbeitet haben und wurden dann aber als Teil von JoGL unter der BSD Lizenz veröffentlicht. Sun hat dann wohl von JoGL einen internen Fork angelegt und die JoGL Macher gekündigt. Die Frage ist nun ob sich jemand berufen fühlt die Klassen weiter zu warten, bzw. fehlende Features einzubauen.


Gruß,
Fancy
 

Marco13

Top Contributor
Als Fingerübung schreibe ich derzeit an einem etwas größeren GL3.2 Programm, darin Kapsel ich alle JoGL Klassen in eigene Klassen, um innerhalb des Projektes keine Verweise auf die JoGL Klassen zu haben. Darin sieht "mein GLWindow" derzeit etwa so aus:
[...]
Das ist zwar nicht immer schön, läuft aber zumindest im Ergebnis geschmeidig.

Ja, so in etwa dachte ich das auch... und wenn man sich noch ein bißchen bemüht, die Verwirrung durch geeignete Benennung der Klassen zu minimieren (ohne IDE ist es schwer, nachzuvollziehen, WO da WELCHER KeyListener denn welcher KeyListener ist ;)) könnte das ja sogar ziemlich "transparent" für den Benutzer sein - D.h. man kann dann das GLWindow fast wie eine normale Swing/AWT-Component verwenden.... fast...

(BTW: Solche Sachen könnten eigentlich auch in eine nächste JOGL-Release mit einfließen :meld: ;) )

Wenn ich Events an den normalen awt EDT weiterleiten würde, hätte ich etwas Bauchscherzen ob das nicht evtl. zu Mircorucklern führen würde. (Um das genau sagen zu können fehlt mir aber schlicht die Kenntnis über den inneren Aufbau des normalen EDT)

Hmjaa... "fast" ... weil ein Problem sein könnte, dass bei einem eigenen Thread Swings "Single Thread Rule" verletzt wird. Wenn man sich vorstellt, dass eine Mausbewegung auf dem GLWindow ... z.B. .. einen JSlider im Swing-Teil des GUIs updaten soll, dann dürfen die MouseEvents nicht von einem anderen Thread als dem echten EDT kommen... Da könnte man jetzt vermutlich ziemlich viel rum-engineeren, so dass man ggf. sogar frei wählen kann, welchen EDT man verwenden will (den eigenen oder den von Swing/AWT)... :reflect: ... aber dazu bräuchte man das "big picture", was das Ding am Ende alles können soll...


Blöde ist aber z.B. das setCursor nicht existiert. Bei ner FPS Steuerung ist das wenig prickelnd den Cursor zu sehen. Andererseits kann ich mir dann wohl sparen ein Fadenkreuz zu implementieren. :D
Dieses komplett native Window ist für mich halt was ganz neues... gäbe es da überhaupt eine andere Möglichkeit als eine DLL mit JNI, die die "Fenstermanagerspezifischen" Funktionen für sowas anbietet? ???:L


Die Klassen stammen aus der Zeit als die JoGL Macher noch bei Sun gearbeitet haben und wurden dann aber als Teil von JoGL unter der BSD Lizenz veröffentlicht. Sun hat dann wohl von JoGL einen internen Fork angelegt und die JoGL Macher gekündigt. Die Frage ist nun ob sich jemand berufen fühlt die Klassen weiter zu warten, bzw. fehlende Features einzubauen.

Einige wenige fühlen sich ja berufen ... aber bisher noch zu wenige, die zu wenig "aktiv" sind - wofür man aber bei der unklaren Gesamtsituation kaum jemandem einen Vorwurf machen kann...
 
G

Guest2

Gast
Ja, so in etwa dachte ich das auch... und wenn man sich noch ein bißchen bemüht, die Verwirrung durch geeignete Benennung der Klassen zu minimieren (ohne IDE ist es schwer, nachzuvollziehen, WO da WELCHER KeyListener denn welcher KeyListener ist ;)) könnte das ja sogar ziemlich "transparent" für den Benutzer sein - D.h. man kann dann das GLWindow fast wie eine normale Swing/AWT-Component verwenden.... fast...

Das war auch mein Ziel. ;) (Wobei ein bisschen refactoring wohl in der Tat nicht schaden könnte :D) Mit dem fast könnte ich zur Zeit auch leben, zumindest bis ich das "big picture" genau definieren kann.


(BTW: Solche Sachen könnten eigentlich auch in eine nächste JOGL-Release mit einfließen :meld: ;) )

Also ich hätte bestimmt nichts dagegen. ;) Problematisch sehe ich allerdings das ich nicht weis was mit dem newt Zeug geplant ist. Vielleicht hat das ja auch einen tieferen Sinn warum nicht die awt Klassen verwendet wurden.


Dieses komplett native Window ist für mich halt was ganz neues... gäbe es da überhaupt eine andere Möglichkeit als eine DLL mit JNI, die die "Fenstermanagerspezifischen" Funktionen für sowas anbietet? ???:L

Imho, nein. Ich hab mir inzwischen mal die JoGL sourcen dazu angesehen. Und ich vermute mit etwas Aufwand könnte man das direkt in das GLWindow (bzw. Window) reinpatchen. Für Windows (WindowsWindow.c) und Linux (X11Window.c, KDWindow.c) würde ich das evtl. sogar hinkriegen, aber was ist mit den anderen (BroadcomEGL.c und IntelGDL.c sagen mir noch nicht mal was konkretes (evtl. Solaris))?

Nuja, wenn ich mal Zeit hab, werd ich wohl noch mal en Blick drauf werfen ;).

Gruß,
Fancy
 

Marco13

Top Contributor
Das war auch mein Ziel. ;) (Wobei ein bisschen refactoring wohl in der Tat nicht schaden könnte :D) Mit dem fast könnte ich zur Zeit auch leben, zumindest bis ich das "big picture" genau definieren kann.
...
Also ich hätte bestimmt nichts dagegen. ;) Problematisch sehe ich allerdings das ich nicht weis was mit dem newt Zeug geplant ist. Vielleicht hat das ja auch einen tieferen Sinn warum nicht die awt Klassen verwendet wurden.

Hm - man könnte spekulieren ob das mit dem Versuch zu tun hat, "Unabhängigkeit" zu erreichen, oder deutlich zu machen, dass man da "in einer anderen Welt" ist (und z.B. bestimmte Thread-Regeln dort nicht mehr gelten), oder man mögliche zukünftige Unterschiede antizipiert hat ... aber dass ist alles nur geraten ;)



Imho, nein. Ich hab mir inzwischen mal die JoGL sourcen dazu angesehen. Und ich vermute mit etwas Aufwand könnte man das direkt in das GLWindow (bzw. Window) reinpatchen. Für Windows (WindowsWindow.c) und Linux (X11Window.c, KDWindow.c) würde ich das evtl. sogar hinkriegen, aber was ist mit den anderen (BroadcomEGL.c und IntelGDL.c sagen mir noch nicht mal was konkretes (evtl. Solaris))?

Nuja, wenn ich mal Zeit hab, werd ich wohl noch mal en Blick drauf werfen ;).

Ja, da hört's bei mir halt noch viel schneller auf... Wobei... wenn es nur um solche "Kleinigkeiten" wie einen ausgeblendeten Cursor geht, könnte man damit wohl erstmal leben....


Aber mal was ganz anderes: Gibt es... irgendwelche... "Best Practices" für Picking mit JOGL/GL3.2? Im Idealfall würde man die ganzen Geometriedaten ja ab einem bestimmten Punkt (und bis zum ersten Auftreten der Notwendigkeit, wegen eines Resize- oder Contextwechsels alles neu zu initialisieren ;) ) NUR noch in einem VBO halten. Wenn man jetzt mit der Maus klicken und rausfinden will, welches Dreieck man getroffen hat ... muss man eigentlich die Daten "mal kurz" nach Java rübermappen, um den Schnitt Sichtstrahl-Dreieck zu berechnen?! :autsch: Spätestens wenn die Frage auftaucht, wo man in diesem Moment das passende GL-Objekt herbekommt, oder was man macht, wenn ständig während einer Mausbewegung Picking durchgeführt werden soll, wird das doch extremst frickelig-murksig!? ???:L
 

Marco13

Top Contributor
Das löst nicht das Problem, das ich meinte: Ich will nicht nur rausfinden (können), welches Objekt ich angeklickt habe, sondern auch welches Dreieck dieses Objektes, und die Baryzentrischen Koordinaten des Klickpunktes in dem Dreieck... (und ggf. dann noch weitere, Objektspezifische Informationen des Objektes an dieser Stelle berechnen können - etwa die Normale oder Texturkoordinaten genau an diesem Punkt). Wie gesagt: Bei EINEM Klick könnte man da den Buffer mappen und irgendwas basteln (mit welchem GL-Objekt auch immer....) - aber bei MouseDrags müßte man ja 50x pro Sekunde die Buffer mappen, und ... irgendwelche Datenstrukturen (Octree o.a.), die das Picking beschleunigen, könnte man damit auch nicht vernünftig aufbauen.... :bahnhof:
 
G

Guest2

Gast
Im Idealfall würde man die ganzen Geometriedaten ja ab einem bestimmten Punkt (und bis zum ersten Auftreten der Notwendigkeit, wegen eines Resize- oder Contextwechsels alles neu zu initialisieren ;) ) NUR noch in einem VBO halten.

Ein VBO ist schon mal nicht schlecht, aber zwei könnten noch besser sein ;) (genauer 1 + n, bei n Objekten). Die beste (und schnellste) Möglichkeit die ich bisher gefunden habe, um alle Geometriedaten auf der Grafikkarte vorzuhalten, ist ein VBO (Typ GL_ARRAY_BUFFER) mit allen Daten aller Vertices (also x, y, z, nx, ny, nz, s, t, ... (jedoch keine doppelten Einträge)) anzulegen. Und zusätzlich für jedes darzustellende Objekt ein weiteres VBO (Typ GL_ELEMENT_ARRAY_BUFFER) in dem nur die Indices der Vertices stehen. Gezeichnet wird das dann mit glDrawElements (nachdem beide VBOs gebunden wurden).

Das spart zum einem einfach Speicherplatz (insbesondere bei "glatten" Objekten wiederholen sich die Vertexdaten sonst regelmäßig), zum anderen kann man die VBOs der Indices beliebig optimieren (z.B. um den Cache der GPU auszunutzen oder die Dreiecke in Dreiecksstripes umzuwandeln).

Zusätzlich kann man dann auch das gemeinsame VBO der Verticies mit jeweils einem VBO der Indices in ein VAO packen um den overhead beim Aufruf zu minimieren.


Wenn man jetzt mit der Maus klicken und rausfinden will, welches Dreieck man getroffen hat ...

Also wenn Du wirklich wissen willst, welches Dreieck Du getroffen hast (und nicht nur welches Objekt), dann schreit das nach dem Geometrieshader ;). Ich würde dazu einfach das / die VBO(s) normal per glDrawElements an die GPU schicken und im Vertexshader lediglich mv * v rechnen. Im Geometrieshader dann den Schnittpunkt Strahl / Dreieck berechnen und die relevanten Ergebnisse per TransformFeedback als Buffer wieder rausschreiben.

Das lässt sich dann auch beliebig auf das anpassen was man braucht, z.B. kann man auch ausgeben wo genau der Strahl das Dreieck getroffen hat. Oder man baut die Ausgabe des Geometrieshaders so, das diese im nächsten Frame / Pass wieder als VBO Eingabe fungiert.

Man kann das auch noch ziemlich beschleunigen indem man den "hinteren" Teil der Grafikkarte ausschaltet (glEnable(GL_RASTERIZER_DISCARD)).

Ob das allerdings "Best Practices" ist kann ich Dir leider nicht sagen, aber es ist das beste was mir einfällt. :D

Gruß,
Fancy
 

Marco13

Top Contributor
Ein VBO ist schon mal nicht schlecht, aber zwei könnten noch besser sein ;) (genauer 1 + n, bei n Objekten). Die beste (und schnellste) Möglichkeit die ich bisher gefunden habe, um alle Geometriedaten auf der Grafikkarte vorzuhalten, ist ein VBO (Typ GL_ARRAY_BUFFER) mit allen Daten aller Vertices (also x, y, z, nx, ny, nz, s, t, ... (jedoch keine doppelten Einträge)) anzulegen. Und zusätzlich für jedes darzustellende Objekt ein weiteres VBO (Typ GL_ELEMENT_ARRAY_BUFFER) in dem nur die Indices der Vertices stehen. Gezeichnet wird das dann mit glDrawElements (nachdem beide VBOs gebunden wurden).

Das spart zum einem einfach Speicherplatz (insbesondere bei "glatten" Objekten wiederholen sich die Vertexdaten sonst regelmäßig), zum anderen kann man die VBOs der Indices beliebig optimieren (z.B. um den Cache der GPU auszunutzen oder die Dreiecke in Dreiecksstripes umzuwandeln).

Zusätzlich kann man dann auch das gemeinsame VBO der Verticies mit jeweils einem VBO der Indices in ein VAO packen um den overhead beim Aufruf zu minimieren.

Das klingt erstmal komisch. Vielleicht ist das für einen konstruierten Testfall das schnellste, aber doch nicht wirklich praktikabel? Wenn man ein Objekt 'x' hat, hat man ein VBO 'vx' mit allen Vertexdaten, und ein VBO 'ix' mit den Indices. Und jetzt kommt ein weiteres Objekt 'y' dazu. Soll man dann 'vx' löschen, und ein neues VBO 'vxy' anlegen, dass die Daten von x und y enthält? Was man dann machen muss, wenn man aus dem VBO für 10 Objekte die Daten für das 3. Objekt rauslöschen soll, kann ich mir kaum vorstellen - erstens weil dann ja ggf. Indices angepasst werden müssen (wenn man das nicht irgendwie mit Offsets zurechttricksen kann), und nicht zuletzt auch weil es ja sein kann, dass die Objekte "strukturell unterschiedlich" sind (einmal mit Texturkoordinaten, einmal mit Vertex Colors...).... ???:L Also, ich würde da eher versuchen, in einem "Objekt" genau das zusammenzufassen, was zusammen gehört - also eher die "2n VBOs für n Objekte"-Schiene gehen... Wobei selbst dort der Punkt, dass der "gleiche" Vertex zwei mal mit unterschiedlichen Texturkoordinaten (!) im Objekt vorkommt zu ziemlichem Rumgefrickel führen kann, wenn man ihn nicht von vornherein berücksichtigt...




Also wenn Du wirklich wissen willst, welches Dreieck Du getroffen hast (und nicht nur welches Objekt), dann schreit das nach dem Geometrieshader ;). Ich würde dazu einfach das / die VBO(s) normal per glDrawElements an die GPU schicken und im Vertexshader lediglich mv * v rechnen. Im Geometrieshader dann den Schnittpunkt Strahl / Dreieck berechnen und die relevanten Ergebnisse per TransformFeedback als Buffer wieder rausschreiben.

Das lässt sich dann auch beliebig auf das anpassen was man braucht, z.B. kann man auch ausgeben wo genau der Strahl das Dreieck getroffen hat. Oder man baut die Ausgabe des Geometrieshaders so, das diese im nächsten Frame / Pass wieder als VBO Eingabe fungiert.

Man kann das auch noch ziemlich beschleunigen indem man den "hinteren" Teil der Grafikkarte ausschaltet (glEnable(GL_RASTERIZER_DISCARD)).

Ob das allerdings "Best Practices" ist kann ich Dir leider nicht sagen, aber es ist das beste was mir einfällt. :D

OK... Ohje :eek: Einen Geometrieshader habe ich bisher noch GAR nicht verwendet... und den jetzt extra für sowas einzuführen klingt aufwändig. Einerseits bietet das sicher interessante Möglichkeiten, andererseits denke ich, dass der Weg von dem Punkt, dass man einen MouseEvent abgefangen hat, bis zu dem Punkt, dass man ausgibt: "Das war Dreieck 42" damit ziemlich weit wäre, und durch viele Interna der Grafikkarte führen würde... Vielleicht liegt das nicht zuletzt daran, dass ich kaum mit GL3.2 klarkomme, aber eben NOCH weniger mit GLSL (was ich vorher überhaupt noch nicht verwendet hatte, und wo ich bisher nur zwo Lighthouse-Tutorials "kopiert und angepasst" :)oops:) habe). Wie auch immer... es scheint als würde der Berg an Arbeit, die zu erledigen ist, größer, je mehr man arbeitet... :rtfm:
 
G

Guest2

Gast
Wenn man ein Objekt 'x' hat, hat man ein VBO 'vx' mit allen Vertexdaten, und ein VBO 'ix' mit den Indices. Und jetzt kommt ein weiteres Objekt 'y' dazu. Soll man dann 'vx' löschen, und ein neues VBO 'vxy' anlegen, dass die Daten von x und y enthält? Was man dann machen muss, wenn man aus dem VBO für 10 Objekte die Daten für das 3. Objekt rauslöschen soll, kann ich mir kaum vorstellen...

Nein, dann währe wohl in der Tat der 2n Ansatz der bessere! ;) Ich sehe das vermutlich aus einem zu eingeschränkten Blickfeld, da ich versuche alle dynamischen Daten direkt auf der Grafikkarte zu instanziieren und zu transformieren. Dann bleiben die Daten der Vertices immer gleich, lediglich der Aufruf der Indices und die Parameter der Shader variieren. Das muss/kann aber natürlich nicht immer so gehen.


...und nicht zuletzt auch weil es ja sein kann, dass die Objekte "strukturell unterschiedlich" sind (einmal mit Texturkoordinaten, einmal mit Vertex Colors...).... ???:L Also, ich würde da eher versuchen, in einem "Objekt" genau das zusammenzufassen, was zusammen gehört - also eher die "2n VBOs für n Objekte"-Schiene gehen...

Ja, wenn die Datensätze der Vertices tatsächlich eine unterschiedliche Struktur aufweisen, sollten sie vermutlich sogar in unterschiedliche VBOs (sonnst müsste man eine menge unnütze Daten im VBO mit rumschleppen), also 2n bzw. irgendwas zwischen 1+n und 2n. ;)

Wichtig erscheint mir halt nur, dem Treiber die Möglichkeit zu geben Sequenzen wie (1,2,3),(1,3,4),... zu cachen. (Bei indizierten VBOs werden die Ergebnisse der Vertexshader zwischengespeichert, bei nicht indizierten VBOs hingegen scheinbar nicht (immer?))


Wobei selbst dort der Punkt, dass der "gleiche" Vertex zwei mal mit unterschiedlichen Texturkoordinaten (!) im Objekt vorkommt zu ziemlichem Rumgefrickel führen kann, wenn man ihn nicht von vornherein berücksichtigt...

Da mache ich es mir auch einfach, da meine komplette Szene aus einem OBJ File kommt. Ich nutze einfach eine Map die z.B. "1/16/7 x/x/x y/y/y" aus dem f Tag des OBJ Files auf einen Index abbildet. Also bereits vorhandenen Index, wenn "1/16/7" bereits in der Map, sonnt Index i++ und v, vn, vt ins VBO der Vertices (bzw. an der Stelle noch in eine ArrayList).


OK... Ohje :eek: Einen Geometrieshader habe ich bisher noch GAR nicht verwendet... und den jetzt extra für sowas einzuführen klingt aufwändig.

So aufwändig ist der gar nicht (auch wenn er sich beim linken etwas anders verhält als die anderen Shader, da noch 3 extra Parameter benötigt werden). Er ist es aber imho wert, da nur der Geometrieshader gleichzeitigen Zugriff auf alle Vertices eines Primitives hat. Außerdem kann er zur Laufzeit Primitive hinzufügen oder ignorieren, daraus ergeben viele Möglichkeiten.

Z.B. angenommen Du willst bei Deinem obigen Dreieck mit dem Mauszeiger auf eine Stelle zeigen und an genau dieser Stelle einen Pfeil in Richtung der Normalen darstellen. Dann kann der Geometrieshader an dem Schnittpunkt des Strahls aus dem Mauszeiger und dem Dreieck neue Primitive einfügen und den Pfeil "on the fly", ohne Zutun der CPU, darstellen.


...bis zu dem Punkt, dass man ausgibt: "Das war Dreieck 42"

Eigentlich sollte das mit Transform Feedback relativ simpel sein, allerdings krieg ich das Transform Feedback derzeit selber nicht zum Laufen, ich vermute da inzwischen leider einen Bug in JoGL. (Der alte Weg über Texturen geht noch, aber ein VBO als TF wäre natürlich viel schicker ;) )
(Muss das, bei Gelegenheit, mal in C probieren, um zu verifizieren ob es an mir, an JoGL oder der Grafikkarte liegt.)


...dass ich kaum mit GL3.2 klarkomme, aber eben NOCH weniger mit GLSL...

Auch wenn es formal wie zwei unterschiedliche Dinge spezifiziert zu sein scheint, würde ich schon sagen das GLSL "DIE" Kernkomponente von GL3.2 ist. Und ich würde auch vermuten, dass wenn Du mal genug Shader geschrieben hast, Du irgendwann das Gefühl bekommst, das Shader kein Ballast (im vergleich zu GL2.1) sind, sondern eben vieles einfach einfacher machen. ;)

(Leider braucht es, um die Möglichkeiten der Shader wirklich auszunutzen, vermutlich wirklich die oben mal erwähnten 1000+ GL3.2 Programme. :()


Wie auch immer... es scheint als würde der Berg an Arbeit, die zu erledigen ist, größer, je mehr man arbeitet... :rtfm:

Ich befürchte es auch. ;)


Gruß,
Fancy
 

Marco13

Top Contributor
Ja, wenn die Datensätze der Vertices tatsächlich eine unterschiedliche Struktur aufweisen, sollten sie vermutlich sogar in unterschiedliche VBOs (sonnst müsste man eine menge unnütze Daten im VBO mit rumschleppen), also 2n bzw. irgendwas zwischen 1+n und 2n. ;)

Wichtig erscheint mir halt nur, dem Treiber die Möglichkeit zu geben Sequenzen wie (1,2,3),(1,3,4),... zu cachen. (Bei indizierten VBOs werden die Ergebnisse der Vertexshader zwischengespeichert, bei nicht indizierten VBOs hingegen scheinbar nicht (immer?))

So gesehen wäre es vermutlich ja das günstigste, komplett auf die Indices zu verzichten (korrigiere mich, wenn ich mit der Vermutung, dass das durch irgendeinen passenden Aufruf von glDraw* geht, falsch liege)... Aber in diesem Fall wäre mir bequeme Verwendbarkeit und Flexibilität wichtiger, als 45 statt 42 FPS...




Da mache ich es mir auch einfach, da meine komplette Szene aus einem OBJ File kommt. Ich nutze einfach eine Map die z.B. "1/16/7 x/x/x y/y/y" aus dem f Tag des OBJ Files auf einen Index abbildet. Also bereits vorhandenen Index, wenn "1/16/7" bereits in der Map, sonnt Index i++ und v, vn, vt ins VBO der Vertices (bzw. an der Stelle noch in eine ArrayList).


Hmja, man hat da so grob die Alternativen selbst die Indizierung zu ändern und zu speichern (und eben für Vertices und Texturkoordinaten unterschiedliche Indizierungen zu verwenden) oder die Vertices zu verdoppeln - was dann aber bei Normalenberechnungen raushauen kann... (und sag' jetzt nicht, dass man die doch im Geometrieshader machen kann, und das da ja dann total einfach ist :pueh: ;) )




So aufwändig ist der gar nicht (auch wenn er sich beim linken etwas anders verhält als die anderen Shader, da noch 3 extra Parameter benötigt werden). Er ist es aber imho wert, da nur der Geometrieshader gleichzeitigen Zugriff auf alle Vertices eines Primitives hat. Außerdem kann er zur Laufzeit Primitive hinzufügen oder ignorieren, daraus ergeben viele Möglichkeiten.

Z.B. angenommen Du willst bei Deinem obigen Dreieck mit dem Mauszeiger auf eine Stelle zeigen und an genau dieser Stelle einen Pfeil in Richtung der Normalen darstellen. Dann kann der Geometrieshader an dem Schnittpunkt des Strahls aus dem Mauszeiger und dem Dreieck neue Primitive einfügen und den Pfeil "on the fly", ohne Zutun der CPU, darstellen.

Eigentlich sollte das mit Transform Feedback relativ simpel sein, allerdings krieg ich das Transform Feedback derzeit selber nicht zum Laufen, ich vermute da inzwischen leider einen Bug in JoGL. (Der alte Weg über Texturen geht noch, aber ein VBO als TF wäre natürlich viel schicker ;) )
(Muss das, bei Gelegenheit, mal in C probieren, um zu verifizieren ob es an mir, an JoGL oder der Grafikkarte liegt.)

Ja, um z.B. Details hinzuzufügen, weiter zu Tesselieren oder so kann der ja sicher praktisch sein, aber spätestens, wenn man den Renderer als "Blackbox" ansehen will, aus dem man implementierungsagnostisch Informationen über die Klickposition rausholen will, wird das dann vermutlich doch aufwändiger (zumindest für mich...). Ehrlich gesagt sehe ich keinen wirklichen systematischen Vorteil, außer, dass man die Buffer auf der Grafikkarte (und nur da) halten kann. Aber vermutlich gibt es, wenn man das erreichen will, nicht so viele Alternativen... Ständiges umkopieren und für die Klickabfrage irgendwohin mappen kann's ja nicht sein :bahnhof:





Auch wenn es formal wie zwei unterschiedliche Dinge spezifiziert zu sein scheint, würde ich schon sagen das GLSL "DIE" Kernkomponente von GL3.2 ist. Und ich würde auch vermuten, dass wenn Du mal genug Shader geschrieben hast, Du irgendwann das Gefühl bekommst, das Shader kein Ballast (im vergleich zu GL2.1) sind, sondern eben vieles einfach einfacher machen. ;)

(Leider braucht es, um die Möglichkeiten der Shader wirklich auszunutzen, vermutlich wirklich die oben mal erwähnten 1000+ GL3.2 Programme. :()

Dass die Möglichkeiten, die mit Shadern theoretisch geboten werden, beeindruckend sind, erkennt man, wenn man sich mal (ganz praktisch) die Samples auf den NVIDIA-Seiten (und ähnlichen) ansieht. Aber es ist auch klar, dass sich da viele schlaue Leute lange hingesetzt haben, um diese hübschen Demos zu erstellen - und dass ein gewaltiger Unterschied ist, zwischen einer Demo, wo man mal den Teapot oder den Stanford Bunny mit einem netten Effekt rendert, und einem "universellen Werkzeugkasten", der es (*rumspinn*) erlauben sollte, mal kurz mit wenigen, einfachen Zeilen Code eine Szene mit 5 Objekten und 8 unterschiedlichen Shadern zu rendern, und dann 3 Objekte wegzunehmen und 4 neue mit 8 neuen Shadern hinzuzufügen.... :rolleyes:
 
G

Guest2

Gast
So gesehen wäre es vermutlich ja das günstigste, komplett auf die Indices zu verzichten (korrigiere mich, wenn ich mit der Vermutung, dass das durch irgendeinen passenden Aufruf von glDraw* geht, falsch liege)...

Ja natürlich, glDrawArrays ist für die Verwendung ohne Indices und glDrawElements entsprechend mit Indices.

Bei glDrawArrays muss gelten: [c]VBO = (v_11, v_12, v_13, v_21, v_22, v_23, ...)[/c]
mit z.B.: [c]v_ij = (x_ij, y_ij, z_ij, nx_ij, ny_ij, nz_ij, s_ij, t_ij)[/c]

Bei glDrawElements entsprechend: [c]VBO = (v_1, v_2, v_3, v_4, ...)[/c]
mit z.B.: [c]v_i = (x_i, y_i, z_i, nx_i, ny_i, nz_i, s_i, t_i)[/c]
und z.B.: [c]IBO = (1, 2, 3, 1, 3, 4, ...)[/c]


Aber in diesem Fall wäre mir bequeme Verwendbarkeit und Flexibilität wichtiger, als 45 statt 42 FPS...

Wie viel FPS das letztendlich ausmacht, lässt sich leider nicht pauschal beantworten, da es wohl im wesentlichen von dem Komplexität der Shader abhängt. Aber mal eine Abschätzung über die Speichergröße:

Angenommen das Objekt ist gleichmäßig trianguliert (d.h. jeder Vertex wird im Schnitt von 3 Dreiecken genutzt), ein Vertexdatensatz besteht aus x, y, z, nx, ny, nz, s, t (d.h. 8 * float = 32 byte) und der Inputtype des Shader ist GL_TRIANGLES.

Dann gilt im nicht indizierten Fall pro "real Eckpunkt": 3 * 32 byte = 96 byte
im indizierten Fall: 1 * 32 byte + 3 * int = 44 byte


Angenommen der Inputtype des Shader ist jetzt nicht mehr GL_TRIANGLES sondern GL_TRIANGLES_ADJACENCY, weil der Shader Informationen über die Nachbardreiecke benötigt. Dann muss pro Vertex ein extra Vertex übertragen werden, aus denen dann die 3 Nachbardreiecke eines Dreiecks aufgespannt werden können.

Dann gilt im nicht indizierten Fall pro "real Eckpunkt": 4 * 32 byte = 128 byte
im indizierten Fall: 1 * 32 byte + 4 * int = 48 byte


Weiter angenommen das selbe Objekt soll jetzt in zwei Renderläufen von zwei verschiedenen Shadern dargestellt werden. Einer hat den Inputtype GL_TRIANGLES und der andere den Inputtype GL_TRIANGLES_ADJACENCY. Im nicht indizierten VBO brauchst Du dann zwei komplette VBOs im indizierten lediglich ein weiteres IBO.

Dann gilt im nicht indizierten Fall pro "real Eckpunkt": (3 * 32 byte ) + (4 * 32 byte) = 224 byte
im indizierten Fall: 1 * 32 byte + 4 * int + 3 * int= 60 byte


Macht ein Größenverhältnis von 1:3.6.

Das klingt jetzt vermutlich ziemlich konstruiert, ist es aber leider nicht, da es einer einfachen Szene mit hartware shadow volumes entspricht (genau da wird z.B. sowohl GL_TRIANGLES als auch GL_TRIANGLES_ADJACENCY pro Objekt benötigt).

Ich gehe zwar davon aus das die FPS nicht auf 1/3 abstürzen würde, aber ich befürchte das es auch deutlich mehr als die 3 FPS sein werden, denn immerhin werden 3 mal so viele Daten durch die GPU gedrückt.


was dann aber bei Normalenberechnungen raushauen kann... (und sag' jetzt nicht, dass man die doch im Geometrieshader machen kann, und das da ja dann total einfach ist :pueh: ;) )

Man könnte es im Geometrieshader machen und es wäre auch ganz einfach :D.

Aber es wäre vermutlich auch nicht sonderlich sinnvoll, da der Geometrieshader nicht von sich aus wissen kann ob eine Kante "hart" oder "glatt" sein soll, sprich ob die Normale über die Kante hinweg interpoliert werden soll. Dazu müsste man ein zusätzliches Vertexattribut übertragen und das könnte dann wieder in Fummelei ausarten. Außerdem werden die Normalen in den meisten Szenen wohl statisch sein und dann macht es vermutlich schon sinn die vorher einmal auf der CPU auszurechnen.


Ehrlich gesagt sehe ich keinen wirklichen systematischen Vorteil, außer, dass man die Buffer auf der Grafikkarte (und nur da) halten kann. Aber vermutlich gibt es, wenn man das erreichen will, nicht so viele Alternativen... Ständiges umkopieren und für die Klickabfrage irgendwohin mappen kann's ja nicht sein :bahnhof:

Ich sehe den Vorteil darin, das es mit dem Geometrieshader eben genau ein "Teil" gibt das dazu gemacht wurde alle "einfachen" Rechenoperationen auf genau jedes darzustellende Dreieck auszuführen. Und um schnell die Baryzentrischen Koordinaten auszurechen und zu prüfen ob diese zwischen 0 und 1 liegen bietet sich das förmlich an.

(Ich würde, um das zu untermauern ja jetzt gerne ein kskb dazu posten, aber ich befürchte in glTransformFeedbackVaryings() ist bei JoGL ein Fehler (der 3 Parameter wir imho nicht korrekt übergeben) und ohne das würde es wieder nach "hack" aussehen.)


...wenn man den Renderer als "Blackbox" ansehen will...

Ja, genau das wird dann schwierig, denn wenn man die Shader wirklich nutzt, dreht es sich nicht mehr nur ums reine darstellen, sondern eben auch ums berechnen / umrechnen der Daten.


Ständiges umkopieren und für die Klickabfrage irgendwohin mappen kann's ja nicht sein :bahnhof:

Imho, nein. Ich würde es entweder nur auf der CPU oder nur auf der GPU machen. Der Versuch große Geometriedaten ständig hin und herzuschieben kann einfach keine gute Lösung werden.


Gruß,
Fancy
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
G [Java Server] Allgemeine Frage zum Thema Networking in Videospielen Spiele- und Multimedia-Programmierung 15
pcfreak9000 "Allgemeine" Performance verbessern (LWJGL 2) Spiele- und Multimedia-Programmierung 2
0x7F800000 allgemeine frage zu Java 3D Spiele- und Multimedia-Programmierung 12
C Fragen zu HashMaps Spiele- und Multimedia-Programmierung 22
B Fragen zu "Physics-Body-Editor"? Spiele- und Multimedia-Programmierung 0
J Fragen zur Gui-Aktualisierung Spiele- und Multimedia-Programmierung 2
A Langtons Ameise - Fragen zur Umsetzung Spiele- und Multimedia-Programmierung 1
D Ein paar Fragen... Spiele- und Multimedia-Programmierung 5
H LWJGL: Fragen zum Verständnis Spiele- und Multimedia-Programmierung 7
Helgon Fragen zur Umsetzung Spiele- und Multimedia-Programmierung 17
A Klickgame ala "Harveys neue Augen" oder "Edna bricht aus" in Java programmieren... Fragen zu Kleinig Spiele- und Multimedia-Programmierung 8
Samake03 [Game]"Plumbo - Lost in Depth" Preview und Fragen Spiele- und Multimedia-Programmierung 18
G Minecraft Minecraft Fragen Spiele- und Multimedia-Programmierung 1
A Fragen zu MMO Spiele- und Multimedia-Programmierung 6
N Ein paar fragen zu JOGL Spiele- und Multimedia-Programmierung 4
M Grundsätzliche Java3D Fragen Spiele- und Multimedia-Programmierung 2
D 3 JMF Fragen Spiele- und Multimedia-Programmierung 8
M Fragen wegen Spieleprogrammierung Spiele- und Multimedia-Programmierung 17
M Fragen zu meinem Pong-Clone Spiele- und Multimedia-Programmierung 6
S glTexSubImage2D()-Fragen(Zerstörbares Terrain, OpenGL) Spiele- und Multimedia-Programmierung 3
K Game-Tutorial von Quaxli Fragen Spiele- und Multimedia-Programmierung 18
D Zwei Fragen (Exponential Fog und Schein-nach-außen-Effekt) Spiele- und Multimedia-Programmierung 6
H Einstieg erfolgreich ;), nun nur noch paar Fragen^^ Spiele- und Multimedia-Programmierung 13
V Fragen zum PositionPathInterpolator und RotationInterpolator Spiele- und Multimedia-Programmierung 2
N 4 Gewinnt fertig (Kritik, Fragen etc. erwünscht) Spiele- und Multimedia-Programmierung 29
J 3d Programmierung, Fragen: Spiele- und Multimedia-Programmierung 14
T Größeres Spiele Projekt - einige Fragen zur Umsetzung Spiele- und Multimedia-Programmierung 3
D JOGL2 eigene mipmaps laden Spiele- und Multimedia-Programmierung 13
D Jogl2 (Netbeans8) selbstlaufende Applikation erstellen Spiele- und Multimedia-Programmierung 4

Ähnliche Java Themen

Neue Themen


Oben