[LWJGL] VBOs und deprecated GL15

Luk10

Top Contributor
Hallo,

VBOs sind ja eine der nicht deprecated Rendermethoden im modernen OpenGL. Ich verwende LWJGL als OpenGL wrapper und frage mich schon seit einiger Zeit wieso die Methoden um VBOs in GL15 oder GL11 sind. Diese sind deprecated und in GL30+ finde ich Methoden wie
Code:
glGenBuffers
oder
Code:
glVertexPointer
nicht.
Kann mir jemand erklären was dahinter steckt?

Ah und mir fällt gerade ein: Braucht man
Code:
glEnableClientState(GL_VERTEX_ARRAY)
noch?

Danke,
Luk10
 
G

Guest2

Gast
Moin,

glGenBuffers ist in 1.5 definiert und nicht deprecated. glEnableClientState und glVertexPointer sind in 1.1 definiert, seit 3.1 aber deprecated. Stattdessen wird nun glEnableVertexAttribArray und glVertexAttribPointer verwendet.

In LWJGL befindet sich die Methode immer in der GL-Klasse in dessen OpenGL Version sie definiert wurde. Z.B. glGenBuffers also in GL15. Das OpenGL Deprecation Model wird dabei leider nicht berücksichtigt.

Damit das sauber ist, muss in modernem OpenGL Dein VBO auch noch an ein VAO gehangen werden. Genaugenommen war das auch schon immer so, nur früher gab es ein implizites default VAO, das nun ebenfalls deprecated ist.

Hier ist ein komplettes Beispiel (OpenGL 4.2). Der Sourcecode ist dort verlinkt. Insbesondere VBO, IBO und VAO.

Viele Grüße,
Fancy
 

Luk10

Top Contributor
Vielen Dank für deine Antwort und besonders für die Links zu diesem Beispiel-Code! Sehr aufschlussreich.
Ich habe jedoch einige Fragen dazu.

Wenn das VAO erstellt wird und diese Methode aufgerufen wird
Java:
public final void glInit() {
      handle = glGenVertexArrays();

      glBindVertexArray(handle);

      vbo.glBind();
      ibo.glBind();

      glBindVertexArray(0);
}
werden ja im VBO eine ganze Reihe von Vertex Attributes "enabled". Meine Fragen:

a) Sollte man nach dem render des VBOs (bzw. VAO) nicht nur das VAO "unbinden", sondern auch den VBO, IBO und die ganzen VertexAttributes?
b) Ist diese Implementierung speziell darauf ausgelegt nur ein einziges VBO (VAO) zuerstellen?
c) Wenn VertexAttrib [1;n] für je 1-n Verticies enabled sind, wie muss die Implementierung im VertexShader dazu aussehen? Müssen auch 1-n
Code:
in
s deklariert werden?

Danke nochmal,
-Luk10-
 
G

Guest2

Gast
a) Sollte man nach dem render des VBOs (bzw. VAO) nicht nur das VAO "unbinden", sondern auch den VBO, IBO und die ganzen VertexAttributes?

Du kannst Dir das VAO als reinen Zustandshalter vorstellen. Sobald Du ein anderes VAO bindest, wird der zugehörige Zustand mit umgeschaltet. Dadurch kannst Du Dir z.B. das Umschalten der Attribute sparen. Im OpenGL Wiki gibt es einen Artikel in dem das schön beschrieben ist, leider ist das Wiki gerade offline.


b) Ist diese Implementierung speziell darauf ausgelegt nur ein einziges VBO (VAO) zuerstellen?

Es ist schon etwas her, dass ich dieses Beispiel geschrieben habe, aber auf Anhieb wüsste ich nicht, was gegen mehrere VAOs mit jeweils eigenen VBOs spricht. Was in dieser Implementierung aber nicht geht, sind mehrere VAOs mit unterschiedlichen Attributen, die aber dasselbe VBO nutzen. Eigentlich müssten die Attribute in das VAO und nicht in das VBO, ich denke dann wird auch der Sinn des VAO als Zustandshalter klarer. Ich werde das anpassen, danke für den Hinweis!


