Lazarus - OpenGL 3.3 Tutorial - Beleuchtung - Directional Light: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
(Die Seite wurde neu angelegt: „200px<br><br> =Beleuchtung - Einfache Beleuchtung mit Clamp = == Ein…“)
 
K (Fragment-Shader)
 
(14 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
[[Image:Lazarus - OpenGL 3.3 Tutorial - Beleuchtung - Einfache Beleuchtung mit Clamp.png|200px]]<br><br>
+
[[Image:Lazarus - OpenGL 3.3 Tutorial - Beleuchtung - Directional Light.png|200px]]<br><br>
=Beleuchtung - Einfache Beleuchtung mit Clamp =
+
=Beleuchtung - Directional Light =
 
== Einleitung ==
 
== Einleitung ==
Ohne Beleuchtung sehen die Object statisch aus, wen man noch Beleuchtung ins Spiel bringt, wirkt eine OpenGL-Scene viel realistischer.<br>
+
Das Directional-Light entspricht in etwa dem Sonnen-Licht, die Lichtstrahlen kommen alle von der gleichen Richtung.<br>
Dabei gibt es verschiedene Arten von Beleuchtung. Das meist verwendete ist '''Directional Light''', dies entspricht dem Sonnenlicht.<br>
+
Im Grunde ist die Sonne auch ein Punktlicht, aber auf der Erde nimmt man es als Directional-Light war.<br>
Dieses Beispiel zeigt eine ganz einfache Variante von diesem Licht. Je steiler das Licht auf ein Polygon einstrahlt, je heller wird das Polygon.<br>
+
Im Beispiel von Rechts.<br>
 
<br>
 
<br>
Das man dies berechnen kann, braucht es für jede Ecke des Polygons eie Normale-Vektor.<br>
+
Im ersten Beispiel wurde die Beleuchung mit Acos und Pi berechnet.<br>
Eine Normale zeigt meistens senkrecht auf ein Polygon.<br>
+
Dieser Umweg kann man sich sparen, es gibt zwar so ein kleiner Rechnungsfehler, aber diesen kann man getrost ingnorieren.<br>
 +
Dies hat sogar den Vorteil, wen der Einstrahlwinkel des Lichtes flacher als 90° ist, ist die Beleuchtungsstärke gleich null.<br>
 +
Als was flacher als 90° ist, ist negativ.<br>
 +
Für dies gibt es in GLSL eine fertige Funktion '''clamp''', mit der kann man einen Bereich festlegen.<br>
 +
So das es in diesem Beispiel keinen Wert < '''0.0''' oder > '''1.0''' gibt.<br>
 
<br>
 
<br>
Es gibt Ausnahmen, zB. bei runden Flächen. Dazu in einem späteren Beispiel.<br>
+
Der einzige Unterschied zu vorherigem Beispiel ist im Shader-Code. Auch der Hintergrund wurde etwas dunkler gemacht, das man den Licht-Effekt besser sieht.<br>
 +
<br>
 +
Bei dem Lichtpositions-Vector ist es egal, wie weit die Lichtquelle weg ist, da der Vektor nur die Lichtrichtung angeben muss.<br>
 +
Meistens nimmt man aber einen '''Einheitsvektor''', das ist ein Vektor mit der Länge '''1.0'''.<br>
 +
Die Lichtposition wird im Vertex-Shader als Konstante definiert.<br>
 
<br><br>
 
<br><br>
Die Konstanten der Würfel-Vektoren.<br>
 
<syntaxhighlight lang="pascal">const
 
  CubeVertex: TCube =
 
    (((-0.5, 0.5, 0.5), (-0.5, -0.5, 0.5), (0.5, -0.5, 0.5)), ((-0.5, 0.5, 0.5), (0.5, -0.5, 0.5), (0.5, 0.5, 0.5)),
 
    ((0.5, 0.5, 0.5), (0.5, -0.5, 0.5), (0.5, -0.5, -0.5)), ((0.5, 0.5, 0.5), (0.5, -0.5, -0.5), (0.5, 0.5, -0.5)),
 
    ((0.5, 0.5, -0.5), (0.5, -0.5, -0.5), (-0.5, -0.5, -0.5)), ((0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (-0.5, 0.5, -0.5)),
 
    ((-0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (-0.5, -0.5, 0.5)), ((-0.5, 0.5, -0.5), (-0.5, -0.5, 0.5), (-0.5, 0.5, 0.5)),
 
    // oben
 
    ((0.5, 0.5, 0.5), (0.5, 0.5, -0.5), (-0.5, 0.5, -0.5)), ((0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (-0.5, 0.5, 0.5)),
 
    // unten
 
    ((-0.5, -0.5, 0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)), ((-0.5, -0.5, 0.5), (0.5, -0.5, -0.5), (0.5, -0.5, 0.5)));</syntaxhighlight>
 
Für die Normale wird nur eine Variable für Vektoren deklariert, da diese aus den Vektoren des Würfels berechnet werden.<br>
 
<syntaxhighlight lang="pascal">var
 
  CubeNormal: TCube;</syntaxhighlight>
 
Für die Normale braucht es noch eine VBO.<br>
 
<syntaxhighlight lang="pascal">type
 
  TVB = record
 
    VAO,
 
    VBOvert,            // VBO für Vektor.
 
    VBONormal: GLuint;  // VBO für Normale.
 
  end;</syntaxhighlight>
 
In der Unit Matrix hat es eine fertige Funktion, welche die Normale aus den Vertex-Koordinaten berechnet.<br>
 
<syntaxhighlight lang="pascal">procedure TForm1.CreateScene;
 
begin
 
  FaceToNormale(CubeVertex, CubeNormal);</syntaxhighlight>
 
Die Normale wird genau gleich in den VRAM geladen, wie die Vertex-Koordinaten.<br>
 
<syntaxhighlight lang="pascal">procedure TForm1.InitScene;
 
begin
 
  glClearColor(0.6, 0.6, 0.4, 1.0); // Hintergrundfarbe
 
 
  // --- Daten für Würfel
 
  glBindVertexArray(VBCube.VAO);
 
 
  // Vektor
 
  glBindBuffer(GL_ARRAY_BUFFER, VBCube.VBOvert);
 
  glBufferData(GL_ARRAY_BUFFER, sizeof(CubeVertex), @CubeVertex, GL_STATIC_DRAW);
 
  glEnableVertexAttribArray(0);
 
  glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, nil);
 
 
  // Normale
 
  glBindBuffer(GL_ARRAY_BUFFER, VBCube.VBONormal);
 
  glBufferData(GL_ARRAY_BUFFER, sizeof(CubeNormal), @CubeNormal, GL_STATIC_DRAW);
 
  glEnableVertexAttribArray(1);
 
  glVertexAttribPointer(1, 3, GL_FLOAT, False, 0, nil);
 
 
end;</syntaxhighlight>
 
 
<br><br>
 
<br><br>
Einfachere Beleuchtungen macht man im Vertex-Shader.<br>
+
Hier sieht man, das anstelle von arcos und Pi, '''clamp''' verwendet wurde.<br>
Will man aber komplexer Beleuchtungen, nimmt man dazu den Fragment-Shader, das dieser Pixelgenau ist.<br>
 
Dafür wird aber mehr Berechnugszeit benötigt.<br>
 
 
==Vertex-Shader:==
 
==Vertex-Shader:==
<br>
 
Die Berechnug für das Licht des einfachen Beispieles ist hier im Vetex-Shader.<br>
 
 
<syntaxhighlight lang="glsl">#version 330
 
<syntaxhighlight lang="glsl">#version 330
  
#define PI 3.1415926535897932384626433832795
+
// Das Licht kommt von Rechts.
 +
#define LightPos vec3(1.0, 0.0, 0.0)
  
 
layout (location = 0) in vec3 inPos;    // Vertex-Koordinaten
 
layout (location = 0) in vec3 inPos;    // Vertex-Koordinaten
Zeile 73: Zeile 32:
 
out vec4 Color;                        // Farbe, an Fragment-Shader übergeben.
 
out vec4 Color;                        // Farbe, an Fragment-Shader übergeben.
  
 +
uniform mat4 ModelMatrix;              // Matrix des Modell, ohne Frustumeinfluss.
 
uniform mat4 Matrix;                    // Matrix für die Drehbewegung und Frustum.
 
uniform mat4 Matrix;                    // Matrix für die Drehbewegung und Frustum.
  
vec3 LightPos = vec3(1.0, 0.0, 0.0);
+
float light(vec3 p, vec3 n) {
 
+
   vec3  v1 = normalize(p);       // Vektoren normalisieren,
float angele(vec3 p, vec3 q){
+
  vec3  v2 = normalize(n);      // so das die Länge des Vektors immer 1.0 ist.
   vec3  r1 = normalize(p);     // Vektoren normalisieren, so das die Länge des Vektors immer 1.0 ist.
+
   float d  = dot(v1, v2);       // Skalarprodukt aus beiden Vektoren berechnen.
  vec3  r2 = normalize(q);
+
  float c = clamp(d, 0.0, 1.0); // Alles > 1.0 und < 0.0, wird zwischen 0.0 und 1.0 gesetzt.
   float d  = dot(r1, r2);     // Skalarprodukt aus beiden Vektoren berechnen.
+
  return c;                     // Lichtstärke als Rückgabewert.
// return acos(d);             // Davon noch den Arkuskosinus berechnen. Somit hat man den Winkel zwischen den beiden Vektoren.
 
//  return max(d, 0.0);
 
return d;
 
// return clamp(dot(r1, r2), 0.0, 1.0);
 
 
}
 
}
  
void main(void)
+
void main(void) {
{
+
   gl_Position  = Matrix * vec4(inPos, 1.0);
   vec3 Normal = mat3(Matrix) * inNormal;
 
  
   float w = angele(LightPos, Normal);
+
   vec3  Normal = mat3(ModelMatrix) * inNormal;
   float col = (w / PI);
+
   float col   = light(LightPos, Normal);
//  float col = w;
 
  
  gl_Position = Matrix * vec4(inPos, 1.0);
+
   Color       = vec4(col, col, col, 1.0);
   Color = vec4(col, col, col, 0.0);
 
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Zeile 103: Zeile 56:
 
<syntaxhighlight lang="glsl">#version 330
 
<syntaxhighlight lang="glsl">#version 330
  
in vec4 Color;     // interpolierte Farbe vom Vertexshader
+
in vec4 Color;     // interpolierte Farbe vom Vertexshader
 
out vec4 outColor;  // ausgegebene Farbe
 
out vec4 outColor;  // ausgegebene Farbe
  
void main(void)
+
void main(void) {
{
 
 
   outColor = Color; // Die Ausgabe der Farbe
 
   outColor = Color; // Die Ausgabe der Farbe
 
}
 
}
Zeile 113: Zeile 65:
  
 
<br>Autor: [[Mathias]]
 
<br>Autor: [[Mathias]]
 +
 
== Siehe auch ==
 
== Siehe auch ==
 
* Übersichtseite [[Lazarus - OpenGL 3.3 Tutorial]]
 
* Übersichtseite [[Lazarus - OpenGL 3.3 Tutorial]]

Aktuelle Version vom 22. Juli 2018, 21:06 Uhr

Lazarus - OpenGL 3.3 Tutorial - Beleuchtung - Directional Light.png

Beleuchtung - Directional Light

Einleitung

Das Directional-Light entspricht in etwa dem Sonnen-Licht, die Lichtstrahlen kommen alle von der gleichen Richtung.
Im Grunde ist die Sonne auch ein Punktlicht, aber auf der Erde nimmt man es als Directional-Light war.
Im Beispiel von Rechts.

Im ersten Beispiel wurde die Beleuchung mit Acos und Pi berechnet.
Dieser Umweg kann man sich sparen, es gibt zwar so ein kleiner Rechnungsfehler, aber diesen kann man getrost ingnorieren.
Dies hat sogar den Vorteil, wen der Einstrahlwinkel des Lichtes flacher als 90° ist, ist die Beleuchtungsstärke gleich null.
Als was flacher als 90° ist, ist negativ.
Für dies gibt es in GLSL eine fertige Funktion clamp, mit der kann man einen Bereich festlegen.
So das es in diesem Beispiel keinen Wert < 0.0 oder > 1.0 gibt.

Der einzige Unterschied zu vorherigem Beispiel ist im Shader-Code. Auch der Hintergrund wurde etwas dunkler gemacht, das man den Licht-Effekt besser sieht.

Bei dem Lichtpositions-Vector ist es egal, wie weit die Lichtquelle weg ist, da der Vektor nur die Lichtrichtung angeben muss.
Meistens nimmt man aber einen Einheitsvektor, das ist ein Vektor mit der Länge 1.0.
Die Lichtposition wird im Vertex-Shader als Konstante definiert.




Hier sieht man, das anstelle von arcos und Pi, clamp verwendet wurde.

Vertex-Shader:

#version 330

// Das Licht kommt von Rechts.
#define LightPos vec3(1.0, 0.0, 0.0)

layout (location = 0) in vec3 inPos;    // Vertex-Koordinaten
layout (location = 1) in vec3 inNormal; // Normale

out vec4 Color;                         // Farbe, an Fragment-Shader übergeben.

uniform mat4 ModelMatrix;               // Matrix des Modell, ohne Frustumeinfluss.
uniform mat4 Matrix;                    // Matrix für die Drehbewegung und Frustum.

float light(vec3 p, vec3 n) {
  vec3  v1 = normalize(p);       // Vektoren normalisieren,
  vec3  v2 = normalize(n);       // so das die Länge des Vektors immer 1.0 ist.
  float d  = dot(v1, v2);        // Skalarprodukt aus beiden Vektoren berechnen.
  float c  = clamp(d, 0.0, 1.0); // Alles > 1.0 und < 0.0, wird zwischen 0.0 und 1.0 gesetzt.
  return c;                      // Lichtstärke als Rückgabewert.
}

void main(void) {
  gl_Position  = Matrix * vec4(inPos, 1.0);

  vec3  Normal = mat3(ModelMatrix) * inNormal;
  float col    = light(LightPos, Normal);

  Color        = vec4(col, col, col, 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