Seite 1 von 1

[OGL] Vertex Array Objects

Verfasst: 02.02.2013, 17:22
von Jonathan
Moin,

bevor ich versuche, Instancing zu implementieren, wollte ich mir zunächst nocheinaml angucken, wie das jetzt unter OpenGL mit den VertexBuffern in den neueren Versionen aussieht. Und siehe da, da gibt es tatsächlich etwas, was ich bisher nie benutzt habe, dessen Sinn ich aber auch noch nicht so ganz verstehe. Meine Lektüre:

http://www.opengl.org/wiki/Vertex_Specification

Gut, da steht jetzt, dass VertexArrayObjects auf irgendeine Art VertexBuffer zusammen fassen. Und dann wird noch viel darüber geredet, was jetzt genau zum VAO-State gehört und was nicht. Aber so ganz konkret, wofür das eigentlich da ist, und wie man es jetzt korrekt benutzen würde, werden die irgendwie nicht. Und auf weitere 3000 schlechte OpenGL-Tutorials habe ich eigentlich keine Lust mehr.

Die Details zu den einzelnen Funktionen kann ich ja überall nachlesen, aber ich hätte gerne gewusst, was ich wie zusammen benutzen sollte. Beispielsweise hab ich in meinem Projekt noch im Rendercode zig "glVertexAttribPointer" Aufrufe (ohne je ein VAO erstellt zu haben, wieso kann man eigentlich alles für 5 verschiedene Sachen benutzen?) und wüsste gerne, ob ich die wirklich brauche - das VAO hört sich eigentlich so an, als könnte ich das am Anfang einmal initialisieren und ab dann benutzen, aber wirklich konkret werden die in die Richtung nicht.

Re: [OGL] Vertex Array Objects

Verfasst: 02.02.2013, 18:10
von dot
Ein VAO ist im Prinzip einfach ein Objekt, das den gesamten State der Input Stage repräsentiert, also die Gesamtheit der gebudnenen Buffer und Vertex Attribute Pointer und aktivierten Vertex Attribute etc. Anstatt also jedes mal aufs Neue alle Buffer zu binden und alle Attribute zu setzen und zu enablen, merkst du dir das alles in einem VAO und bindest dann nur noch das jeweilige VAO und fertig. Ab OpenGL 3.1 Core (iirc) geht ohne VAOs gar nix mehr, da es dort kein Default VAO mehr gibt...

Re: [OGL] Vertex Array Objects

Verfasst: 02.02.2013, 21:17
von PlainOldCJ
Es ist zu erwarten, dass es performanter ist ein VAO zu binden, als die Zustände einzeln zu setzen.
Zum Beispiel verringert sich die Anzahl von Funktionsaufrufen an den Grafikkartentreiber.

Re: [OGL] Vertex Array Objects

Verfasst: 03.02.2013, 09:25
von simbad
Die Zeit die in den Aufrufen an den Treiber verbraten wird ist riesig.
Du musst nur mal die Zeit messen die die das beschreiben einer 4GB große Datei einmal byte für byte verbraucht und einmal in 512Byte Blöcken.
Die Differenz die sich da ergibt ist in erster Linie den Aufrufen an das OS geschuldet, denn das OS buffered die Daten eh in einer Blockgröße das es für angemessen befindet, bevor die Daten auf das Medium gebracht werden.
So ziemlich jede Optimierung, die massenhafte OS calls vermeidet ist deutlich bemerkbar.

Re: [OGL] Vertex Array Objects

Verfasst: 03.02.2013, 14:33
von Jonathan
Ja ok, aber 4GB Byte für Byte schreiben und 3 Vertexbuffer binden ist nochmal ein Unterschied..
Das VAO speichert aber nur alle Buffer, oder? Ich muss zum Rendern dann also den Shader, alle Texturen, alle Uniforms und eben mein VAO (statt 2-3 Vertexbuffer + Indexbuffer + Setup was was heißen soll) setzen, ja?
Ich probiere das jetzt mal so aus, und poste Bilder, sobald ich Ergebnisse habe :)

Re: [OGL] Vertex Array Objects

Verfasst: 03.02.2013, 15:40
von Schrompf
Der Trick an VAOs ist doch meines Wissens, dass das Setup mit drin ist? Damit kann der GPU-Treiber eine Menge Verifikation und Zuordnung bei Erstellung machen, anstatt vor jedem DrawCall.

Wenn es wirklich nur die Buffer wären, wäre das ja nicht viel mehr als das Bündeln einiger Zeiger-Zuweisungen. Da hätte man wirklich nicht viel rausholen können.

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 09:48
von Jonathan
Es hört sich so an, als wären es wirklich nur die Buffer:
http://stackoverflow.com/questions/1182 ... ay-objects

