Du bist nicht angemeldet.

Werbeanzeige

  • »Spiele Programmierer« ist der Autor dieses Themas

Beiträge: 1 235

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

1

15.04.2014, 18:14

GLSL; Seltsame Fehlfunktion bei Blinn Phong Glanzlicht

Ich versuche heute schon den ganzen Tag ein anständiges Glanzlicht in meinen Wasser-Shader zu implementieren und komme irgendwie nicht darauf, wo der Fehler liegt. Die Normalen habe ich alle bereits als Farbe und einem Normal-Debug-Geometryshader untersucht und scheinen mir zu stimmen. Der "Eye"-Vektor zeigt vom Fragment zum Betrachter. Der "SunDirection"-Vektor zeigt die Richtung in die sich das Licht bewegt. Meine aktueller vereinfacher Fragmentshadercode:

HLSL-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#version 330

uniform vec3 SunDirection;

smooth in vec3 Eye;
    
out vec4 OutColor;

void main()
{
    vec3 HalfwayVector = normalize(normalize(Eye) - normalize(SunDirection));
    float SpecularIntensity = max(dot(HalfwayVector, vec3(0.0, 1.0, 0.0)), 0.0); //Die Normale ist zur Vereinfachung fest gesetzt.
    float SpecularColor = 1.0 * pow(SpecularIntensity, 5.0);
    OutColor = vec4(SpecularColor, SpecularColor, SpecularColor, 1.0);
}


Und der Vertexshader...

HLSL-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#version 330 

uniform mat4 ViewTransformMatrix;
uniform ivec2 PositionAdd;
uniform vec3 CameraPos;

layout(location = 1) in float WaterHeight;
layout(location = 0) in float Height;

smooth out vec3 Eye;

void main()
{
    ivec2 Pos2D = ivec2(gl_VertexID & (TERRAINBLOCKDATA_SIZE - 1), gl_VertexID >> TERRAINBLOCKDATA_SIZE_LOG2); //Berechnung der Position aus dem Grid
    Pos2D += PositionAdd;

    vec3 Position = vec3(float(Pos2D.x), (1.0 / (VERTICALFACTOR)) * float(WaterHeight), float(Pos2D.y));
    gl_Position = ViewTransformMatrix * vec4(Position, 1.0);
    Eye = normalize(CameraPos - Position);
}


Das Ergebnis ist zwar gar nicht komplett falsch, hat aber so einen komischen scharfe Ecke auf der Seite der Lichtquelle(Sonne) bei einem flachen Betrachtungswinkel. Das sieht sehr seltsam aus, wenn die virtuelle Sonne untergeht, bevor das Glanzlicht ganz verschwindet. Der weiße Glanzfleck wird dabei immer kleiner, ohnw schwächer zu werden.

Am späten Tag, könnte es noch in Ordnung sein: (Die Grasfläche im Hintergrund wird mit einem anderen Fragmentshader ohne Glanzlicht gerendert)


Wenn die Sonne untergegangen ist, verschwindet das Glanzlicht nicht mit und das Artefakt ist besonders gut erkennbar.


Obwohl eigentlich nicht so viel falsch sein kann, bin ich langsam ratlos. Habt ihr irgendwelche Ideen?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Spiele Programmierer« (15.04.2014, 20:40)


stef

Treue Seele

Beiträge: 238

Wohnort: Kassel

Beruf: Softwareentwickler

  • Private Nachricht senden

2

17.04.2014, 14:35

normalize(normalize(Eye) - normalize(SunDirection)) liefert keinen half way Vector sondern einen Vector der von SunDirection auf Eye zeigt.
Der half way sollte sich berechnen indem du addierst, also normalize(normalize(Eye) + normalize(SunDirection)).

EDIT: Unter der Annahme das SunDirection der Vector ist der vom Fragment zur Lichtquelle zeigt. (Da ist deine Beschreibung nicht so ganz klar)
"In C++ it's harder to shoot yourself in the foot, but when you do, you blow off your whole leg." — Bjarne Stroustrup.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »stef« (17.04.2014, 14:45)


  • »Spiele Programmierer« ist der Autor dieses Themas

Beiträge: 1 235

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

3

17.04.2014, 14:53

"SunDirection" ist ja der Vektor der von der Sonne zum Bildpunkt zeigt.
Der Vektor vom Bildpunkt zur Sonne, der für den Winkel gebraucht wird, ist dann der Gegenvektor, also "-", wie auch im Link dargestellt.
Wenn ich das Minus mit einem Plus ersetze, scheint es mir genau verkehrt herum zu sein. Also das Licht ist sowieso nur in der Nacht sichtbar und wird in die selbe Richtung relfektiert, von der es kommt. (180° Drehung des Lichtstrahls)

Trotzdem danke für den Hilfeversuch.

EDIT:
Siehe dein Edit, genau das Gegenteil ist der Fall. Mit "Der "SunDirection"-Vektor zeigt die Richtung in die sich das Licht bewegt." meinte ich genau das.

4

19.04.2014, 20:11

Die Integral Funktion für das reflektierte Licht ist nur über der Hemisphere über dem Punkt definiert.

Da du das Punktprodukt zwischen der Normale und dem Halfway Vektor, statt dem zwischen Einfallsvektor und Normale (in Phong), nimmst, musst du noch die Funktion auf die Hemisphere (dot(Incident, Normal) >= 0!) begrenzen, da sonst eine Beleuchtung nicht stattfinden kann.

Wie lösen wir das?
Wenn die Sonne bei dir unter geht und deine Normale (0,1,0) ist, ist der Winkel zwischen Einfallsvektor und Normale größer als 90 Grad und somit der Kosinus (Punktprodukt) kleiner als 0. Wenn dieser Fall eintritt, ist der Blinn-Phong-Term nicht definiert, bzw. 0

Das heißt: du musst deinen Code etwas ergänzen:

HLSL-Quelltext

1
2
float SpecularIntensity = max(dot(HalfwayVector, vec3(0.0, 1.0, 0.0)), 0.0);
SpecularIntensity = (dot(normalize(SunDirection), SurfaceNormal) > 0.0) ? SpecularIntensity : 0.0;


(Das hier ist nur Pseudocode. Du musst noch auf die SurfaceNormal zugreifen und möglichst zweifache Normalisierung der SunDirection vermeiden)
EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

  • »Spiele Programmierer« ist der Autor dieses Themas

Beiträge: 1 235

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

5

19.04.2014, 22:55

Eigentlich habe ich doch schon die "max"-Funktion einbaut die entsprechend bei 0 limitiert?

6

19.04.2014, 23:19

Jupp. Aber du "limitierst" den Winkel zwischen H (Halfwayvector) und Normale, anstatt dem zwischen Einfalls- und Normale:

HLSL-Quelltext

1
max(dot(HalfwayVector, vec3(0.0, 1.0, 0.0)), 0.0)


Wie du in der Zeichnung erkennen kannst, ist dieser zwar in dem "Sonnenuntergangs"-Fall richtig, aber der Winkel zwischen Psi und H nicht (rot markiert) ;)

EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

Werbeanzeige

Ähnliche Themen