ZFX
ZFX Neu
Home
Community
Neueste Posts
Chat
FAQ
IOTW
Tutorials
Bücher
zfxCON
ZFXCE
Mathlib
ASSIMP
NES
Wir über uns
Impressum
Regeln
Suchen
Mitgliederliste
Membername:
Passwort:
Besucher:
4381895
Jetzt (Chat):
23 (0)
Mitglieder:
5239
Themen:
24223
Nachrichten:
234554
Neuestes Mitglied:
-insane-

ZFX
Coding-Foren
OpenGL API + SDL
Normal Mapping
Normal
AutorThema
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Normal MappingNach oben.
Hi,
ich beschäftige mich gerade mit Normal Mapping in GLSL. So wie ich das verstanden habe werden die Normale anhand der Normal-Textur berechnet (Binormal, Tangent). ich habe bei Typhoon-Labs einen Shader gefunden, der das Normal-Mapping anscheinend komplett ohne diese beidenVektoren macht:
Vertex-Shader
Code:
varying vec3        V;            // eye direction in eye frame
varying vec3        L;            // light direction from vertex to light center in eye frame
varying vec3        N;            // normal in eye frame

void main(void)
{
    // vertex position in eye frame
    vec4 P = gl_ModelViewMatrix * gl_Vertex;
    
    V = normalize(-P.xyz);
    L = normalize(gl_LightSource[0].position.xyz - P.xyz);
    N = normalize(gl_NormalMatrix * gl_Normal);

    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
}


Fragment-Shader
Code:
uniform sampler2D        colorMap;
uniform sampler2D        normalMap;

varying vec3            L;
varying vec3            N;
varying vec3            V;

void main(void)
{
    vec2 tcoord = gl_TexCoord[0].st;
    
    vec3 n = 2.0 * texture2D(normalMap, tcoord).xyz - 1.0;
    vec3 R = -normalize(reflect(L, n));
    
    vec4 color = texture2D(colorMap, tcoord);
    vec4 ambient = color * gl_FrontLightProduct[0].ambient;
    vec4 diffuse = color * gl_FrontLightProduct[0].diffuse * max(dot(n, L), 0.0);
    vec4 specular = gl_FrontLightProduct[0].specular * pow(max(dot(R, V), 0.0), gl_FrontMaterial.shininess);

    gl_FragColor = diffuse + specular + ambient;
}


Kann mir jemand erklären, wie das funktioniert??
25.04.2008, 11:02:57 Uhr
Schrompf Offline
ZFX'ler


Registriert seit:
04.04.2006

Sachsen
Re: Normal MappingNach oben.
Der Shader sieht für mich wie Unsinn aus. Der VertexShader berechnet die Vertex-Normale angeblich in Eye Space, aber der Vektor wird im Fragmentshader gar nicht verwendet. Stattdessen wird dort einfach nur die Normale aus der Normal Map gelesen und direkt für die Lichtberechnung verwendet. Das geht gut, wenn die Normalen in der Normal Map des Modells in Model Space gegeben sind, aber es versagt, sobald das Objekt auf irgendeine Art verdreht wird.
25.04.2008, 11:49:08 Uhr
Dreamworlds Development
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.
Ich werde da auch nicht schlau draus, seltsamerweise sieht das Ergebnis gut aus:
http://wr-media.net/tmp/normal.png
25.04.2008, 11:58:19 Uhr
Ingrater Offline
ZFX'ler


Registriert seit:
18.04.2007

Baden-Württemberg
Re: Normal MappingNach oben.
Joa in der Shader IDE mag das funktionieren, in deiner Anwendung wird das allerdings nicht wirklich gehen. Schau dir mal die Beispiele an die bei ATI's Rendermonkey dabei sind, die sind meiner Meinung nach sehr gut, wenn acuh die Variablennamen teilweise Gewöhnungsbedürftig sind (ungarische Notation oder sowas)
25.04.2008, 14:57:09 Uhr
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.
Die Abbildung ist aus meiner Anwendung.
25.04.2008, 14:59:33 Uhr
Ingrater Offline
ZFX'ler


