# [LWJGL] VBOs und deprecated GL15



## Luk10 (1. Dez 2012)

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 
	
	
	
	





```
glGenBuffers
```
 oder 
	
	
	
	





```
glVertexPointer
```
 nicht.
Kann mir jemand erklären was dahinter steckt? 

Ah und mir fällt gerade ein: Braucht man 
	
	
	
	





```
glEnableClientState(GL_VERTEX_ARRAY)
```
 noch?

Danke,
Luk10


----------



## Guest2 (1. Dez 2012)

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 (3. Dez 2012)

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

```
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 
	
	
	
	





```
in
```
s deklariert werden?

Danke nochmal,
-Luk10-


----------



## Guest2 (5. Dez 2012)

Luk10 hat gesagt.:


> 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.




Luk10 hat gesagt.:


> 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!




Luk10 hat gesagt.:


> 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
> 
> 
> 
> ...



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 (6. Dez 2012)

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-


----------



## Guest2 (6. Dez 2012)

Luk10 hat gesagt.:


> 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




Luk10 hat gesagt.:


> 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.



Luk10 hat gesagt.:


> 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 (20. Dez 2012)

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 
	
	
	
	





```
vec4 position
```
 und einen 
	
	
	
	





```
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:


```
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);
```


----------



## Guest2 (21. Dez 2012)

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:


```
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 (21. Dez 2012)

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?


----------



## Guest2 (21. Dez 2012)

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,
> 
> ...



Viele Grüße,
Fancy


----------



## Luk10 (22. Dez 2012)

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-


----------



## Guest2 (22. Dez 2012)

Das normale MSAA wird in LWJGL einfach mit


```
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. 



Luk10 hat gesagt.:


> 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


----------

