Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Mo Jul 14, 2025 21:34

Foren-Übersicht » Programmierung » Shader
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 15 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Sa Jun 05, 2010 16:34 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
Hi,

ich habe es schon mit vielen Shadern - Programmen versucht, korrekte Lichtberechnungen
durchzuführen. Jedoch ohne Erfolgt :(. Immer wenn ich meine Kamera drehe/bewege sind die
Lichteffekt verschoben oder schon garnicht mehr zu sehen.
Ich verwende momentan folgende Shader:

Vertex:
Code:
varying vec4 diffuse, ambient;
varying vec3 normal, lightDir, halfVector;

void main() {
    normal = normalize(gl_NormalMatrix * gl_Normal);
    lightDir = normalize(vec3(gl_LightSource[0].position));
    halfVector = normalize(gl_LightSource[0].halfVector.xyz);
    diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
    ambient = gl_FrontMaterial.ambient * (gl_LightSource[0].ambient + gl_LightModel.ambient);

    gl_Position = ftransform();
}


Fragment:
Code:
varying vec4 diffuse, ambient;
varying vec3 normal, lightDir, halfVector;

void main() {
    vec3 n, halfV, viewW, ldir;
    float NdotL, NdotHV;

    vec4 color = ambient;
    n = normalize(normal);

    NdotL = dot(n, lightDir);

    if(NdotL > 0.0) {
        halfV = normalize(halfVector);
        NdotHV = max(dot(n, halfV), 0.0);
        color += gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV, gl_FrontMaterial.shininess);
        color += diffuse * NdotL;
    }

    gl_FragColor = color;
}


Hier zur Verdeutlichung 2 Screenshots mit dem selben Shader nur aus 2 verschiedenen Positionen:
http://xyross.de/download/xy1.jpg
http://xyross.de/download/xy2.jpg
Edit by Horazont: Bitte keine so großen Bilder direkt einfügen

Woran liegt das :(?

Mfg, Pk3 :).


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jun 05, 2010 17:33 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Wie setzt du den die Position der Lichtquelle? Die Lichtquelle muss in den View-Space transformiert werden, da deine Normale ja durch gl_NormalMatrix ebenfalls dahin geschoben wird.

Am besten setzt du den Lichtvektor nachdem du die Kamera mit gluLookAt gesetzt hast, dann sollte OpenGL sie automatisch richtig transformieren.

gl_LightSource[0].halfVector hab ich noch nie benutzt, sicher das der richtig ist? Du kannst den auch via reflect(lightvec, normal) berechnen. lightvec muss dabei vom Fragment zum Licht zeigen.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jun 05, 2010 17:42 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
Ich verwende kein gluLookAt, sondern transformiere so:

Code:
void clRender::Lights(void) {
    int i;
    for(i = 0; i < MAX_LIGHTS; i++) {
        if(LightSystem.Light[i].lock == 1 && LightSystem.Light[i].enable == 1) {
            glLoadIdentity();
            GLfloat position[] = { LightSystem.Light[i].Pos.X, LightSystem.Light[i].Pos.Y, LightSystem.Light[i].Pos.Z, 1.0f };

            glRotatef(Camera.Angle.Y, 1.0f, 0.0f, 0.0f);
            glRotatef(360 - Camera.Angle.X, 0.0, 1.0f, 0.0f);
            glTranslatef(Camera.Pos.X, Camera.Pos.Y, Camera.Pos.Z);

            glLightfv(GL_LIGHT0+i, GL_POSITION, position);
        }
    }
}


Diese Funktion wird als allerstes bei jedem Rendervorgang ausgeführt.
Das Licht wird ohne Shader auch fehlerfrei angezeigt, egal wie meine Kameraposition/rotation ist.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 06, 2010 09:14 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
Ich habe mal einen Shader aus eurer Shader - Sammlung ausprobiert - sieht schon besser aus :D.
Dieser: http://wiki.delphigl.com/index.php/shader_PerPixelLighting
Nur funktioniert es bei mir leider nicht ganz so, wie es sein soll:

http://xyross.de/download/xy3.jpg

Wie man sieht ist das Licht rundlich abgehackt :/. Wenn ich meine Kamera weiter weg vom
Licht bewege ist mehr vom Licht zu sehen (Radius ist groeßer). Wie beim Shader beschrieben habe ich auch das
Licht mit glDisable(GL_LIGHTING) vor dem Aufruf dess Shaders deaktiviert.

Scheinbar muss ich wohl die Lichtquellenposition im Shader mit einer Matrix multiplizieren.
Aber wie und mit welcher?


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 06, 2010 10:16 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Wie beim Shader beschrieben habe ich auch das Licht mit glDisable(GL_LIGHTING) vor dem Aufruf dess Shaders deaktiviert.

Ähm, schalt das mal ein ;) Wäre möglich das die Aktivierung des Lichtes dafür sorgt das die Lichtquelle richtig transformiert wird.

Zitat:
Scheinbar muss ich wohl die Lichtquellenposition im Shader mit einer Matrix multiplizieren.
Aber wie und mit welcher?

gl_NormalMatrix müsste das für eine drektionale Lichtquelle sein. Anschließend das normalisieren nicht vergessen.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 06, 2010 10:26 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
Vertex - Shader:

Code:
varying vec3 v;
varying vec3 lightvec;
varying vec3 normal;
varying vec4 FrontColor;
 
void main(void) {

  normal         = normalize(gl_NormalMatrix * gl_Normal);
  v              = vec3(gl_ModelViewMatrix * gl_Vertex);

// ##### G E Ä N D E R T #####
  vec3 lightPos = gl_NormalMatrix * gl_LightSource[0].position.xyz;
  lightvec       = normalize(lightPos.xyz - v);
// #######################

  gl_TexCoord[0] = gl_MultiTexCoord0;
  FrontColor     = gl_Color;
 
  gl_Position    = gl_ModelViewProjectionMatrix * gl_Vertex;
}


Soll das so aussehen? Sorry, ich bin noch ziemlich neu in der Shader - Programmierung.
Will einfach nur das das mit der Lichtposition richtig hinhaut, denn ohne Licht kann man nicht
gerade die besten Shadereffekte erzielen :).

Also leider klappts immer noch nicht. Hab das OpenGL - Licht auch aktiviert, aber jetzt verfolgt mich das
Licht.... Also es is so, dass das Licht zwar abgeschwächt wird je weiter man sich von der Lichtquellenposition entfernt, aber das Licht ist nur in einem bestimmten Radius um die Kameraposition sichtbar, und der Licht - Radius wird immer groeßer, je weiter ich mich von der Lichtposition entferne. Hoffe du verstehst, was ich meine :) .


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 06, 2010 12:20 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
Ich hab jetzt mal ein bisschen rumprobiert und habe festgestellt, das es
garnix mit der Lichtposition zutun hat:

Fragment - Shader:
Code:
varying vec3 v;
varying vec3 lightvec;
varying vec3 normal;
varying vec4 FrontColor;
 
uniform sampler2D Texture0;
 
void main(void) {
  vec3 Eye       = normalize(-v);
  vec3 Reflected = normalize(reflect(-lightvec, normal));

  vec4 IAmbient  = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
  vec4 IDiffuse  = gl_LightSource[0].diffuse * dot(normal, lightvec) * gl_FrontMaterial.diffuse;


// ### H I E R ###
  vec4 ISpecular = gl_LightSource[0].specular * pow(dot(Reflected, Eye), gl_FrontMaterial.shininess) * gl_FrontMaterial.specular;
// ############
 
  gl_FragColor   = vec4((gl_FrontLightModelProduct.sceneColor + IAmbient + IDiffuse) * texture2D(Texture0, vec2(gl_TexCoord[0])) + ISpecular) + vec4(0,0,0,1);
}


