Lazarus - OpenGL 3.3 Tutorial - Beleuchtung - Directional Light

Aus DGL Wiki
Version vom 20. Dezember 2017, 23:36 Uhr von Mathias (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „200px<br><br> =Beleuchtung - Einfache Beleuchtung mit Clamp = == Ein…“)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

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

Beleuchtung - Einfache Beleuchtung mit Clamp

Einleitung

Ohne Beleuchtung sehen die Object statisch aus, wen man noch Beleuchtung ins Spiel bringt, wirkt eine OpenGL-Scene viel realistischer.
Dabei gibt es verschiedene Arten von Beleuchtung. Das meist verwendete ist Directional Light, dies entspricht dem Sonnenlicht.
Dieses Beispiel zeigt eine ganz einfache Variante von diesem Licht. Je steiler das Licht auf ein Polygon einstrahlt, je heller wird das Polygon.

Das man dies berechnen kann, braucht es für jede Ecke des Polygons eie Normale-Vektor.
Eine Normale zeigt meistens senkrecht auf ein Polygon.

Es gibt Ausnahmen, zB. bei runden Flächen. Dazu in einem späteren Beispiel.


Die Konstanten der Würfel-Vektoren.

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)));

Für die Normale wird nur eine Variable für Vektoren deklariert, da diese aus den Vektoren des Würfels berechnet werden.

var
  CubeNormal: TCube;

Für die Normale braucht es noch eine VBO.

type
  TVB = record
    VAO,
    VBOvert,            // VBO für Vektor.
    VBONormal: GLuint;  // VBO für Normale.
  end;

In der Unit Matrix hat es eine fertige Funktion, welche die Normale aus den Vertex-Koordinaten berechnet.

procedure TForm1.CreateScene;
begin
  FaceToNormale(CubeVertex, CubeNormal);

Die Normale wird genau gleich in den VRAM geladen, wie die Vertex-Koordinaten.

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;



Einfachere Beleuchtungen macht man im Vertex-Shader.
Will man aber komplexer Beleuchtungen, nimmt man dazu den Fragment-Shader, das dieser Pixelgenau ist.
Dafür wird aber mehr Berechnugszeit benötigt.

Vertex-Shader:


Die Berechnug für das Licht des einfachen Beispieles ist hier im Vetex-Shader.

#version 330

#define PI 3.1415926535897932384626433832795

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 Matrix;                    // Matrix für die Drehbewegung und Frustum.

vec3 LightPos = vec3(1.0, 0.0, 0.0);

float angele(vec3 p, vec3 q){
  vec3  r1 = normalize(p);     // Vektoren normalisieren, so das die Länge des Vektors immer 1.0 ist.
  vec3  r2 = normalize(q);
  float d  = dot(r1, r2);      // Skalarprodukt aus beiden Vektoren berechnen.
//  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)
{
  vec3 Normal = mat3(Matrix) * inNormal;

  float w = angele(LightPos, Normal);
  float col = (w / PI);
//  float col = w;

  gl_Position = Matrix * vec4(inPos, 1.0);
  Color = vec4(col, col, col, 0.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