Registriert seit:
18.04.2007

Baden-Württemberg
Re: Normal MappingNach oben.
Was passiert wenn du die Kugel drehst? Auf jeden fall ist das auf keinen Fall auch nur ein Annährend korrekter Normal Mapping Shader.

Wenn du dann mal ein bisschen weiter gehen willst und z.b. Parallax Mapping implementieren willst, oder sogar Parallax Occlusion Mapping brauchst du die Binormale und Tangente sowieso.
25.04.2008, 15:05:49 Uhr
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.
Selbst wenn sich die Kugel dreht, scheint alles in Ordnung zu sein (soweit ich das sehe).
Ich weiß das ich die beiden Vektoren brauche, ich weiß nur nicht warum der Shader anscheinend auch ohne funktioniert
25.04.2008, 15:12:45 Uhr
Schrompf Offline
ZFX'ler


Registriert seit:
04.04.2006

Sachsen
Re: Normal MappingNach oben.
Der Shader funktioniert anscheinend schon auf Deinem Bild nicht. Das Licht beleuchtet die Kacheln immer von links, obwohl die Kacheln weiter links auf der Kugel doch von rechts beleuchtet werden sollen. Sieht für mich also danach aus, als würdest Du diesen (fehlerhaften) World Space Normal Mapping-Shader mit einer Tangent Space Normal Map benutzen. Das eine ist eine Textur, in der die Normalen im Koordinatensystem des Objektes drinstehen. Die Normalen darin zeigen also tatsächlich nach links/oben/rechts/unten/hinten/vorn... usw. In einer Tangent Space Normal Map sind alle Normalen im Tangent Space, wie der Name schon sagt. D.h. die Normalen sind relativ zur Oberfläche, sie zeigen immer in Richtung Z+ mit Neigungen in Richtung +-X und +-Y. Wenn die Normal Map dieser Kacheltextur im Bildbetrachter hellblau mit rot/grünen Kachelmuster aussieht, dann ist es eine Tangent Space Normal Map.
25.04.2008, 15:24:57 Uhr
Dreamworlds Development
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.

Das sind die Texturen
http://wr-media.net/tmp/normal_map.png
http://wr-media.net/tmp/color_map.png
25.04.2008, 15:39:25 Uhr
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.
Ich hab jetzt mal meinen eigenen Shader zusammengebaut
http://wr-media.net/tmp/normal2.png


Vertex
Code:
varying vec3 halfAngle;
varying vec3 lightDirection;

void main()
{
    vec3 normal = gl_Normal;
    vec3 tangent = gl_MultiTexCoord1.xyz;
    vec2 texcoord = gl_MultiTexCoord0.st;

    //Lighting
    vec4 position = gl_ModelViewMatrix * gl_Vertex;
    normal = gl_NormalMatrix * normalize(normal);
    tangent = gl_NormalMatrix * normalize(tangent);
    vec3 binormal = cross(normal, tangent);
    mat3 textureSpaceMatrix = mat3(tangent, binormal, normal);

    vec3 lightPosition = gl_LightSource[0].position.xyz;
    vec3 eyeDirection = textureSpaceMatrix * normalize(-position.xyz);
    lightDirection = textureSpaceMatrix*normalize(lightPosition-position.xyz);
    halfAngle = normalize(eyeDirection+lightDirection);

    gl_Position = ftransform();
    gl_TexCoord[0].st = texcoord*vec2(1.0, -2.0);
}



Fragment:
Code:
uniform sampler2D normalMap;
uniform sampler2D colorMap;

varying vec3 halfAngle;
varying vec3 lightDirection;

void main()
{
    vec3 normal = texture2D(normalMap, gl_TexCoord[0].st).xyz;
    normal = vec3(2.0)*(normal-vec3(0.5));
    
    vec4 ambient = gl_FrontLightProduct[0].ambient;
    vec4 diffuse = gl_FrontLightProduct[0].diffuse *max(dot(normal, lightDirection), 0.0);
    vec4 specular = gl_FrontLightProduct[0].specular * pow(max(dot(normal, halfAngle), 0.0), gl_FrontMaterial.shininess);
    vec4 diffuseColor = texture2D(colorMap, gl_TexCoord[0].st);
    
    gl_FragColor = diffuseColor* (ambient+diffuse+specular);
}



Ganz zufrieden bin ich nicht, irgendwie scheint noch was nicht zu stimmen.
25.04.2008, 15:48:50 Uhr
Schrompf Offline
ZFX'ler


Registriert seit:
04.04.2006

Sachsen
Re: Normal MappingNach oben.
Du musst auch den halfAngle durch die tangentSpaceMatrix jagen. Und ich empfehle, lightDirection und halfAngle im Pixelshader zu renormalisieren. Im VertexShader kannst Du Dir das dann sparen. Der Specular-Term wird üblicherweise nicht mit der Texturfarbe multipliziert, sondern getrennt addiert.
25.04.2008, 16:00:05 Uhr
Dreamworlds Development
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.
Danke für den Tipp, meintest Du so:
Code:
varying vec3 halfAngle;
varying vec3 lightDirection;

void main()
{
    vec3 normal = gl_Normal;
    vec3 tangent = gl_MultiTexCoord1.xyz;
    //vec2 texcoord = gl_MultiTexCoord0.st;

    //Lighting
    vec4 position = gl_ModelViewMatrix * gl_Vertex;
    normal = gl_NormalMatrix * normalize(normal);
    tangent = gl_NormalMatrix * normalize(tangent);
    vec3 binormal = cross(normal, tangent);
    mat3 textureSpaceMatrix = mat3(tangent, binormal, normal);

    vec3 lightPosition = gl_LightSource[0].position.xyz;
    vec3 eyeDirection = textureSpaceMatrix * normalize(-position.xyz);
    //lightDirection = textureSpaceMatrix*normalize(lightPosition-position.xyz);
    lightDirection = textureSpaceMatrix*(lightPosition-position.xyz);

    halfAngle = eyeDirection+lightDirection;
    //halfAngle = normalize(eyeDirection+lightDirection);
    halfAngle = textureSpaceMatrix*halfAngle;

    // Textur-Koordinaten
    gl_TexCoord[0] = gl_MultiTexCoord0;
    
    // Vertex transformieren
    gl_Position = ftransform();
}


Fragment
Code:
uniform sampler2D normalMap;
uniform sampler2D colorMap;

varying vec3 halfAngle;
varying vec3 lightDirection;

void main()
{
    vec3 lightDir = normalize(lightDirection);
    vec3 halfA = normalize(halfAngle);
    
    vec3 normal = texture2D(normalMap, gl_TexCoord[0].st).xyz;
    normal = vec3(2.0)*(normal-vec3(0.5));
    
    vec4 ambient = gl_FrontLightProduct[0].ambient;
    vec4 diffuse = gl_FrontLightProduct[0].diffuse *max(dot(normal, lightDir), 0.0);
    vec4 specular = gl_FrontLightProduct[0].specular * pow(max(dot(normal, halfA), 0.0), gl_FrontMaterial.shininess);
    vec4 diffuseColor = texture2D(colorMap, gl_TexCoord[0].st);
    
    gl_FragColor = diffuseColor* (ambient+diffuse)+specular;
}

25.04.2008, 16:13:36 Uhr
Aramis Offline
ZFX'ler


Registriert seit:
14.03.2007

Baden-Württemberg
406712329
Re: Normal MappingNach oben.
Ahoi,

IMHO wird im Normalfall auch nicht die Materialgrundfarbe mit der Texturfarbe verrechnet. ich bin mir da aber gerade nicht sonderlich sicher. Der Grund ist dass viele Modeller es erlauben auf alle 4 "Farbtypen" (Ambient, Diffuse, Specular, Emissive) eine separate Textur zu legen. Und üblicherweise wird dann ausschließlich der Diffuseslot benutzt ... (auch wenn er bei 3ds Max bespielsweise so halb gekoppelt ist mit dem Ambientslot)

Code:
gl_FragColor = diffuseColor*diffuse + specular + ambient;


MfG
Aramis

