What is the word on using gl_NormalMatrix inside a fragment shader in OpenGL 2.0 ?
I am using NVIDIA Quadro FX 500 with 61.76 driver
gl_NormalMatrix does not seem to have any effect for transforming vectors or even points.
Any advice would be of help. Thanks!

**0**

# gl_NormalMatrix / gl_ModelViewMatrix inside Fragment shader ?

Started by dimensionX, Oct 07 2004 12:12 PM

7 replies to this topic

Sponsor:

###
#3
Members - Reputation: **100**

Posted 07 October 2004 - 01:34 PM

Fragment Shader:-

-----------------

uniform sampler2D decalTexture;

uniform sampler2D bumpMapTexture;

uniform samplerCube cubeMapTexture;

varying vec2 texCoord;

varying vec3 T, B, N;

varying vec3 V, L;

varying vec3 cmV;

void main(void)

{

T = normalize(T);

B = normalize(B);

N = normalize(N);

V = normalize(V);

L = normalize(L);

cmV = normalize(cmV);

vec3 view, light, half;

/* Transform V & L to tangent-space and compute half vector */

view.x = dot(T, V);

view.y = dot(B, V);

view.z = dot(N, V);

light.x = dot(T, L);

light.y = dot(B, L);

light.z = dot(N, L);

half = normalize(light + view);

/* Fetch the Decal color and tangent-space normal */

vec3 decal = vec3 (texture2D(decalTexture, texCoord));

vec3 normal = vec3 (texture2D(bumpMapTexture, texCoord));

normal.x = 2.0 * normal.x - 1.0;

normal.y = 2.0 * normal.y - 1.0;

normal.z = 2.0 * normal.z - 1.0;

/* Compute Diffuse and Specular components */

float ndotl = max(dot(normal, light), 0.0);

float ndoth = pow(max(dot(normal, half), 0.0), 60.0);

/* Transform normal from Tangent-space to World space */

vec3 t = vec3(T.x, B.x, N.x);

vec3 b = vec3(T.y, B.y, N.y);

vec3 n = vec3(T.z, B.z, N.z);

vec3 cmNormal;

cmNormal.x = dot(t, normal);

cmNormal.y = dot(b, normal);

cmNormal.z = dot(n, normal);

/* Transform normal from World space to cubemap space */

cmNormal = vec3 (gl_NormalMatrix * cmNormal);

cmNormal = normalize(cmNormal);

vec3 refVector = reflect(-cmV, cmNormal);

vec3 refColor = vec3 (textureCube(cubeMapTexture, refVector));

vec3 fColor;

fColor.x = ndotl * (decal.x + refColor.x) + ndoth;

fColor.y = ndotl * (decal.y + refColor.y) + ndoth;

fColor.z = ndotl * (decal.z + refColor.z) + ndoth;

gl_FragColor = vec4 (vec3(fColor), 1.0);

}

----------------------------------------------------------------

I implemented the same method using ARB Vertex/fragment programs and it works perfectly.

The reason I declared T, B, N as varying is because I am not able to fetch the BumpMap normal inside the vertex shader.

I tested the rest of the stuff like (diffuse, specular, bumpshading) by changing the argument fColor in the last statment:

gl_FragColor = vec4 (vec3(fColor), 1.0);

to ndotl, ndoth respectively.

I tried using gl_NormalMatrix, glModelViewMatrix and even glTextureMatrix[0] (by loading the Inverse of the modelview transform into the texture unit 0 texture matrix stack). All gave the same effect no change.

Any clue would of great help, Thank you!

---------------------------------------------------------------

Below is the vertex and fragment shader for cube environment mapping which works perfectly.

Vertex Shader:-

---------------

varying vec3 N;

varying vec3 V;

void main(void)

{

gl_Position = ftransform();

vec3 vertex = vec3 (gl_ModelViewMatrix * gl_Vertex);

V = normalize(-vertex);

N = vec3 (gl_NormalMatrix * gl_Normal);

}

Fragment Shader:-

------------------

uniform samplerCube cubeMapTexture;

varying vec3 N;

varying vec3 V;

void main(void)

{

vec3 view = normalize(V);

vec3 normal = normalize(N);

vec3 refVector = reflect(-view, normal);

vec3 refColor = vec3 (textureCube(cubeMapTexture, refVector));

gl_FragColor = vec4 (vec3(refColor), 1.0);

}

----------------------------------------------------------------

-----------------

uniform sampler2D decalTexture;

uniform sampler2D bumpMapTexture;

uniform samplerCube cubeMapTexture;

varying vec2 texCoord;

varying vec3 T, B, N;

varying vec3 V, L;