Allerdings: Ich lege ja die Eingabe mit glVertexAttribPointer fest, und muss dem die Position des Attributes im Shader geben - es hängt also schon irgendwie vom Shader ab, ich sollte zumindest nur andere Shader mit der selben Attributreihenfolge benutzen. So richtig überzeugt bin ich von dem ganzen Konzept noch nicht, mal sehen, in wie weit sich das noch ändert.

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 11:56
von PlainOldCJ
Wegen der Reihenfolge der Attribute:

Ich mache das so, dass ich in jedem Shader mit

Code: Alles auswählen

layout(location = 0) in vec4 aPosition;
layout(location = 1) in vec3 aNormal;
...
feste Positionen für die Attribute vergebe und somit für jeden Mesh
nur einen VBO brauche.

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 12:07
von simbad
Jonathan hat geschrieben:Ja ok, aber 4GB Byte für Byte schreiben und 3 Vertexbuffer binden ist nochmal ein Unterschied..
Das VAO speichert aber nur alle Buffer, oder?
Nein. Weil es um die Frage der Menge der Aufrufe geht. Bei 4GB Daten kannste den Geschwindigkeitsunterschied mit der Bahnhofsuhr messen. Grundsätzlich ergibt sich immer das gleiche Problem. Wenn du Daten aus deinem User-Space-Prozess an das OS, und der GraKa-Treiber ist Bestandteil des OS, übergeben musst, geht viel Zeit beim Übergang in den Sicherheitsbereich des OS drauf. Früher hat man das per Soft-Interrupt gemacht. Dann müssen die Daten oft nochmal umkopiert werden, die Treiberfunktionen aufgerufen und noch vieles mehr.
Wenn ich diesen Aufwand, anstelle tausendfach zu wiederholen, einmal machen, habe ich einen Geschwindigkeitsgewinn von 1000 erreicht. Und genau darum ging es bei meinen Vergleich mit der Datei.

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 12:56
von dot
In Zeiten von Use Mode Drivern sollten die Kernel Mode Switches eher kaum zum Problem werden. Im konkreten Fall liegt der Overhead einzig und allein in der kaputten API begründet, Details gibt's z.B. hier: http://developer.download.nvidia.com/op ... aphics.pdf

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 15:53
von simbad
Das Papier wiederspricht meiner Aussage nicht.
Denn unterm Strich führt auch hier die Masse der Kommunikation zum Engpass. Um das zu umgehen, geht man dazu über der Anwendung eine Addresse mitzuteilen, in die die Anwendung ihre Daten hineinschreibt und die eigentlich schon auf der GraKa liegt. Damit kopiert das Programm die Daten direkt dahin wo sie hinsollen. Aber was passiert, wenn die Software einfach mal über die Grenzen schreibt?
Wie wird sichergestellt, dass die Anwendung nicht vitale Bereich der GraKa erwischt und wenn sie es doch tut, nicht gleich den Computer mit ins Nirvana befördert. Solange Hardware und Anwendung getrennt sind, ist das schlimmste das mein Prozess stirbt. Ist das immer noch so?
Kann sichergestellt werden, das die GraKa immer in ihren Grundzustand zurückfindet? Und ist der Window-Manager auch in der Lage einen solchen Crash direkt auf der Karte entsprechend abzuhandeln?

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 16:18
von dot
simbad hat geschrieben:Das Papier wiederspricht meiner Aussage nicht.
Denn unterm Strich führt auch hier die Masse der Kommunikation zum Engpass.
Klar, ich wollte nur feststellen, dass, aufgrund der Art und Weise wie Grafiktreiber in einem modernen OS funktionieren, die Kernel Mode Switches nicht unbedingt zum direkten Bottleneck werden, sondern dass der Overhead im konkreten Fall hier eher durch das kaputte Objektmodell der API bedingt ist. VAOs sollten es dem Treiber ermöglichen, diesen Overhead weitestgehend zu vermeiden.
simbad hat geschrieben:Um das zu umgehen, geht man dazu über der Anwendung eine Addresse mitzuteilen, in die die Anwendung ihre Daten hineinschreibt und die eigentlich schon auf der GraKa liegt. Damit kopiert das Programm die Daten direkt dahin wo sie hinsollen. Aber was passiert, wenn die Software einfach mal über die Grenzen schreibt?
Wie wird sichergestellt, dass die Anwendung nicht vitale Bereich der GraKa erwischt und wenn sie es doch tut, nicht gleich den Computer mit ins Nirvana befördert. Solange Hardware und Anwendung getrennt sind, ist das schlimmste das mein Prozess stirbt. Ist das immer noch so?
Kann sichergestellt werden, das die GraKa immer in ihren Grundzustand zurückfindet? Und ist der Window-Manager auch in der Lage einen solchen Crash direkt auf der Karte entsprechend abzuhandeln?
Ich glaub du hast da was falsch verstanden. Aber das ist auch egal, die NVIDIA Extension um die es in der Präsentation oben geht ist für das Thema hier irrelevant, mir ging es nur um die Beschreibung der Natur des Overhead.

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 17:54
von simbad
War aber trotzdem interessant.

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 21:36
von PlainOldCJ
Zu den Folien. Ich habe das so verstanden:

