Lazarus - OpenGL 3.3 Tutorial - Instancing - VertexAttribDivisor
Inhaltsverzeichnis
Instancing - VertexAttribDivisor
Einleitung
Mit VertexAttribDivisor kann man nicht nur bestimmen, das es sich im ein Instance-Attribut handelt.
Man kann auch festlegen, das ein Attribut-Wert mehrmals verwendet wird, bevor er um eins weiter springt.
Im Beispiel sieht man, das der Farb-Wert vier mal verwendet wird, bevor der nächste wert kommt.
Für die Farben werden nur 4 Werte benötigt. Diese werden als Konstante deklariert,
da diese sich zur Laufzeit nicht mehr ändern.
const
Quad: array[0..1] of TFace3D =
(((-0.8, -0.8, 0.0), (-0.8, 0.8, 0.0), (0.8, 0.8, 0.0)),
((-0.8, -0.8, 0.0), (0.8, -0.8, 0.0), (0.8, 0.8, 0.0)));
Instance_Color: array[0..3] of TVector3f =
((1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), (1.0, 1.0, 0.0));
Rechtecke gibt es 16 Stück, die Matrizen dafür sind dynamisch.
var
Instance_Matrix: array[0..15] of TMatrix;
Mit glVertexAttribDivisor(... kann man nicht nur bestimmen, das es sich um ein Instance-Attribut handelt.
Sondern man kann auch sagen wie viel mal ein Attribut-Wert verwendet wird.
Dies geschieht mit dem zweiten Parameter.
procedure TForm1.InitScene;
var
i: integer;
begin
glClearColor(0.6, 0.6, 0.4, 1.0); // Hintergrundfarbe
glBindVertexArray(VBTriangle.VAO);
// Vektor
glBindBuffer(GL_ARRAY_BUFFER, VBTriangle.VBO.Pos);
glBufferData(GL_ARRAY_BUFFER, SizeOf(Quad), @Quad, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, nil);
glVertexAttribDivisor(0, 0);
// Instance Color
glBindBuffer(GL_ARRAY_BUFFER, VBTriangle.VBO.iColor);
glBufferData(GL_ARRAY_BUFFER, SizeOf(Instance_Color), @Instance_Color, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, False, 0, nil);
glVertexAttribDivisor(1, 4); // Wert 4x verwenden.
// Instance Matrix
glBindBuffer(GL_ARRAY_BUFFER, VBTriangle.VBO.iMatrix);
glBufferData(GL_ARRAY_BUFFER, SizeOf(TMatrix) * Length(Instance_Matrix), nil, GL_STATIC_DRAW);
for i := 0 to 3 do begin
glEnableVertexAttribArray(i + 2);
glVertexAttribPointer(i + 2, 4, GL_FLOAT, False, SizeOf(TMatrix), Pointer(i * 16));
glVertexAttribDivisor(i + 2, 1); // Wert 1x verwenden.
end;
end;
Matrizen drehen und anschliessend, neu laden.
procedure TForm1.Timer1Timer(Sender: TObject);
const
r: GLfloat = 0.0;
var
i: integer;
begin
r += 0.01;
if r > 2 * pi then begin
r -= 2 * pi;
end;
for i := 0 to 15 do begin
Instance_Matrix[i].Identity;
Instance_Matrix[i].Scale(0.25, 0.05, 1.0);
Instance_Matrix[i].RotateC(Pi * 2 / 16 * i + r);
Instance_Matrix[i].TranslateLocalspace(2.0, 0.0, 0.0);
end;
glBindVertexArray(VBTriangle.VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBTriangle.VBO.iMatrix);
glBufferSubData(GL_ARRAY_BUFFER, 0, SizeOf(TMatrix) * Length(Instance_Matrix), @Instance_Matrix);
ogc.Invalidate;
end;
Vertex-Shader:
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 instance_color;
layout (location = 2) in mat4 instance_Matrix;
out vec4 Color;
void main(void) {
gl_Position = instance_Matrix * vec4(position, 1.0);
Color = vec4(instance_color, 1.0);
}
Fragment-Shader
#version 330
in vec4 Color; // interpolierte Farbe vom Vertexshader
out vec4 outColor; // ausgegebene Farbe
void main(void)
{
outColor = Color; // Die Ausgabe der Farbe
}
Autor: Mathias
Siehe auch
- Übersichtseite Lazarus - OpenGL 3.3 Tutorial