PDA

View Full Version : Scaling problem

capedica
05-23-2005, 09:34 AM
Hi,
in many shaders i use inverse model view matrix (matrix with translation,rotation and scaling) and all goes right if i translate or rotate my mesh, but if i trie to scale it, lighting doesn't function, someone knows why? maybe it's a common problem...

Humus
05-23-2005, 04:08 PM
Are you using gl_NormalMatrix for your normal? In that case, you'll have to renormalize the normal if you're scaling your modelview matrix.

Java Cool Dude
05-23-2005, 05:11 PM
As Humus has pointed out, use the gl_NormalMatrix in your vertex shader to generate the eye space normal

varying vec3 eyeSpaceNormal;
.
.
.
eyeSpaceNormal = gl_NormalMatrix*gl_Normal;
.
.
.
Then normalize it in your fragment shader.
Peace.

Relic
05-23-2005, 11:38 PM
He didn't say he's doing per fragment lighting. If not, you only need to normalize it in the vertex shader before your per vertex lighting calculations.

capedica
05-24-2005, 05:22 AM
In my shader (per-pixl lighting) i build my tangent space with normal,tangent and binormal:

.......
varying vec3 light_coord;
varying vec3 eye_coord;
....
mat3 mat = mat3(tangent, binormal, gl_Normal);
light_coord = (light_pos_world.xyz - gl_Vertex.xyz) * mat;

eye_coord = (eye_pos_world.xyz - gl_Vertex.xyz) * mat;
.....Have i to multiply gl_Normal for gl_NormalMatrix? and tangent and binormal too?
(This shader is correct if i don't scale the mesh, if i scale it lighting is not so correct.
Thank you very much

Relic
05-24-2005, 05:40 AM
This is inside the vertex shader.

This looks incorrect for two reasons.
You use the object coordinates (gl_Vertex) to calculate your lighting setup.
Lighting is normally done in world space.
Your code is not working if your modelview matrix has any rotation or scale in it.

Two ways to fix that. Either bring your light into modelspace and calculate there then you can use gl_Vertex and the normals as they are, or bring coordinates and lights into eye space (gl_ModelViewMatrix) and multiply the normal space with the gl_NormalMatrix.

Something like this:
mat3 mat = mat3(normalize(gl_NormalMatrix * tangent),
normalize(gl_NormalMatrix * binormal),
normalize(gl_NormalMatrix * gl_Normal));

The other names are a little confusing to say what you intended, e.g. eye_pos_world doesn't sound to be in the same coordinate system as gl_Vertex.

In general, do not post excerpts of shader code only, very often the important parts are missing.

capedica
05-24-2005, 06:21 AM
ok ,this is the complete shader taken from a demo on web: it realize parallax mapping:

[VERTEX SHADER]
// VERTSHADER.GLS
// Copyright (C) 2004-2005 by Nathan Reed. All rights and priveleges reserved.
// Vertex shader for the shaders program. This calculates per-vertex lighting data,
// to be consumed by the companion fragment program.

// INPUTS
uniform vec3 lightPosition0_obj; // Light position in world
//uniform vec3 lightPosition1;

uniform vec3 cameraPosition_obj; // Eye position in world
uniform vec2 lightRadius; // Radius of light

//attribute vec3 tangent, binormal; // Tangent and binormal vectors on the surface (in world space)
// gl_MultiTexCoord0
// gl_Normal
// gl_Vertex
// gl_ModelViewProjectionMatrix

// OUTPUTS
varying vec3 light_coord[2]; // vector to light in tangent space
varying vec3 eye_coord; // vector to eye in tangent space
varying vec3 attentuation_coord[2]; // light location, pre-divided by light radius
// gl_TexCoord[0]
// gl_Position

void main ()
{
vec3 cameraPosition = vec3(cameraPosition_obj);
vec3 lightPosition0 = vec3(lightPosition0_obj);

vec3 tangent = vec3(gl_MultiTexCoord3[0],gl_MultiTexCoord3[1],gl_MultiTexCoord3[2]);
vec3 binormal = vec3(-gl_MultiTexCoord4[0],-gl_MultiTexCoord4[1],-gl_MultiTexCoord4[2]);
//vec3 tangent = vec3(1.0,0.0,0.0);
//vec3 binormal = vec3(0.0,0.0,1.0);
float light_radius[2];
light_radius[0] = lightRadius[0];
light_radius[1] = lightRadius[1];

vec4 light_pos_world[2];
light_pos_world[0] = vec4(lightPosition0[0],lightPosition0[1],lightPosition0[2],1.0);
light_pos_world[1] = vec4(100.0,5.0,10.0,1.0);//lightPosition1[0],lightPosition1[1],lightPosition1[2],1.0);
vec4 eye_pos_world = vec4(cameraPosition[0],cameraPosition[1],cameraPosition[2],1.0);
// Copy through texture coordinates
gl_TexCoord[0] = gl_MultiTexCoord0;

// Calculate world-to-tangent matrix
// NOTE: matrix indices are transposed in glslang, so we construct the matrix with the reverse convention,
// and then when we use it, we do the multiplication in the reverse order.
mat3 w2t = mat3(tangent, binormal, gl_Normal);

// Calculate vector from vertex to light in tangent space
light_coord[0] = (light_pos_world[0].xyz - gl_Vertex.xyz) * w2t;
light_coord[1] = (light_pos_world[1].xyz - gl_Vertex.xyz) * w2t;

// Calculate vector from vertex to eye in tangent space
eye_coord = (eye_pos_world.xyz - gl_Vertex.xyz) * w2t;

// Calculate "attentuation coordinates" - light vector divided by light radius
attentuation_coord[0] = light_coord[0] / light_radius[0];
attentuation_coord[1] = light_coord[1] / light_radius[1];

// Same modelview/projection transform as in fixed function pipeline
gl_Position = ftransform();
}
[FRAGMENT SHADER]
// FRAGSHADER.GLS
// Copyright (C) 2004-2005 by Nathan Reed. All rights and priveleges reserved.
// Fragment shader for the shaders program. This evaluates the lighting equation at each pixel.

uniform sampler2D diffuse_map;
uniform sampler2D bump_map;
uniform sampler2D height_map;

//uniform vec4 light_color0;
//uniform vec4 light_color1;
// rgb light color
uniform vec4 ambient_color; // rgb ambient color

varying vec3 light_coord[2]; // light location in tangent space
varying vec3 eye_coord; // eye location in tangent space
varying vec3 attentuation_coord[2]; // light location, pre-divided by light radius

const float height_scale = 0.04; // scale and bias for the height map
const float height_bias = -height_scale / 2.0;
const float specular_exponent = 64.0;
const float specular_factor = 0.3;

// Function to unpack a unit vector from a texture
vec3 unpack_vector (vec4 v)
{
return v.xyz * 2.0 - 1.0;
}

void main ()
{
vec4 light_color[2];
light_color[0] = vec4(0.5,0.5,0.5,1.0);
light_color[1] = vec4(0.5,0.5,0.5,1.0);

// Normalize light and eye vectors
vec3 light_coord_normalized[2];
light_coord_normalized[0] = normalize(light_coord[0]);
light_coord_normalized[1] = normalize(light_coord[1]);
vec3 eye_coord_normalized = normalize(eye_coord);

// Sample height map (in alpha channel of bump map) and scale it to world coordinates
//vec4 sample = texture2D(bump_map, gl_TexCoord[0].xy);
//vec3 sample_normal = unpack_vector(sample);
//float height = sample.a * height_scale + height_bias;
vec4 sample = texture2D(height_map, gl_TexCoord[0].xy);
vec3 sample_normal = unpack_vector(sample);
float height = sample.a * height_scale + height_bias;

// Estimate parallax offset for looking up normal and diffuse coordinates
vec2 tex_coord = gl_TexCoord[0].xy + (eye_coord_normalized.xy * height * sample_normal.z);

// Unpack the normal from the normal map (in RGB of bump map)
vec3 normal = normalize(unpack_vector(texture2D(bump_map, tex_coord)));

// Lookup diffuse texture value
vec4 texture = texture2D(diffuse_map, tex_coord);

// Dot normal with light position
float cosine[2];
cosine[0] = max(dot(normal, light_coord_normalized[0]), 0.0);
cosine[1] = max(dot(normal, light_coord_normalized[1]), 0.0);

// Calculate attentuation factor as 1 - (r / light_radius)^2
float attentuation[2];
attentuation[0] = max(1.0 - dot(attentuation_coord[0], attentuation_coord[0]), 0.0);
attentuation[1] = max(1.0 - dot(attentuation_coord[1], attentuation_coord[1]), 0.0);

// Calculate half-angle vector
vec3 halfangle[2];
halfangle[0] = normalize(light_coord_normalized[0] + eye_coord_normalized);
halfangle[1] = normalize(light_coord_normalized[1] + eye_coord_normalized);

// Calculate specular factor
float specular[2];
specular[0] = pow(max(dot(normal, halfangle[0]), 0.0), specular_exponent);
specular[1] = pow(max(dot(normal, halfangle[1]), 0.0), specular_exponent);

// Calculate final fragment color
vec4 light_contrib[2];
light_contrib[0] = light_color[0] * attentuation[0] * (texture * cosine[0] + specular_factor * specular[0]);
light_contrib[1] = light_color[1] * attentuation[1] * (texture * cosine[1] + specular_factor * specular[1]);
gl_FragColor = texture * ambient_color + light_contrib[0] + light_contrib[1];
}CameraPosition and lightPosition that are passed to vertex shader are multiplied for inverse model view matrix, then passed to vertex shader.
In this way when i translate or rotate my mesh all goes right , but if i scale it i obtain a final color darker.
Someone knows why?
Thank you

Relic
05-24-2005, 07:13 AM
This is doing object space lighting.
The scale affects the input light_pos_world which affects attenuation (only 3 t's in that word.)

light_coord[0] = (light_pos_world[0].xyz - gl_Vertex.xyz) * w2t;
...
attentuation_coord[0] = light_coord[0] / light_radius[0];

Which means the shader was not written to handle scaling.

Java Cool Dude
05-24-2005, 08:05 AM
To work around non-homogenous scaling, or any other transforms for that matter, what I do is take the cumulative transform matrix and pass it to my vertex shader before multiplying it by gl_Vertex to obtain the world position.
Here's a shader that illustrates what I'm talking about

<VERTEX_SHADER>
<Uniform name = "worldTransform0" size = "4" type = "float"/>
<Uniform name = "worldTransform1" size = "4" type = "float"/>
<Uniform name = "worldTransform2" size = "4" type = "float"/>
<Uniform name = "worldTransform3" size = "4" type = "float"/>
<Uniform name = "cameraPosition" size = "4" type = "float"/>
<Uniform name = "bumpScale" size = "1" type = "float"/>

<RawData>
uniform vec4 worldTransform0;
uniform vec4 worldTransform1;
uniform vec4 worldTransform2;
uniform vec4 worldTransform3;
uniform vec4 cameraPosition;
varying mat3 normalMatrix;
uniform float bumpScale;

void main(void)
{
mat3 rotations = mat3(worldTransform0.xyz,
worldTransform1.xyz,
worldTransform2.xyz);

normalMatrix[0] = rotations*gl_MultiTexCoord1.xyz;
normalMatrix[0] *= bumpScale;

normalMatrix[1] = rotations*gl_MultiTexCoord2.xyz;
normalMatrix[1] *= bumpScale;

normalMatrix[2] = rotations*gl_Normal;

vec4 worldSpaceVertexPos = vec4(worldTransform0.x * gl_Vertex.x +
worldTransform1.x * gl_Vertex.y +
worldTransform2.x * gl_Vertex.z +
worldTransform3.x,
worldTransform0.y * gl_Vertex.x +
worldTransform1.y * gl_Vertex.y +
worldTransform2.y * gl_Vertex.z +
worldTransform3.y,
worldTransform0.z * gl_Vertex.x +
worldTransform1.z * gl_Vertex.y +
worldTransform2.z * gl_Vertex.z +
worldTransform3.z, 0.0);

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = cameraPosition - worldSpaceVertexPos;
gl_Position = ftransform();
}
</RawData>
</VERTEX_SHADER>