Für die Zuordnung buffer Name -> buffer Eigenschaften (insbesondere Addr. im GPU Speicher) muss im Hauptspeicher der CPU gelesen werden,
was Cache-Misses zur Folge hat.

War das die Aussage zur OpenGL 3.x Performance?

Re: [OGL] Vertex Array Objects

Verfasst: 04.02.2013, 22:25
von dot
jap

Re: [OGL] Vertex Array Objects

Verfasst: 05.02.2013, 01:08
von Jonathan
Ok, kennt jemand ein aktuelles OpenGL Tutorial (ab Version 4 oder so?). Ich bin es langsam leid, dass jede Funktion für sich zwar dokumentiert ist, aber die ganzen Zusammenhänge nicht so wirklich gut. Und wer weiß wie oft wenn ich was suche stoße ich auf Seiten, die einfach alt sind und wo ich selbst mit meinem Halbwissen merke, dass die Informationen die da stehen, lange nicht mehr aktuell sind und ignoriert werden sollten (immerhin, sonst hätte ich heute schon echt viel Blödsinn gecodet). Im Grunde genommen würde mir ein Beispielprogramm zu Instancing in Open GL mit Vertex- und Index Buffer und VAOs und was sonst noch alles dazugehört schon reichen.

Re: [OGL] Vertex Array Objects

Verfasst: 05.02.2013, 08:02
von Matthias Gubisch
Vieleicht hilft dir das etwas, bezüglich Tutorial

http://www.daveshreiner.com/SIGGRAPH/s11/

Beinhaltet zwar viele absoulte Grundlagen die dir wahrscheinlich schon bekannt sind aber ein anderes das sich bereits mit OGL 4 beschäftigt fällt mir grad nicht ein.

Re: [OGL] Vertex Array Objects

Verfasst: 05.02.2013, 16:02
von anonym
Jonathan hat geschrieben:Ok, kennt jemand ein aktuelles OpenGL Tutorial (ab Version 4 oder so?). Ich bin es langsam leid, dass jede Funktion für sich zwar dokumentiert ist, aber die ganzen Zusammenhänge nicht so wirklich gut.
Bezieht sich das auf die alphabetisch geordnete Online-Auflistung aller Funktionen des API, oder auf die Spezifikation? Letztere bietet über die einzelnen Komponenten der API einen jeweils vollständigen Überblick, anstatt dass man sich wie in ersterem Fall auf gut Glück einzelne Funktionen herauspickt und dabei Gefahr läuft, irgendetwas wichtiges zu übersehen.

Re: [OGL] Vertex Array Objects

Verfasst: 05.02.2013, 21:15
von NytroX
Hi allerseits,

http://www.swiftless.com/opengltuts/opengl4tuts.html

Das ist eines der verständlichsten Tutorials was ich damals gefunden hatte, wenn man den alten Kram bei OGL weglassen will.

Re: [OGL] Vertex Array Objects

Verfasst: 06.02.2013, 12:29
von waigie
Ich finde http://www.opengl-tutorial.org/ noch recht gut.

Re: [OGL] Vertex Array Objects

Verfasst: 07.02.2013, 01:24
von Jonathan
Nun, es scheint zu gehen :)

Ich glaube, ich benutzte VAOs jetzt so, wie sie gedacht sind, falls jemand drüber gucken möchte und mich auf Fehler hinweisen möchte, nun, das darf er sehr gerne machen :D

Code: Alles auswählen

#include "InstancedModel.hpp"

#include <assimp/Importer.hpp>
#include <assimp/PostProcess.h>
#include <assimp/scene.h>

#include <GL/glew.h>

using namespace std;
using namespace glm;

