0

I have a ray box intersection algorithm that is supposedly returning the distance to the intersected plane, however it is not meeting my expectaions.

I am outputing the absolute value of the position of the intersection point as a color. My expectation being that the color should be the same wherever the camera is, since the intersection point hasn't moved.

However my cube has different colors depending on where it is looked from:

Front view:

enter image description here

Slightly uo and right view (same face):

enter image description here

As you can see the color has changed based on the position.

I am raytracing the entire structure on teh fragment shader as follows:

#version 430

in vec2 f_coord;

out vec4 fragment_color;

uniform vec3 camera_pos;
uniform float aspect_ratio;
uniform float cube_dim;

#define EPSILON 0.0001
// Check whether the position is inside of the specified box
bool inBoxBounds(vec3 corner, float size, vec3 position)
{
    bool inside = true;
    //Put the position in the coordinate frame of the box
    position-=corner;
    //The point is inside only if all of it's components are inside
    for(int i=0; i<3; i++)
    {
        inside = inside && (position[i] > -EPSILON);
        inside = inside && (position[i] < size+EPSILON);
    }

    return inside;
}
//Calculate the distance to the intersection to a box, or inifnity if the bos cannot be hit
float boxIntersection(vec3 origin, vec3 dir, vec3 corner0, float size)
{
    dir = normalize(dir);
    //calculate opposite corner
    vec3 corner1 = corner0 + vec3(size,size,size);

    //Set the ray plane intersections
    float coeffs[6];
    coeffs[0] = (corner0.x - origin.x)/(dir.x);
    coeffs[1] = (corner0.y - origin.y)/(dir.y);
    coeffs[2] = (corner0.z - origin.z)/(dir.z);
    coeffs[3] = (corner1.x - origin.x)/(dir.x);
    coeffs[4] = (corner1.y - origin.y)/(dir.y);
    coeffs[5] = (corner1.z - origin.z)/(dir.z);

    float t = 1.f/0.f;
    //Check for the smallest valid intersection distance
    for(uint i=0; i<6; i++)
        t = coeffs[i]>=0&& inBoxBounds(corner0,size,origin+dir*coeffs[i])?
            min(coeffs[i],t) : t;

    return t;
}

void main()
{
    vec3 r = vec3(f_coord.x, f_coord.y, 1.f/tan(radians(40)));
    vec3 dir = r;
    dir.y /= aspect_ratio;
    r = camera_pos;
    float t = boxIntersection(r, dir, vec3(-cube_dim), cube_dim*2);
    if(isinf(t))
        discard;
    r += dir*(t);

    fragment_color = vec4(abs(r)/100,0);
}

Edit:

f_coord is the normalized coordinate system from -1 to 1 (the normalized screen coordinate in the opengl window)

camera_pos is the position of the camera in the 3D world coordinate system.

Community
  • 1
  • 1
Makogan
  • 8,208
  • 7
  • 44
  • 112
  • 1
    What is `f_coord` and in what coordinate system does it live? It looks a bit weird that you are dividing by the aspect ratio. In what coordinate system does `camera_pos` live? – Nico Schertler Jun 20 '18 at 06:15
  • 1
    If I see it right then you are casting your rays as the perspective camera is looking so the rays are not parallel ... that means even if your plane is parallel with znear projection plane each ray hit at different distance... you should see a circle like pattern from the center of screen ... – Spektre Jun 20 '18 at 06:53
  • f_coord is the pixel position in the -1 to 1 opengl nromalized coordinate system, camera_pos live sin the world coordinate system – Makogan Jun 20 '18 at 06:53
  • @Makogan take a look at this [How to best write a voxel engine in C with performance in mind](https://stackoverflow.com/a/48092685/2521214) see the vertex shader its only purpose is to cast such ray ... compare with your stuff if there is not some deviation ... – Spektre Jun 20 '18 at 06:56
  • @Spektre I am not sure I understand your comment. The rays are indeed not parallel as this is not an orthogonal projection ray tracing. However the issue is not that the on one frame the cube has different collors rather than teh same color, bu that as I move the camera the color of the cube changes. My expectation however is, the cube has not moved, only the camera has, thus the points of intersection should eb the same, and thus the color of the cube should be the same regardless of where the camera is (which is not the case in the images I presented) – Makogan Jun 20 '18 at 06:56
  • @Spektre it seems to me it's the same – Makogan Jun 20 '18 at 07:00
  • @Makogan yep to me too but I didn't have my cup of tea yet so I might overlook something ... then you can check with the other ray tracer of mine [Reflection and refraction impossible without recursive ray tracing?](https://stackoverflow.com/a/45140313/2521214) and look for ray triangle intersection in the fragment ... that should do the same as your plane/ray intersection. You just need to tweak/ or get rid of the `u,v` barycentric inside check conditions. `v0,v1,v2` is the tested triangle ... – Spektre Jun 20 '18 at 07:04
  • @Spektre, I cna confirm the plane intersection code itself works, I have used it extensively in other applications and it has not beeen modified – Makogan Jun 20 '18 at 19:10
  • @Makogan then you need to debug this more thoroughly either use this: [GLSL debug prints](https://stackoverflow.com/a/44797902/2521214) and print out some variables in specific parts of screen to veriffy what is wrong or port your code to C++ on CPU side debug there and when working port back to GLSL (that one is more time consuming but using C++ IDE has more debug option like stepping, tracing,breakpointing etc ...) – Spektre Jun 21 '18 at 06:26

1 Answers1

3

The reason is this line in boxIntersection():

dir = normalize(dir);

The t that you are calculating is the ray parameter in x = origin + t * dir. If you normalize dir, then t is equal to the Euclidean distance.

But in main(), you use a different dir:

r += dir*(t);

Here, dir is not normalized, hence you get a different intersection point.

The solution is simple: Do not normalize at all. Or if you need the actual distance, normalize in main() instead of boxIntersection(). Alternatively, you can make the dir parameter an inout parameter. This way, any change to dir from within the function is reflected back to the caller:

float boxIntersection(vec3 origin, inout vec3 dir, vec3 corner0, float size)
Nico Schertler
  • 32,049
  • 4
  • 39
  • 70