Transformations in GLSL

Started by
10 comments, last by Falhar 17 years, 11 months ago
I am trying to compute attenuation for my lights in a fragment shader. I pass the world space light and vertex position to the fragment shader and calculate the light vector, which is then scaled by the inverse radius of the light. I use this value to compute the final attenuation like so: float attenuation = clamp(1.0-dot(lv, lv), 0.0, 1.0); It works perfectly for objects that are position at the origin, but if any object is translated the attenuation is computed as if the object were actually centered about the origin.. which makes me think I dont understand transforms & coordinate spaces properly.. I always assumed that muliplying the incoming vertex position (gl_Vertex) by the modelview matrix would give you the vertex position in world space. Basically you have some object, with some frame of reference, and before rendering you modify the modelview matrix to translate, rotate, or scale it into place. In the vertex shader you have to do this transformation yourself.. gl_ModelViewMatrix * gl_Vertex. My light position is in world space as well. Ive tried converting them both to homogenous points in eye space, as stated in the orange book - but i get the same effect. Am I missing something here? Shouldnt I be able to just transform the incoming vertex position by the modelview matrix and go from there?
Advertisement
this is not gonna work
float attenuation = clamp(1.0-dot(lv, lv), 0.0, 1.0);
to understand why stick a few values in lv and do the math
doing this should also give u a clue on what u need to calculate
zedzeek, thanks for the reply! I think the forumula should work though, maybe I didnt explain well enough:

I didnt derive this equation myself, I had some help from some people over on the gp&t forum and the game engine at humus.ca (awesome site!)- but I did run some numbers myself before using it, and it seems to work. And more importantly, it looks pretty damn good as well. But the problem remains with the calculations somehow working as if all objects are centered about the origin.

Just to double check myself, I ran through another set of numbers. I kept the same positions, just changed the radius for each calculation. Here goes:

Test 1
======
lightRadius = 1/450 = 0.0022
lightPosition = (0, 100, 0)
vertexPosition = (300, 0, 285)

lightVector = (lightPosition - vertexPosition) * lightRadius
lightVector = (-300, 100, -285) * 0.0022
lightVector = (-0.66, 0.22, -0.627)

attenuation = (clamp(1.0-dot(lightVector, lightVector), 0.0, 1.0))
attenuation = (clamp(1.0-(0.435 + 0.121 + 0.393), 0.0, 1.0))
attenuation = (clamp(0.051), 0.0, 1.0)
attenuation = 0.0

Test 2 (larger light radius)
============================
lightRadius = 1/1500 = 6.66
lightPosition = (0, 100, 0)
vertexPosition = (300, 0, 285)

lightVector = (lightPosition - vertexPosition) * lightRadius
lightVector = (-300, 100, -285) * 6.66
lightVector = (-1998, 666, -1898)

attenuation = (clamp(1.0-dot(lightVector, lightVector), 0.0, 1.0))
attenuation = (clamp(1.0-(1994004 + 443556 + 3602404), 0.0, 1.0))
attenuation = (clamp(6039964), 0.0, 1.0)
attenuation = 1.0

Now, I could be making a mistake here or overlooking something, or maybe there is some special case regarding the way I am calculating attenuation - but this seems to work. Here is a screenshot showing the problem specifically:

atten error

This is a pretty crappy example, but if you can see the object in the top right corner, it should be mostly dark. If I move the light just above the origin it appears fully lit, if i place the light just above the object itself, its totally black...

It seems like such a simple problem, and I have tried everything, read everything I can about coordinate space transformations, the modelview and projection matrices and I just cant figure out whats going wrong here.

[Edited by - luridcortex on May 12, 2006 5:40:55 PM]
I've had exactly the same problem for months. it get's worse when you are rotating objects.

If you translate the light position (in the shader) by the the negative of the objects position from the origin, you will end up with the correct lighting, but if you rotate the object, the problem will arise again.

Does the normal matrix have anything to do with it?

Quote:Original post by LopezIf you translate the light position (in the shader) by the the negative of the objects position from the origin, you will end up with the correct lighting, but if you rotate the object, the problem will arise again.


Yeah, I tried that at first to get it working too. Arrrgh!
just quickly looking at the test cases it seems as if the math is all wrong
Quote:Original post by zedzeek
just quickly looking at the test cases it seems as if the math is all wrong


The acutal computations, or the equation as a whole?

EDIT: Well, I did copy the wrong radius over in the second one, but that was just a copy paste error. Anyway, as you can see, the equation works for all objects placed at the origin. Any idea why that might be happening zed?
Here is the source for the vertex and fragment program that I am using. Maybe someone might see whats going wrong:

VertexShader
attribute vec3 tangent;uniform vec3 lightPos;uniform vec3 camPos;varying vec3 lVec;varying vec3 lp;varying vec3 pos;void main(){		gl_TexCoord[0] =  gl_TextureMatrix[0] * gl_MultiTexCoord0;	gl_Position = ftransform();		// Eye-Space?	vec4 ecPos = gl_ModelViewMatrix * gl_Vertex;	vec3 ecPos3 = (vec3(ecPos)) / ecPos.w;	vec3 lightVec = (lightPos - ecPos3);		vec3 n = gl_Normal;	vec3 t = tangent;	vec3 b = cross(n,t);		lVec.x = dot(lightVec, t);	lVec.y = dot(lightVec, b);	lVec.z = dot(lightVec, n);	 	pos = gl_Vertex.xyz;	lp = lightPos;} 


FragmentShader
uniform sampler2D tex_1, tex_2;uniform vec4 lightColor;uniform float radius;varying vec3 lVec;varying vec3 pos;varying vec3 lp;void main(){	vec3 lv = (pos - lp) * radius;	float attenuation = clamp(1.0-dot(lv, lv), 0.0, 1.0);		vec3 lightVec = normalize(lVec);		vec4 base = texture2D(tex_1, gl_TexCoord[0].st);	vec3 bump = (texture2D(tex_2, gl_TexCoord[0].st).xyz - 0.5) * 2.0;	bump.y = -bump.y;		bump = normalize(bump);		float diffuse = max(0.0, dot(lightVec, bump));			vec4 lighting = diffuse * base;			gl_FragColor = lighting * lightColor * attenuation;}


Everytime I run through the math it seems to come out ok, and the formula is based off of Matt's explanation here
Still trying hard to get this working ;)

I still want to think this has something to do with transformations.

If I transform the vertex by the modelview matrix: gl_ModelViewMatrix * gl_Vertex
and send that to the fragment shader as the vertex position, and send the light position in world space, the attenuation works perfectly for all objects except that the light seems to be centered about the camera and moves with it!

Is it necessary to transform the light position and vertex position by the modelview matrix? If I do this, the original problem described above occurs (all objects are lit as if centered at the origin)

I notice several people use a similar equation to mine - ati demos & unigine in particular. What they do is dot the light vector in tangent space with itself. I perform the calculation manually in the fragment shader because it seems to look better. I have tried that exact method, and the same problem occurs. Could the problem perhaps be on the application side? I simply apply the camera matrix at the beginning of the scene, then apply the models transformation, and then render.
sorry mate i havent looked closly at what u have but

u have
lightVector = (-0.66, 0.22, -0.627)
attenuation = (clamp(1.0-dot(lightVector, lightVector), 0.0, 1.0))
attenuation = (clamp(0.051), 0.0, 1.0)

but infact the answer is
(-0.66 0.22 -0.627)
0.122871

theres also more erros after this

This topic is closed to new replies.

Advertisement