InstancedModel::InstancedModel(string ModelFile, string VertexFile, string FragmentFile)
{
	Assimp::Importer Importer;
	const aiScene* Scene=Importer.ReadFile(ModelFile,
		                                    aiProcess_Triangulate | aiProcess_CalcTangentSpace | aiProcess_RemoveRedundantMaterials |
		                                    aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_LimitBoneWeights);
	auto Mesh=Scene->mMeshes[0];

	//Positions
	m_PositionData.resize(Mesh->mNumVertices);
	memcpy(m_PositionData.data(), Mesh->mVertices, m_PositionData.size()*sizeof(vec3));

	//Uvs
	m_UvData.resize(Mesh->mNumVertices);
	memcpy(m_UvData.data(), Mesh->mTextureCoords[0], m_UvData.size()*sizeof(vec2));

	//Indices
	m_IndexData.resize(Mesh->mNumFaces*3);
	for(unsigned int i=0; i<Mesh->mNumFaces; ++i)
	{
		if(Mesh->mFaces[i].mNumIndices<3)
			continue; //skip points and lines
		
		//copy the indices of 1 triangle
		m_IndexData[i*3+0]=Mesh->mFaces[i].mIndices[0];
		m_IndexData[i*3+1]=Mesh->mFaces[i].mIndices[1];
		m_IndexData[i*3+2]=Mesh->mFaces[i].mIndices[2];
	}

	//and some fancy positions:
	for(auto i=0u; i<10; ++i)
	{
		m_InstancedPositionData.push_back(vec3(0, 0, i*10));
	}


	//Position Buffer:
	unsigned int PositionBuffer;
	glGenBuffers(1, &PositionBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, PositionBuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vec3)*m_PositionData.size(), m_PositionData.data(), GL_STATIC_DRAW);

	//Uv Buffer:
	unsigned int UvBuffer;
	glGenBuffers(1, &UvBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, UvBuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vec2)*m_UvData.size(), m_UvData.data(), GL_STATIC_DRAW);

	//Index Buffer
	unsigned int IndexBuffer;
	glGenBuffers(1, &IndexBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, IndexBuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned int)*m_IndexData.size(), m_IndexData.data(), GL_STATIC_DRAW);

	//Instanced Positions:
	unsigned int InstancedPositionBuffer;
	glGenBuffers(1, &InstancedPositionBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, InstancedPositionBuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vec3)*m_InstancedPositionData.size(), m_InstancedPositionData.data(), GL_STATIC_DRAW);

	//The Shader
	m_Shader.Load(VertexFile, FragmentFile);
	auto PositionLocation=glGetAttribLocation(m_Shader.GetProgram(), "attPosition");
	auto UvLocation=glGetAttribLocation(m_Shader.GetProgram(), "attUv");
	auto InstPosLocation=glGetAttribLocation(m_Shader.GetProgram(), "instPosition");


	//The Vertex Array Object
	glGenVertexArrays(1, &m_VertexArrayObject);
	glBindVertexArray(m_VertexArrayObject);
	
	//Positions
	glBindBuffer(GL_ARRAY_BUFFER, PositionBuffer);
	glVertexAttribPointer(PositionLocation, 3,	GL_FLOAT, GL_FALSE, 0, nullptr);
	glEnableVertexAttribArray(PositionLocation);
	
	//Uv
	glBindBuffer(GL_ARRAY_BUFFER, UvBuffer);
	glVertexAttribPointer(UvLocation, 2,	GL_FLOAT, GL_FALSE, 0, nullptr);
	glEnableVertexAttribArray(UvLocation);

	//Instanced Positions
	glBindBuffer(GL_ARRAY_BUFFER, InstancedPositionBuffer);
	glVertexAttribPointer(InstPosLocation, 3,	GL_FLOAT, GL_FALSE, 0, nullptr);
	glEnableVertexAttribArray(InstPosLocation);
	glVertexAttribDivisor(InstPosLocation, 1);


	//Indicies
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);

	glBindVertexArray(0);
}

InstancedModel::~InstancedModel()
{
	glDeleteVertexArrays(1, &m_VertexArrayObject);

	//well, delete buffers
}


void InstancedModel::Render()
{
	m_Shader.Set();
	glBindVertexArray(m_VertexArrayObject);
	//glDrawArrays(GL_TRIANGLES, 0, m_IndexData.size()/3);
	//glDrawElements(GL_TRIANGLES, m_IndexData.size()/3, GL_UNSIGNED_INT, nullptr);
	glDrawElementsInstanced(GL_TRIANGLES, m_IndexData.size()/3, GL_UNSIGNED_INT, nullptr, 10);
	glBindVertexArray(0);
	m_Shader.Unset();
}
Instancing
Instancing
(Das ist wieder eines der Bilder, bei denen ein Nicht-Informatiker absolut nicht verstehen kann, wie man sich über so was hässliches freuen kann... :D)