Wenn ich statts der pow(...) - Funktion z.B. den Wert "1" eintrage, klappt alles wunderbar (Licht wird korrekt
dargestellt, auch wenn ich glDisable(GL_LIGHTING); verwende). Eigentlich ist das dann aber nicht korrekt, weil der Specular - Wert immer der selbe ist. Komischerweise sieht man da aber keinen Unterschied ob Specular jetzt
0 oder nen Maximalwert hat...

Jetzt is es aber ganz klar wo der Fehler liegt:

Fragment - Shader:
Code:
  vec3 Eye       = normalize(-v);
  vec3 Reflected = normalize(reflect(-lightvec, normal));


Im Vertex - Shader sind die Variablen wie folgt:
Code:
  normal = normalize(gl_NormalMatrix * gl_Normal);
  v = vec3(gl_ModelViewMatrix * gl_Vertex);

  vec3 aux;
  vec3 ecPos;
  ecPos = gl_ModelViewMatrix * gl_Vertex;
  aux = vec3(gl_LightSource[0].position - ecPos);

  lightvec = normalize(aux);


Weißt du vielleicht, wie das richtig sein soll? Wie gesagt, ich transformiere ohne gluLookAt, sondern z.B. so:

Code:
GLfloat position[] = { 0.0f, 0.0f, 0.0f, 1.0f };

glLoadIdentity();
glRotatef(Camera.Angle.Y, 1.0f, 0.0f, 0.0f);
glRotatef(360 - Camera.Angle.X, 0.0, 1.0f, 0.0f);
glTranslatef(Camera.Pos.X + Licht.Pos.X, Camera.Pos.Y + Licht.Pos.Y, Camera.Pos.Z + Licht.Pos.Z);

glLightfv(GL_LIGHT0+i, GL_POSITION, position);


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Jun 06, 2010 21:07 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Also es is so, dass das Licht zwar abgeschwächt wird je weiter man sich von der Lichtquellenposition entfernt, aber das Licht ist nur in einem bestimmten Radius um die Kameraposition sichtbar, und der Licht - Radius wird immer groeßer, je weiter ich mich von der Lichtposition entferne. Hoffe du verstehst, was ich meine :) .

Da dürfte dein Problem liegen. Der Shader ist für eine direktionale Lichtquelle, offensichtlich gibst du ihm aber eine Position wie für eine Punktlichtquelle ;)

Im Fall einer Punktlichtquelle musst du den Vektor von der Fragmentposition zur Lichtquelle berechnen.

Zitat:
Jetzt is es aber ganz klar wo der Fehler liegt:

Ja, siehe oben. Aus "-lightvec" muss dann ggf. auch einfach "lightvec" werden....wie gesagt bei mir ist lightvec die Richtung in die die direktionale Lichtquelle scheint.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 07, 2010 15:00 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
Also muss ich einfach nur die Direction von der Lichtquelle zum Fragment berechnen ?:

Code:
vec3 Reflected = normalize(reflect(lightDir, normal));