varying vec3 cmV;

void main(void)

{

T = normalize(T);

B = normalize(B);

N = normalize(N);

V = normalize(V);

L = normalize(L);

cmV = normalize(cmV);

vec3 view, light, half;

/* Transform V & L to tangent-space and compute half vector */

view.x = dot(T, V);

view.y = dot(B, V);

view.z = dot(N, V);

light.x = dot(T, L);

light.y = dot(B, L);

light.z = dot(N, L);

half = normalize(light + view);

/* Fetch the Decal color and tangent-space normal */

vec3 decal = vec3 (texture2D(decalTexture, texCoord));

vec3 normal = vec3 (texture2D(bumpMapTexture, texCoord));

normal.x = 2.0 * normal.x - 1.0;

normal.y = 2.0 * normal.y - 1.0;

normal.z = 2.0 * normal.z - 1.0;

/* Compute Diffuse and Specular components */

float ndotl = max(dot(normal, light), 0.0);

float ndoth = pow(max(dot(normal, half), 0.0), 60.0);

/* Transform normal from Tangent-space to World space */

vec3 t = vec3(T.x, B.x, N.x);

vec3 b = vec3(T.y, B.y, N.y);

vec3 n = vec3(T.z, B.z, N.z);

vec3 cmNormal;

cmNormal.x = dot(t, normal);

cmNormal.y = dot(b, normal);

cmNormal.z = dot(n, normal);

/* Transform normal from World space to cubemap space */

cmNormal = vec3 (gl_NormalMatrix * cmNormal);

cmNormal = normalize(cmNormal);

vec3 refVector = reflect(-cmV, cmNormal);

vec3 refColor = vec3 (textureCube(cubeMapTexture, refVector));

vec3 fColor;

fColor.x = ndotl * (decal.x + refColor.x) + ndoth;

fColor.y = ndotl * (decal.y + refColor.y) + ndoth;

fColor.z = ndotl * (decal.z + refColor.z) + ndoth;

gl_FragColor = vec4 (vec3(fColor), 1.0);

}

----------------------------------------------------------------

I implemented the same method using ARB Vertex/fragment programs and it works perfectly.

The reason I declared T, B, N as varying is because I am not able to fetch the BumpMap normal inside the vertex shader.

I tested the rest of the stuff like (diffuse, specular, bumpshading) by changing the argument fColor in the last statment:

gl_FragColor = vec4 (vec3(fColor), 1.0);

to ndotl, ndoth respectively.

I tried using gl_NormalMatrix, glModelViewMatrix and even glTextureMatrix[0] (by loading the Inverse of the modelview transform into the texture unit 0 texture matrix stack). All gave the same effect no change.

Any clue would of great help, Thank you!

---------------------------------------------------------------

Below is the vertex and fragment shader for cube environment mapping which works perfectly.

Vertex Shader:-

---------------

varying vec3 N;

varying vec3 V;

void main(void)

{

gl_Position = ftransform();

vec3 vertex = vec3 (gl_ModelViewMatrix * gl_Vertex);

V = normalize(-vertex);

N = vec3 (gl_NormalMatrix * gl_Normal);

}

Fragment Shader:-

------------------

uniform samplerCube cubeMapTexture;

varying vec3 N;

varying vec3 V;

void main(void)

{

vec3 view = normalize(V);

vec3 normal = normalize(N);

vec3 refVector = reflect(-view, normal);

vec3 refColor = vec3 (textureCube(cubeMapTexture, refVector));

gl_FragColor = vec4 (vec3(refColor), 1.0);

}

----------------------------------------------------------------

###
#4
Crossbones+ - Reputation: **1944**

Posted 07 October 2004 - 06:55 PM

Quote:

Original post by dimensionX

What is the word on using gl_NormalMatrix inside a fragment shader in OpenGL 2.0 ?

not really a help because its nothing official, but.. expecting the normal and modelview to be applied to vertices and not fragment i wouldnt see why they should even be around at the fragment stage?

###
#5
Members - Reputation: **100**

Posted 08 October 2004 - 02:20 AM

The orange book (OpenGL Shading Language) says it can be accessed and used in both the vertex and fragment shaders.

So if I can't access texture units inside a vertex shader and gl_normalMatrix does not have any effect inside the fragment shader, how do I get to implement my reflective bump mapping ?

I guess the only way is to send the gl_NormalMatrix from the application to tha gragment program as a uniform variable.

Did NVIDIA comment on this anywhere ?

Thanks!

So if I can't access texture units inside a vertex shader and gl_normalMatrix does not have any effect inside the fragment shader, how do I get to implement my reflective bump mapping ?