c) Wenn VertexAttrib [1;n] für je 1-n Verticies enabled sind, wie muss die Implementierung im VertexShader dazu aussehen? Müssen auch 1-n
Code:
in
s deklariert werden?

Du meinst, wenn im VAO/VBO mehr Vertexattribute deklariert werden, als im Shader genutzt werden? Imho sollte das nichts ausmachen. Eine Ausnahme ist allerdings die location 0, diese sollte aus Kompatibilitätsgründen immer die Vertexkoordinaten enthalten. Näheres steht dazu imho auch im Wiki, aber es ist eben offline...

Viele Grüße,
Fancy
 

Luk10

Top Contributor
Wie viel Performance fressen denn zusätzliche / viele VBOs? Macht es Sinn Verticies mit sehr unterschiedlichen VertexAttributes in ein und den selben VBO zu stecken? (Ich habe < 1000 Verticies und würde sie bis jetzt auf ca. 10 VBOs á +-100 Verticies aufteilen (1 VBO pro geometry). Ich könnte sie aber auch theoretisch in einen einzigen Stecken um mir drawElements() Aufrufe zu sparen.

Außerdem: Ist es verhältnissmäßig viel Aufwand Daten im VBO auszutauschen / zu ersetzten (Buffer-Mapping)?

Ich bin leider fürchterlich unerfahren was das ganze Thema angeht ... deshalb diese Fragen.

Vielen Dank für deine Hilfe!
-Luk10-
 
G

Guest2

Gast
Wie viel Performance fressen denn zusätzliche / viele VBOs? Macht es Sinn Verticies mit sehr unterschiedlichen VertexAttributes in ein und den selben VBO zu stecken? (Ich habe < 1000 Verticies und würde sie bis jetzt auf ca. 10 VBOs á +-100 Verticies aufteilen (1 VBO pro geometry). Ich könnte sie aber auch theoretisch in einen einzigen Stecken um mir drawElements() Aufrufe zu sparen.

Bei 1000 Vertices ist das nicht kritisch, sodass Du bedenkenlos die Variante nehmen kannst, die in Deinem Code "sauberer" ist. Im Allgemeinen wird pro VBO ein Richtwert von etwa 4 MB angegeben, bei "normalen" Attributen also etwa 125k Vertices. Wenn das VBO lange lebt, auch mehr. Das Umschalten zwischen VAOs/VBOs "kostet" ein wenig, sodass weniger VAOs/VBOs schneller sein können.

Dasselbe VBO mit anderen Parametern in einem anderen VAO wieder zu verwenden, könnte nützlich sein, wenn man eine multi pass Renderschleife nutzt. Bei single pass braucht man das aber ihmo nicht.

Juhu, das Wiki ist wieder da: Vertex Specification, Vertex Specification Best Practices


Außerdem: Ist es verhältnissmäßig viel Aufwand Daten im VBO auszutauschen / zu ersetzten (Buffer-Mapping)?

Ja, das kann dazu führen, dass der OpenGL Treiber die GPU mit der CPU synchronisieren muss und das bremst dann beide aus. Es gibt aber Techniken, mit denen das zumindest eingedämmt werden kann: Buffer Object Streaming

Grundsätzlich ist es aber eine gute Idee die VAOs/VBOs unangetastet zu lassen und notwenige Veränderungen im Shader durchzuführen. Aber gerade als Einsteiger kann das manchmal etwas schwierig sein.

Ich bin leider fürchterlich unerfahren was das ganze Thema angeht ... deshalb diese Fragen.

Ist ja nichts schlimmes. Niemand kommt als Allwissender zur Welt. ;)

Viele Grüße,
Fancy
 

Luk10

Top Contributor
Hallo,

ich habe wieder eine Frage. Ich schlage mich gerade mit interleaved VertexAttributes und ich bin mir nicht ganz sicher was falsch ist.

Mein Set-up:
> Ich habe 4 Vertices
> Ich habe pro Vertex einen
Code:
vec4 position
und einen
Code:
vec3 color
.
> Die VertexAttributes sind nach folgendem Schema interleaved: position - color - position - color - ...
> Vertex 0, 1, 2 und 0, 2, 3 sollen je ein Dreieck bilden (Indices sind auch so angegeben)

> GOPVertexAttribute ist (index, size, type, stride, offset, normalized, name)
> Attribute werden über glBindAttribLocation(..., index, name) gebunden.

Es entstehen mit folgendem Code keine compiler oder runtime Errors jedoch wird auch nichts gezeichnet. Shader werden ebenfalls richtig übersetzt und gelinkt. Irgendwas stimmt mit dem interleaved VBO nicht.

Aufgerufen wird drawElements mit size = indices.size() und offset = 0
Vielleicht kann mir jemand weiterhelfen.

Hier der Code dazu:

Java:
		List<Float> vertexValues = new ArrayList<Float>();
		List<Integer> indices = new ArrayList<Integer>();
		List<GOPVertexAttribute> vertexAttributes = new ArrayList<GOPVertexAttribute>();

		// vertex 0
		vertexValues.add(-0.5f);
		vertexValues.add(0.5f);
		vertexValues.add(0f);
		vertexValues.add(1f);

		vertexValues.add(0.5f);
		vertexValues.add(0.5f);
		vertexValues.add(0.5f);

		// vertex 1
		vertexValues.add(0.5f);
		vertexValues.add(0.5f);
		vertexValues.add(0f);
		vertexValues.add(1f);

		vertexValues.add(0.5f);
		vertexValues.add(0.5f);
		vertexValues.add(0.5f);

		// vertex 2
		vertexValues.add(0.5f);
		vertexValues.add(-0.5f);
		vertexValues.add(0f);
		vertexValues.add(1f);

		vertexValues.add(0.5f);
		vertexValues.add(0.5f);
		vertexValues.add(0.5f);

		// vertex 3
		vertexValues.add(-0.5f);
		vertexValues.add(-0.5f);
		vertexValues.add(0f);
		vertexValues.add(1f);

		vertexValues.add(0.5f);
		vertexValues.add(0.5f);
		vertexValues.add(0.5f);

		indices.add(0);
		indices.add(1);
		indices.add(2);

		indices.add(0);
		indices.add(2);
		indices.add(3);

		vertexAttributes.add(new GOPVertexAttribute(0, 4, GOPRenderUtils.TYPE_FLOAT, 0, 1, false, "position"));
		vertexAttributes.add(new GOPVertexAttribute(4, 3, GOPRenderUtils.TYPE_FLOAT, 1, 1, false, "color"));
		GOPVertexArrayObject vao = new GOPVertexArrayObject(GOPRenderUtils.TYPE_TRIANGLES, indices.size(), GOPRenderUtils.MODE_STATIC_DRAW, vertexValues, indices,
				vertexAttributes);
 
G

Guest2

Gast
Moin,

ich bin mir nicht sicher, ob ich das alles richtig nachvollzogen habe, aber das mit den offsets und den strides sieht merkwürdig aus. In glVertexAttribPointer ist das so spezifiziert:

https://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml hat gesagt.:
stride
Specifies the byte offset between consecutive generic vertex attributes. If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.

pointer
Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of the buffer currently bound to the GL_ARRAY_BUFFER target. The initial value is 0.

Deiner Bespreibung nach hätte ich bei Dir folgendes erwartet:

Java:
        vertexAttributes.add(new GOPVertexAttribute(0, 4, GOPRenderUtils.TYPE_FLOAT, (4 + 3) * 4, 0 * 4, false, "position"));
        vertexAttributes.add(new GOPVertexAttribute(1, 3, GOPRenderUtils.TYPE_FLOAT, (4 + 3) * 4, 4 * 4, false, "color"));

Viele Grüße,
Fancy
 

Luk10

Top Contributor
Ah ich habe nicht gesehen wie genau das offset bzw. stride angegeben werden ... schon gar nicht in bytes.

Vielen Dank, wenn ich noch weitere Fragen habe schreib ich sie wieder hier rein.
Luk10

EDIT: Eine kleine Frage noch: Muss ich als Index des zweiten VertexAttributes nicht 4 angeben, da vec4 des ersten 4 (0-3) Plätze belegt?
 
Zuletzt bearbeitet:
G

Guest2

Gast
Könnte man annehmen, ein vec4 ist aber nur eine location "breit":

https://www.opengl.org/registry/doc/GLSLangSpec.4.30.7.pdf hat gesagt.:
If a vertex shader input is any scalar or vector type, it will consume a single location. If a non-vertex shader input is a scalar or vector type other than dvec3 or dvec4, it will consume a single location, while types dvec3 or dvec4 will consume two consecutive locations. Inputs of type double and dvec2 will consume only a single location, in all stages.

If the declared input is an array of size n and each element takes m locations, it will be assigned m * n consecutive locations starting with the location specified. For example,

[c]layout(location = 6) in vec4 colors[3];[/c]

will establish that the shader input colors is assigned to vector location numbers 6, 7, and 8.

If the declared input is an n x m single- or double-precision matrix, it will be assigned multiple locations starting with the location specified. The number of locations assigned for each matrix will be the same as for an n-element array of m-component vectors. For example,

[c]layout(location = 9) in mat4 transforms[2];[/c]

will establish that shader input transformsis assigned to vector locations 9-16, with transforms[0] being assigned to locations 9-12 and transforms[1] being assigned to locations 13-16.

If the declared input is a structure, its members will be assigned consecutive locations in the order of declaration, with the first member assigned the location specified for the structure. The number of locations consumed by a structure member is determined by applying the rules above recursively as though the structure member were declared as an input variable of the same type. For example,

Code:
layout(location = 3) struct S {
vec3 a;
mat2 b;
vec4 c[2];
} s;

will assign location 3 to s.a, locations 4 and 5 to the two column vectors of s.b,and locations 6 and 7 to s.c.

Viele Grüße,
Fancy
 

Luk10

Top Contributor
Okay, dankeschön!

Noch eine andere eher lwjgl-Spezifische Frage:
Ich möchte gerne MSAA nutzen (da GL_POLYGON_SMOOTH ja veraltet ist um meine Polygon mit AA zu zeichnen. Kann man mit lwjgl MSAA "to window" nutzen oder nur "to fbo"? Ich habe eine Weile gesucht aber ich finde keine passenden Quellen im Internet. Auch zu fbos und lwjgl finde ich nur das ziemlich veraltete wiki-Tutorial. Wäre super wenn mir da jemand mit MSAA helfen könnte.

Noch keine kleine Frage: Kann man AA auf die Kanten von Polygons im fragment Shader anwenden?

Danke,
-Luk0-
 
G

Guest2

Gast
Das normale MSAA wird in LWJGL einfach mit

Java:
        final DisplayMode displayMode = new DisplayMode(WIDTH, HEIGHT);
        final PixelFormat pixelFormat = new PixelFormat().withSamples(4);
        final ContextAttribs contextAttribs = new ContextAttribs(GL_MAJOR_VERSION, GL_MINOR_VERSION).withProfileCore(true).withForwardCompatible(true);

        Display.setDisplayMode(displayMode);
        Display.create(pixelFormat, contextAttribs);
        Display.setTitle(TITLE);

aktiviert.

Noch keine kleine Frage: Kann man AA auf die Kanten von Polygons im fragment Shader anwenden?

Hm, für normales MSAA braucht man das ja nicht (zumindest beim Forward Shading). Bei Post-Process Effekten wie MLAA oder FXAA sieht das imho etwas anderes aus (im Zweifel komplizierter ;)).

Viele Grüße,
Fancy
 

Ähnliche Java Themen

Neue Themen


Oben