[OGL] Vertex Array Objects

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
Jonathan
Establishment
Beiträge: 2367
Registriert: 04.08.2004, 20:06
Kontaktdaten:

[OGL] Vertex Array Objects

Beitrag 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.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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...
PlainOldCJ
Beiträge: 11
Registriert: 03.12.2012, 20:56
Echter Name: Christian

Re: [OGL] Vertex Array Objects

Beitrag 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.
simbad
Establishment
Beiträge: 132
Registriert: 14.12.2011, 14:30

Re: [OGL] Vertex Array Objects

Beitrag 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.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2367
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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 :)
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Schrompf
Moderator
Beiträge: 4854
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2367
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
PlainOldCJ
Beiträge: 11
Registriert: 03.12.2012, 20:56
Echter Name: Christian

Re: [OGL] Vertex Array Objects

Beitrag 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.
simbad
Establishment
Beiträge: 132
Registriert: 14.12.2011, 14:30

Re: [OGL] Vertex Array Objects

Beitrag 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.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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
simbad
Establishment
Beiträge: 132
Registriert: 14.12.2011, 14:30

Re: [OGL] Vertex Array Objects

Beitrag 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?
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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.
simbad
Establishment
Beiträge: 132
Registriert: 14.12.2011, 14:30

Re: [OGL] Vertex Array Objects

Beitrag von simbad »

War aber trotzdem interessant.
PlainOldCJ
Beiträge: 11
Registriert: 03.12.2012, 20:56
Echter Name: Christian

Re: [OGL] Vertex Array Objects

Beitrag 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?
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag von dot »

jap
Benutzeravatar
Jonathan
Establishment
Beiträge: 2367
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Matthias Gubisch
Establishment
Beiträge: 470
Registriert: 01.03.2009, 19:09

Re: [OGL] Vertex Array Objects

Beitrag 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.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
anonym
Beiträge: 79
Registriert: 15.07.2009, 07:35
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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.
NytroX
Establishment
Beiträge: 363
Registriert: 03.10.2003, 12:47

Re: [OGL] Vertex Array Objects

Beitrag 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.
waigie
Beiträge: 82
Registriert: 20.05.2009, 19:37

Re: [OGL] Vertex Array Objects

Beitrag von waigie »

Ich finde http://www.opengl-tutorial.org/ noch recht gut.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2367
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: [OGL] Vertex Array Objects

Beitrag 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)
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Antworten