I guess the only way is to send the gl_NormalMatrix from the application to tha gragment program as a uniform variable.

Did NVIDIA comment on this anywhere ?

Thanks!

###
#6
Members - Reputation: **432**

Posted 08 October 2004 - 03:12 AM

gl_NormalMatrix is a built-in variable in glsl. Take a look at section 7.5 of the OpenGL shading language specification.

gl_NormalMatrix is the inverse transpose of the upper 3x3 part of the modelview matrix.

gl_NormalMatrix is the inverse transpose of the upper 3x3 part of the modelview matrix.

###
#8
Members - Reputation: **432**

Posted 09 October 2004 - 04:43 AM

I'm sorry, I should probably have read your post more thoroughly first...

I have a radeon 9600, and use RenderMonkey for coding GLSL shaders all the time. I consistently use gl_NormalMatrix, and there's no problem...

Here's some code that does per-pixel Phong shading:

Vertex shader:

Fragment shader:

Here gl_NormalMatrix is used to transform the normal vectors in the vertex shader. If you remove gl_NormalMatrix, you're going to get some weird and wrong results. Why don't you try it?

I have a radeon 9600, and use RenderMonkey for coding GLSL shaders all the time. I consistently use gl_NormalMatrix, and there's no problem...

Here's some code that does per-pixel Phong shading:

Vertex shader:

/* Author: James D. Trotter

29/09-2004

Phong illumination program

--------------------------

http://en.wikipedia.org/wiki/Phong_shading

The vertex shader transforms the

vertex-normal by the inverse

transpose of the modelview

matrix, so that the normal

is in world-space.

The eye-space vector from the

light to the vertex is trans-

formed into world-space, and

sent to the fragment shader.

The eye-space vector from the

vertex to the camera, (the

negative vertex coordinate,

since the camera is at the

origin in eye-space), is

transformed into world-space,

so that it can be used to

calculate the specular light

component in the fragment shader.

*/

// Position of the point-light

uniform vec4 lightPosition;

// Values interpolated across the polyogon

varying vec3 normal; // Vertex-normal

varying vec3 viewVec; // World-space view vector

varying vec3 lightVec; // World-space light vector

void main(void) {

// Get the vertex normal, transformed

// by the inverse transpose of the

// modelview-matrix

normal = gl_NormalMatrix * gl_Normal;

// Get the world-space vector

// from the light to the vertex.

vec4 lightToVertex = lightPosition - gl_Vertex;

lightVec = (gl_ModelViewMatrix * lightToVertex).xyz;

// Get the world-space vector from

// the vertex to the camera.

viewVec = (gl_ModelViewMatrix * gl_Vertex).xyz;

// Perform vertex transformations.

gl_Position = ftransform();

}

Fragment shader:

/* Author: James D. Trotter

29/09-2004

Phong illumination program:

---------------------------

http://en.wikipedia.org/wiki/Phong_shading

Using the interpolated vertex normal,

lighting is calculated according to

the phong illumination or reflection

model. All three lighting components -

diffuse, ambient, and specular - are

taken into account:

Diffuse: L.N

where L is the tangent-space

vector from the light to the

vertex. And N is the

(interpolated) fragment normal.

Specular: pow(R.V, n)

where R is the reflected light

vector around the normal N.

V is the tangent-space vector

from the vertex to the viewer.

n indicates the surface reflectivity.

Ambient: The ambient term is added to

give general illumination. This

is needed because diffuse and

specular only accurately give

local lighting conditions.

*/

// Values interpolated across the polyogon

varying vec3 normal; // Vertex-normal

varying vec3 viewVec; // World-space view vector

varying vec3 lightVec; // World-space light vector

// Light properties

uniform vec4 Ii; // Light brightness

uniform vec4 Ia; // Ambient light term

// Surface properties

uniform vec4 Kd; // Reflection coefficient

uniform vec4 Ks; // Specular coefficient

uniform vec4 Ka; // Ambient coefficient

uniform float n; // Surface reflectivity

void main(void) {

// Normalize incoming vectors

vec3 L = normalize(lightVec);

vec3 V = normalize(viewVec);

// Calculate the diffuse component

vec4 Id = Kd * max(dot(L, normal), 0.0);

// Calculate reflection vector

vec3 R = normalize(reflect(L, normal));

// Calculate the specular component

vec4 Is = Ks * pow(max(dot(R, V), 0.0), n);

// Add the components together

gl_FragColor = Ia * Ka + Ii * (Id + Is);

}

Here gl_NormalMatrix is used to transform the normal vectors in the vertex shader. If you remove gl_NormalMatrix, you're going to get some weird and wrong results. Why don't you try it?