Lazarus - OpenGL 3.3 Tutorial - Erster Shader
Inhaltsverzeichnis
Einrichten und Einstieg - Erster Shader
Einleitung
Hier wird zum ersten Mal ein Shader geladen, ohne solchen macht OpenGL >= 3.3 keinen Sinn.
Nähere Details dazu im Kapitel Shader. Hier geht es in erster Linie mal darum, dass man etwas rendern kann.
In diesem Beispiel wird ein sehr einfacher Shader verwendet. Dieser macht nichts anderes, als das Mesh rot darzustellen.
Die ID, welche auf den Shader zeigt.
var
ProgramID: GLuint;
Lädt den Vertex- und Fragment-Shader in die Grafikkarte.
In diesem Beispiel sind die beiden Shader in einer Textdatei.
Natürlich kann man diese auch direkt als String-Konstante im Quellcode deklarieren.
function Initshader(VertexDatei, FragmentDatei: string): GLuint;
var
sl: TStringList;
s: string;
ProgramObject: GLhandle;
VertexShaderObject: GLhandle;
FragmentShaderObject: GLhandle;
ErrorStatus, InfoLogLength: integer;
begin
sl := TStringList.Create;
ProgramObject := glCreateProgram();
// Vertex - Shader
VertexShaderObject := glCreateShader(GL_VERTEX_SHADER);
sl.LoadFromFile(VertexDatei);
s := sl.Text;
glShaderSource(VertexShaderObject, 1, @s, nil);
glCompileShader(VertexShaderObject);
glAttachShader(ProgramObject, VertexShaderObject);
// Check Shader
glGetShaderiv(VertexShaderObject, GL_COMPILE_STATUS, @ErrorStatus);
if ErrorStatus = 0 then begin
glGetShaderiv(VertexShaderObject, GL_INFO_LOG_LENGTH, @InfoLogLength);
SetLength(s, InfoLogLength + 1);
glGetShaderInfoLog(VertexShaderObject, InfoLogLength, nil, @s[1]);
Application.MessageBox(PChar(s), 'OpenGL Vertex Fehler', 48);
Halt;
end;
glDeleteShader(VertexShaderObject);
// Fragment - Shader
FragmentShaderObject := glCreateShader(GL_FRAGMENT_SHADER);
sl.LoadFromFile(FragmentDatei);
s := sl.Text;
glShaderSource(FragmentShaderObject, 1, @s, nil);
glCompileShader(FragmentShaderObject);
glAttachShader(ProgramObject, FragmentShaderObject);
// Check Shader
glGetShaderiv(FragmentShaderObject, GL_COMPILE_STATUS, @ErrorStatus);
if ErrorStatus = 0 then begin
glGetShaderiv(FragmentShaderObject, GL_INFO_LOG_LENGTH, @InfoLogLength);
SetLength(s, InfoLogLength + 1);
glGetShaderInfoLog(FragmentShaderObject, InfoLogLength, nil, @s[1]);
Application.MessageBox(PChar(s), 'OpenGL Fragment Fehler', 48);
Halt;
end;
glDeleteShader(FragmentShaderObject);
glLinkProgram(ProgramObject); // Die beiden Shader zusammen linken
// Check Link
glGetProgramiv(ProgramObject, GL_LINK_STATUS, @ErrorStatus);
if ErrorStatus = 0 then begin
glGetProgramiv(ProgramObject, GL_INFO_LOG_LENGTH, @InfoLogLength);
SetLength(s, InfoLogLength + 1);
glGetProgramInfoLog(ProgramObject, InfoLogLength, nil, @s[1]);
Application.MessageBox(PChar(s), 'OpenGL ShaderLink Fehler', 48);
Halt;
end;
Result := ProgramObject;
sl.Free;
end;
Dieser Code wurde um 2 Zeilen erweitert.
In der ersten Zeile wird der Shader in die Grafikkarte geladen.
Die zweite Zeile aktiviert den Shader.
Dies wird spätestens dann interessant, wenn man mehrere Shader verwendet.
Näheres im Kapitel Shader.
procedure TForm1.CreateScene;
begin
ProgramID := InitShader('Vertexshader.glsl', 'Fragmentshader.glsl');
glUseProgram(programID);
Beim Zeichnen muss man auch mit glUseProgram(... den Shader wählen, mit welchem das Mesh gezeichnet wird.
Bei diesem Mini-Code könnte dies weggelassen werden, da nur ein Shader verwendet wird und dieser bereits in TForm1.CreateScene aktiviert wurde.
procedure TForm1.ogcDrawScene(Sender: TObject);
begin
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(programID);
Am Ende noch mit glDeleteShader(... die Shader in der Grafikkarte wieder freigeben.
In diesem Code ist dies nur einer.
procedure TForm1.FormDestroy(Sender: TObject);
begin
glDeleteProgram(ProgramID);
Die beiden verwendeten Shader, Details dazu im Kapitel Shader.
Vertex-Shader:
#version 330
layout (location = 0) in vec3 inPos;
void main(void)
{
gl_Position = vec4(inPos, 1.0);
}
Fragment-Shader:
#version 330
out vec4 outColor; // ausgegebene Farbe
void main(void)
{
outColor = vec4(1.0, 0.0, 0.0, 1.0);
}
Autor: Mathias
Siehe auch
- Übersichtseite Lazarus - OpenGL 3.3 Tutorial