PDA

View Full Version : Angle between two vectors issue



Kealor1458
12-09-2017, 08:35 AM
I'm basically trying to get the angle between two vectors and factor that into a smoothstep which i then use elsewhere:


void main()
{
float sampleDepth = texture2D(spec, v_vTexcoord ).r;
vec3 normalPos = vec3(v_vTexcoord.xy,sampleDepth);
vec3 normalVector = texture2D(norm, v_vTexcoord ).rgb;

float brightnessMod = 0.0;
for (float i = 0.0; i < lightNum; i++)
{
vec3 lightPos = texture2D(light,vec2(i,0.0)).rgb;
vec3 lightVector = vec3(normalPos-lightPos);
float angle = acos(clamp(dot(normalize(lightVector),normalize(no rmalVector)),-1.0,1.0); // <<< This is the problem line as far as i can tell
brightnessMod += 1.0-smoothstep(0.0,PI/2.0,angle);
}
gl_FragColor = vec4((v_vColour * texture2D( gm_BaseTexture, v_vTexcoord ) * min(brightnessMod,1.0)).rgb,1.0);
}


From context it seems to me that the "smoothstep()" is allways returning 1, even though the angle should be in [0, pi] but even when i change the "smoothstep()" to "smoothstep(0.0,100000.0,angle)" it still returns 1.

Now am i an idiot and there is a problem with ang = v1 dot v2 (since normalized)? or is there something else going on.

lightVector and NormalVector are both vec3s and i can provide additional context if needed. I'm somewhat fresh on the opengl scene but i cannot for the life of me figure out what is going on.

GClements
12-09-2017, 08:48 AM
Now am i an idiot and there is a problem with ang = v1 dot v2 (since normalized)? or is there something else going on.

If the two vectors are almost colinear, It's possible for dot() returns a value greater than 1 (or less than -1) due to rounding error. In that case, the result of acos() will be undefined.

Other than that, I can't see any issue with the code posted.

Kealor1458
12-09-2017, 09:06 AM
If the two vectors are almost colinear, It's possible for dot() returns a value greater than 1 (or less than -1) due to rounding error. In that case, the result of acos() will be undefined.

What would be the most efficient method to account for this? just a clamp function?

Kealor1458
12-09-2017, 11:02 AM
I edited the original post to have the entire void main() of the fragment shader, just for context.

GClements
12-09-2017, 11:16 AM
What would be the most efficient method to account for this? just a clamp function?
Or multiply by 0.9999.


I edited the original post to have the entire void main() of the fragment shader, just for context.
The brightnessMod variable isn't used, so the variable (and the calculation of its value) will be eliminated. In fact, everything but the last line will be eliminated.

Kealor1458
12-09-2017, 11:00 PM
My bad, i was attempting to debug by testing other variables and i forgot to change it back to its default, its actually:

gl_FragColor = vec4((v_vColour * texture2D( gm_BaseTexture, v_vTexcoord ) * min(brightnessMod,1.0)).rgb,1.0);
instead of
gl_FragColor = vec4((v_vColour * texture2D( gm_BaseTexture, v_vTexcoord )).rgb,1.0);

I fixed the original post to reflect this

GClements
12-10-2017, 02:36 AM
float brightnessMod = 0.0;
for (float i = 0.0; i < lightNum; i++)
{
vec3 lightPos = texture2D(light,vec2(i,0.0)).rgb;


You should probably be using texelFetch() here. Bear in mind that texture2D() expects normalised texture coordinates.

But even with that mistake, it should work for i==0.

Other than that, the only thing I can suggest is to copy specific variables to gl_FragColor() so that you can check that they have the expected values.

Another potential issue is that applying normalize() to a zero vector is undefined (and may result in NaNs).

Kealor1458
12-10-2017, 03:22 AM
You should probably be using texelFetch() here. Bear in mind that texture2D() expects normalised texture coordinates.

But even with that mistake, it should work for i==0.

Other than that, the only thing I can suggest is to copy specific variables to gl_FragColor() so that you can check that they have the expected values.

Another potential issue is that applying normalize() to a zero vector is undefined (and may result in NaNs).

Ah thanks for catching that out, ive been testing with one light but that would be a problem later, Though it apears that the texelFetch function either doesnt work in my system or im doing something else wrong, this code throws an error (im using openGL ES btw):

for (int i = 0; i < int(lightNum); i++)
{
vec3 lightPos = texelFetch(light,ivec2(i,0)).rgb;
//Rest of for loop
}


Also i have made some progress, im no longer having the issue above, as it turns out i was loading some data incorrectly and the end result was normalizing a zero vector, fixing this had made (almost) everything run smoothly.

Though currently the output is scaled oddly, and the light is emitted in a more elliptical manner for some reason: https://imgur.com/a/7f0yd . Anybody have any ideas? (ill update original post)

GClements
12-10-2017, 05:43 AM
Though it apears that the texelFetch function either doesnt work in my system or im doing something else wrong, this code throws an error (im using openGL ES btw):

OpenGL ES 2 doesn't have texelFetch(). So you need to use (i+0.5)/texture_width (the texture filters should be set to GL_NEAREST).

Kealor1458
12-10-2017, 06:47 AM
OpenGL ES 2 doesn't have texelFetch(). So you need to use (i+0.5)/texture_width (the texture filters should be set to GL_NEAREST).

How come the "+0.5"? Also im having some issues using the texture filter functions as well:


glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

throws an error

edit: adding the 0.5 is needed for it to work, also it seems everything is working perfectly on my end now! even without the glTexParameterf setting. Though i am still curious about the two. Thanks alot!

GClements
12-10-2017, 09:21 AM
How come the "+0.5"?
You want to sample in the centre of each texel.



Also im having some issues using the texture filter functions as well:


glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

throws an error

Is a valid texture bound when you call those functions? Texture filters are a property of a texture; those calls set the filters for the texture currently bound to the GL_TEXTURE_2D target.


edit: adding the 0.5 is needed for it to work, also it seems everything is working perfectly on my end now! even without the glTexParameterf setting. Though i am still curious about the two. Thanks alot!
The default setting for GL_TEXTURE_MIN_FILTER is GL_NEAREST_MIPMAP_LINEAR, which requires that the texture has all mipmap levels defined. But if you're sampling with constant texture coordinates, it should be using the magnification filter, which defaults to GL_LINEAR. If you aren't sampling the exact centre of each texel, it will interpolate between adjacent texels.