1 Mal gendert, zuletzt am 25.04.2008, 16:43:54 Uhr von Aramis.
25.04.2008, 16:42:39 Uhr
Schrompf Offline
ZFX'ler


Registriert seit:
04.04.2006

Sachsen
Re: Normal MappingNach oben.
Hier in dem Fall wäre es doch schlauer, ambient und diffuse zusammenzufassen.

Jetzt transformierst Du einmal eyeDirection mit der Matrix und dann nochmal den halfAngle. Und das gerade mal 10 Minuten, nachdem ich meinen Beitrag abgesetzt hatte. Sachmal... probierst Du überhaupt aus, was Du da tust. Und denkst Du vorher auch mal nach? Du weißt, in welchem Koordinatenraum Dein eyeVector gegeben ist. Du weißt, in welchem Koordinatenraum die lightDirection gegeben ist. Du musst beide im gleichen Koordinatenraum haben, um sie miteinander verrechnen zu können, und Du musst sie am Ende in Tangentenkoordinaten konvertieren. Such Dir aus, in welcher Reihenfolge Du es haben willst.
25.04.2008, 17:00:26 Uhr
Dreamworlds Development
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.
Zitat von Schrompf:
Hier in dem Fall wäre es doch schlauer, ambient und diffuse zusammenzufassen.

Jetzt transformierst Du einmal eyeDirection mit der Matrix und dann nochmal den halfAngle. Und das gerade mal 10 Minuten, nachdem ich meinen Beitrag abgesetzt hatte. Sachmal... probierst Du überhaupt aus, was Du da tust. Und denkst Du vorher auch mal nach? Du weißt, in welchem Koordinatenraum Dein eyeVector gegeben ist. Du weißt, in welchem Koordinatenraum die lightDirection gegeben ist. Du musst beide im gleichen Koordinatenraum haben, um sie miteinander verrechnen zu können, und Du musst sie am Ende in Tangentenkoordinaten konvertieren. Such Dir aus, in welcher Reihenfolge Du es haben willst.


Yo, immer langsam, man kann sich doch wohl mal vertun oder.


Der erste Ansatz war dann nähmlich richtig;
Code:
vec3 eyeDirection = textureSpaceMatrix * normalize(-position.xyz);
    lightDirection = textureSpaceMatrix*normalize(lightPosition-position.xyz);
    halfAngle = normalize(eyeDirection+lightDirection);

Mit dem Unterschied, dass der halfAngle, erst später normalisiert wird.
Code:
vec3 eyeDirection = textureSpaceMatrix * normalize(-position.xyz);
    lightDirection = textureSpaceMatrix*normalize(lightPosition-position.xyz);
    halfAngle =eyeDirection+lightDirection;

25.04.2008, 17:37:00 Uhr
Schrompf Offline
ZFX'ler


Registriert seit:
04.04.2006

Sachsen
Re: Normal MappingNach oben.
Zitat von wolf_10:

Der erste Ansatz war dann nähmlich richtig;


Ja, da hast Du Recht, das hatte ich übersehen. Ich bitte um Entschuldigung.
25.04.2008, 17:45:36 Uhr
Dreamworlds Development
wolf_10 Offline
ZFX'ler


Registriert seit:
18.10.2002

Baden-Württemberg
Re: Normal MappingNach oben.
Zitat von Schrompf:
Zitat von wolf_10:

Der erste Ansatz war dann nähmlich richtig;


Ja, da hast Du Recht, das hatte ich übersehen. Ich bitte um Entschuldigung.


Kein Prob.
Ne kurze Frage hätte ich noch. Ich hab grad noch probiert das Licht um die Kugel zu rotieren, dabei ist mir aufgefallen, das ich so keinen weichen Übergang zwischen beleuchtet und unbeleuchtet hinkriege. Wenn Das Licht seitlich von der Kugel ist, wird die auf einmal dunkler und wenn es hinter der Kugel ist, wird sie komplett schwarz (auch auf einmal).

Hat noch jemand nen Tipp?
25.04.2008, 19:11:57 Uhr
Normal


ZFX Community Software, Version 0.9.1
Copyright 2002-2003 by Steffen Engel