Wenn ja wie :( ?


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 07, 2010 15:17 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Du nimmst dir die Position vom Vertexshader und reichst sie dann an den Fragmentshader weiter.

Vertexshader:
Code:
// ...

varying vec3 position;

void main() {
   // ...

   position = vec3(gl_ModelViewMatrix * gl_Vertex);

   // ...
}


Fragmentshader:
Code:
varying vec3 position;

void main() {
   vec3 lightvec = normalize(gl_LightSource[0].position.xyz - position);

   // ...
}

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 07, 2010 15:36 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
Thx, aber das hab ich ja gehabt, aber ich brauch ja den Richtungswinkel, weil ich kein Directionslicht sondern ein
Punktlich habe.

Vertex:
Code:
varying vec3 pos;
varying vec3 normal;
varying vec4 color;
varying vec3 lightDistance;

void main(void) {
    normal = normalize(gl_NormalMatrix * gl_Normal);
    pos = vec3(gl_ModelViewMatrix * gl_Vertex);

    lightDistance = normalize(gl_LightSource[0].position - pos);
    color     = gl_Color;
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position    = gl_ModelViewProjectionMatrix * gl_Vertex;
}


Fragment:
Code:
varying vec3 pos;
varying vec3 lightDistance;
varying vec3 normal;
varying vec4 color;
uniform sampler2D Texture0;

void main(void) {
    vec3 Eye       = normalize(-pos);
    vec3 Reflected = normalize(reflect(lightDistance, normal));

    vec4 IAmbient  = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
    vec4 IDiffuse  = gl_LightSource[0].diffuse * dot(normal, lightDistance) * gl_FrontMaterial.diffuse;
    vec4 ISpecular = gl_LightSource[0].specular * pow(max(dot(Reflected, Eye), 0.0), gl_FrontMaterial.shininess) * gl_FrontMaterial.specular;

    gl_FragColor = vec4((gl_FrontLightModelProduct.sceneColor + IAmbient + IDiffuse) * texture2D(Texture0, vec2(gl_TexCoord[0])) + ISpecular);
    gl_FragColor.w = 1.0;
}


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 07, 2010 16:41 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Thx, aber das hab ich ja gehabt, aber ich brauch ja den Richtungswinkel, weil ich kein Directionslicht sondern ein
Punktlich habe.

Ups...hab ich irgendwie nicht gesehen. Jedenfalls damit das korrekt ist musst du den Lichtvektor im Fragmentshader berechnen, sonst könnte es Helligkeitsschwankungen geben, weil die Länge des Lichtvektors variiert. Auch könnte es Probleme bei der Interpolation geben wenn die Lichtquelle sehr nahe an deinem Dreieck bzw. das Dreieck sehr groß ist. Diese ganzen Effekte treten nur auf, wenn du Vektoren interpolierst => darum die Position interpolieren.

Wenn du den Lichtvektor einmal hast berechnet sich der Richtungswinkel (*) beim Punktlicht genauso wie beim Direktionslicht, also dot-Produkt.


(*) Streng genommen berechnest du hier nicht den Winkel sondern nur den Kosinus desselben.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 07, 2010 18:16 
Offline
DGL Member

Registriert: Sa Jun 05, 2010 16:15
Beiträge: 94
So, hoffe dass das jetzt die letzte Frage von mir is :D: Is das so richtig?

Fragment:
Code:
varying vec3 pos;
varying vec3 normal;
varying vec4 color;
uniform sampler2D Texture0;

void main(void) {
    vec3 lightDistance = normalize(gl_LightSource[0].position - pos);
    vec3 dir = dot(normalize(pos), lightDistance);
    vec3 Eye       = normalize(-pos);
    vec3 Reflected = normalize(reflect(-dir, normal));

    vec4 IAmbient  = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
    vec4 IDiffuse  = gl_LightSource[0].diffuse * dot(normal, lightDistance) * gl_FrontMaterial.diffuse;
    vec4 ISpecular = gl_LightSource[0].specular * pow(max(dot(Reflected, Eye), 0.0), gl_FrontMaterial.shininess) * gl_FrontMaterial.specular;

    gl_FragColor = vec4((gl_FrontLightModelProduct.sceneColor + IAmbient + IDiffuse) * texture2D(Texture0, vec2(gl_TexCoord[0])) + ISpecular);
    gl_FragColor.w = 1.0;
}


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 07, 2010 18:58 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Ich würd sagen sieht richtig aus, aber siehe meine Signatur ;)

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 07, 2010 20:01 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Aug 18, 2007 18:47
Beiträge: 694
Wohnort: Köln
Programmiersprache: Java
Hi,

du solltest im Fragment-Shader noch die Normale normalisieren.

Nebenbei: Varyings setze ich in der Regel immer ein V voraus. Damit ich immer gleich sehe woher die Variable kommt.
Also etwas wie:
Code:
vec3 normal = normalize(vNormal);

_________________
Es werde Licht.
glEnable(GL_LIGHTING);
Und es ward Licht.


Zitat aus einem Java Buch: "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off"

on error goto next


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 15 Beiträge ] 
Foren-Übersicht » Programmierung » Shader


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.009s | 15 Queries | GZIP : On ]