Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Point plus vector gives odd result

  1. #1
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    22

    Point plus vector gives odd result

    Hi,

    I have a point ray_start_pos in world coordinates. I add the vector (reflection_dir * ray_length) to get ray_end_pos, which is then transferred to screen coordinates by multiplying the pvm matrix with ray_end_pos.

    (Abstract of) original GLSL code:

    Code :
    mat4    pvm = proj * view * model;
     
    vec3    reflection_dir = normalize(reflect(cam_to_ray_start_pos, ground_normal));
     
    float   ray_length = min(1000.0, length(ray_start_pos - cam_pos));
     
    vec3    ray_end_pos = ray_start_pos + reflection_dir * ray_length;
    vec4    ray_end_pos_on_screen = pvm * vec4(ray_end_pos, 1.0);
     
    ray_end_pos_on_screen.xyz = ray_end_pos_on_screen.xyz * 0.5 / ray_end_pos_on_screen.w + 0.5;

    My PROBLEM: when ray_length is small, around 100, then ray_end_pos_on_screen.xyz is as expected. When ray_length is larger, around 1000, then ray_end_pos_on_screen.xyz seems to 'wrap around', in the sense that (in tests especially) ray_end_pos_on_screen.x is suddenly much too large, or has other odd values.

    Any idea what could be wrong? Thanks!

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,519
    What are you doing with ray_end_pos_on_screen? Anything which involves the w component is going to be wrong. What's the purpose of the last line?

  3. #3
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    22
    Quote Originally Posted by GClements View Post
    What are you doing with ray_end_pos_on_screen? Anything which involves the w component is going to be wrong. What's the purpose of the last line?
    For debugging, the only action done with ray_end_pos_on_screen is to examine its values by deriving the current fragment's color from it:

    Code :
    [...] (see initial post)
     
    out_col = vec4(ray_end_pos_on_screen.x, ray_end_pos_on_screen.y, 0.0, 1.0); // set the fragment shader's output color

    For a small ray_length, e.g. 100.0, the scene gets more intensively red from the screen's left to right border, as expected. For the very same ray_start_pos and reflection_dir I get odd red/yellow/green patterns if ray_length is greater than around 200.0, e.g. if ray_length = 1000.0.

    I just wanted to know if there are things to attend when involving the pvm matrix. In university we were told that "clipping in normalized coordinates will not work due to non linear transformation in z". I wonder if this could somehow explain my odd ray_end_pos_on_screen content?!?

  4. #4
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,519
    Quote Originally Posted by JasonRay View Post
    For a small ray_length, e.g. 100.0, the scene gets more intensively red from the screen's left to right border, as expected. For the very same ray_start_pos and reflection_dir I get odd red/yellow/green patterns if ray_length is greater than around 200.0, e.g. if ray_length = 1000.0.
    Bear in mind that if the result is outside of the unsigned unit cube, each component will be clamped separately, meaning that the direction (i.e. hue) won't be preserved.

    Quote Originally Posted by JasonRay View Post
    I just wanted to know if there are things to attend when involving the pvm matrix. In university we were told that "clipping in normalized coordinates will not work due to non linear transformation in z". I wonder if this could somehow explain my odd ray_end_pos_on_screen content?!?
    Clipping isn't a factor here, although the lack of clipping may be. If eye-space Z is positive (behind the viewpoint), clip-space W will be negative, resulting in normalised X,Y,Z all being flipped. Clipping exists largely to prevent that situation from occurring; even without the near-plane test, the geometry which remains after clipping will be in front of the viewpoint.

    Provided that ray_end_pos lies within the view frustum, ray_end_pos_on_screen.xyz is calculated correctly. If ray_end_pos is outside of the view frustum, the result will be wrong. In particular, if the reflection of ray_end_pos in the viewpoint is inside of the view frustum, ray_end_pos_on_screen.xyz will correspond to that reflection. You might want to explicitly test for ray_end_pos_on_screen.w<0 before dividing by it and discard (or set a constant colour) for that case. And also test whether any of abs(ray_end_pos_on_screen.xyz/ray_end_pos_on_screen.w) are greater than one.

  5. #5
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    22
    Quote Originally Posted by GClements View Post
    You might want to explicitly test for ray_end_pos_on_screen.w<0 before dividing by it and discard (or set a constant colour) for that case.
    Seems as this did the job, thank you!

    One more question: I have a point in world space, e.g. ray_start_pos, and from there a vector that points into some arbitrary direction (in world space), e.g. reflection_dir, and the length of reflection_dir, e.g. ray_length (just as in the example of my initial post).

    Is there an easy way at all to determine ray_length so that ray_end_pos = ray_start_pos + reflection_dir * ray_length is located at the (nearest) screen border? I mean is there an easy way to do correct clipping in the given case? 'Easy way' shall mean around 5 to 10 or so lines of shader code, in any case easier than the whole Cohen-Sutherland machinery.

  6. #6
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,519
    Quote Originally Posted by JasonRay View Post
    One more question: I have a point in world space, e.g. ray_start_pos, and from there a vector that points into some arbitrary direction (in world space), e.g. reflection_dir, and the length of reflection_dir, e.g. ray_length (just as in the example of my initial post).

    Is there an easy way at all to determine ray_length so that ray_end_pos = ray_start_pos + reflection_dir * ray_length is located at the (nearest) screen border? I mean is there an easy way to do correct clipping in the given case? 'Easy way' shall mean around 5 to 10 or so lines of shader code, in any case easier than the whole Cohen-Sutherland machinery.
    It's much simpler if you transform both ray_start_pos and reflection_dir to clip space. In that situation, and provided that ray_start_pos lies within the view frustum, then you can use:

    Code :
    vec3 l0 = -(ray_start_pos.xyz + ray_start_pos.w) / reflection_dir.xyz;
    vec3 l1 = -(ray_start_pos.xyz - ray_start_pos.w) / reflection_dir.xyz;
    vec3 l = max(l0, l1);
    ray_length = min(min(ray_length, l.x), min(l.y, lz));

    The vector l0 contains the lengths at which the ray will coincide with the x=-w, y=-w and z=-w planes. The vector l1 contains the lengths at which the ray will coincide with the x=w, y=w and z=w planes. You want the smallest positive value. Provided that ray_start_pos is within the view frustum, each component (x, y or z) will be negative in one vector and positive in the other, so max(l0,l1) will choose the positive value for each component.

  7. #7
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    22
    Quote Originally Posted by GClements View Post
    It's much simpler if you transform both ray_start_pos and reflection_dir to clip space. In that situation, and provided that ray_start_pos lies within the view frustum, then you can use:

    Code :
    vec3 l0 = -(ray_start_pos.xyz + ray_start_pos.w) / reflection_dir.xyz;
    vec3 l1 = -(ray_start_pos.xyz - ray_start_pos.w) / reflection_dir.xyz;
    vec3 l = max(l0, l1);
    ray_length = min(min(ray_length, l.x), min(l.y, lz));
    Hey that works very well! My odd artifacts I described in the initial post are gone.

    Thank you very much!

    I made some slight changes to your code, I use:

    Code :
    vec3 l0 = -(ray_start_pos_on_screen.xyz + ray_start_pos_on_screen.w) / reflection_dir.xyz;
    vec3 l1 = -(ray_start_pos_on_screen.xyz - ray_start_pos_on_screen.w) / reflection_dir.xyz;
    vec3 l = max(l0, l1);
     
    ray_length = min(min(ray_length, l.x), min(l.y, l.z));

  8. #8
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    22
    Quote Originally Posted by JasonRay View Post
    I made some slight changes to your code, I use:

    Code :
    vec3 l0 = -(ray_start_pos_on_screen.xyz + ray_start_pos_on_screen.w) / reflection_dir.xyz;
    vec3 l1 = -(ray_start_pos_on_screen.xyz - ray_start_pos_on_screen.w) / reflection_dir.xyz;
    vec3 l = max(l0, l1);
     
    ray_length = min(min(ray_length, l.x), min(l.y, l.z));
    Hmm. Are my changes correct at all? I mix up screen space ray_start_pos_on_screen and world space reflection_dir?!?

  9. #9
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,519
    Quote Originally Posted by JasonRay View Post
    I mix up screen space ray_start_pos_on_screen and world space reflection_dir?!?
    You need to transform reflection_dir as well as ray_start_pos.

  10. #10
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    22
    Do you mean I have to transform ray_start_pos AND reflection_dir TO SCREEN SPACE using the pvm matrix before applying your ray_length calculation?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •