GLProgramming.com

home :: about :: development guides :: irc :: forums :: search :: paste :: links :: contribute :: code dump

-> Click here to learn how to get live help <-


New Paste :: Recent Pastes:: Add Line Numbers


bbox shader w/ single channel 3d texture by taby
//
// fragment.glsl::Fig. 1
//
// 1) the bounding box delineates where the fluid simulation resides in R3
//
// 2) this fragment shader finds the line segment stretching from the points on the bounding box surface
// where the eye ray enters and exits
//
// 3) if no initial eye ray / front-facing bounding box plane intersection occurs, it aborts early
//
// 4) once the line segment has been found, it is marched along, starting at the front-facing entry point,
// and continuing on until the sample position is past the back-facing exit point
// 
// 5) since the last step will rarely occur at the same location as the exit point,
// the step is shortened so that it lies upon the exit point, where the final step's sample is taken.
// the contribution of that sample is scaled down in power according to how much the step was shortened
//
// 6) *TOP-DOWN* 3rd-person view of the eye ray intersecting with the front and back faces
// 
//     #
//     .
//    _.____
//   / x  F/\
//  /__'__/  \
//  \  ' B\  /
//   \_x___\/ 
//     .
//     .
//     .
//
// F = front-facing entry plane
// B = back-facing exit plane
// # = eye
// . = eye ray
// ' = march steps
//

//non-normalized origin-based look-at vector
varying vec3 look_at;

// eye point
uniform vec3 eye;

// directional light ray vector
uniform vec3 light;

// bounding box extents
uniform vec3 bnd_min;
uniform vec3 bnd_max;

// march/sample precision
uniform float march_len;

// a little help getting things started (see: get_start())
uniform int inside_box;

// the volumetric data
uniform sampler3D data;

// some sanity checkers
#define INF 1e38
#define EPSILON 1e-5


void get_start(inout vec3 start, const in vec3 march_step)
{
    bool found_match = false;

    // if inside box, eye is the start position, otherwise, start at edge of box
    if(1 == inside_box)
    {
        start = eye;
        found_match = true;
    }
    else
    {
        if(false == found_match && -EPSILON > dot(look_at, vec3(1, 0, 0)))
        {
            // extend ray to +x plane, test if surface point is within y and z bounds
            float mul = abs(eye.x - bnd_max.x) / abs(march_step.x);
            start = eye + (march_step*mul);

            if(bnd_max.x + EPSILON > start.x && bnd_max.x - EPSILON < start.x && bnd_min.y < start.y && bnd_max.y > start.y && bnd_min.z < start.z && bnd_max.z > start.z)
                found_match = true;
        }
        else if(false == found_match && -EPSILON > dot(look_at, vec3(-1, 0, 0)))
        {
            // extend ray to -x plane, test if surface point is within y and z bounds
            float mul = abs(eye.x - bnd_min.x) / abs(march_step.x);
            start = eye + (march_step*mul);

            if(bnd_min.x + EPSILON > start.x && bnd_min.x - EPSILON < start.x && bnd_min.y < start.y && bnd_max.y > start.y && bnd_min.z < start.z && bnd_max.z > start.z)
                found_match = true;
        }
            
        if(false == found_match && -EPSILON > dot(look_at, vec3(0, 1, 0)))
        {
            // extend ray to +y plane, test if surface point is within x and z bounds
            float mul = abs(eye.y - bnd_max.y) / abs(march_step.y);
            start = eye + (march_step*mul);

            if(bnd_max.y + EPSILON > start.y && bnd_max.y - EPSILON < start.y && bnd_min.x < start.x && bnd_max.x > start.x && bnd_min.z < start.z && bnd_max.z > start.z)
                found_match = true;
        }
        else if(false == found_match && -EPSILON > dot(look_at, vec3(0, -1, 0)))
        {
            // extend ray to -y plane, test if surface point is within x and z bounds
            float mul = abs(eye.y - bnd_min.y) / abs(march_step.y);
            start = eye + (march_step*mul);

            if(bnd_min.y + EPSILON > start.y && bnd_min.y - EPSILON < start.y && bnd_min.x < start.x && bnd_max.x > start.x && bnd_min.z < start.z && bnd_max.z > start.z)
                found_match = true;
        }
        
        if(false == found_match && -EPSILON > dot(look_at, vec3(0, 0, 1)))
        {
            // extend ray to +z plane, test if surface point is within x and y bounds
            float mul = abs(eye.z - bnd_max.z) / abs(march_step.z);
            start = eye + (march_step*mul);

            if(bnd_max.z + EPSILON > start.z && bnd_max.z - EPSILON < start.z && bnd_min.x < start.x && bnd_max.x > start.x && bnd_min.y < start.y && bnd_max.y > start.y)
                found_match = true;
        }
        else if(false == found_match && -EPSILON > dot(look_at, vec3(0, 0, -1)))
        {
            // extend ray to -z plane, test if surface point is within y and z bounds
            float mul = abs(eye.z - bnd_min.z) / abs(march_step.z);
            start = eye + (march_step*mul);

            if(bnd_min.z + EPSILON > start.z && bnd_min.z - EPSILON < start.z && bnd_min.x < start.x && bnd_max.x > start.x && bnd_min.y < start.y && bnd_max.y > start.y)
                found_match = true;
        }
    }
    
    if(false == found_match)
        start.x = INF;
}

void get_end(const in vec3 start, inout vec3 end, const in vec3 march_step)
{
    bool found_match = false;

    if(false == found_match && EPSILON < dot(look_at, vec3(1, 0, 0)))
    {
        // extend ray to +x plane, test if surface point is within y and z bounds
        float mul = abs(start.x - bnd_max.x) / abs(march_step.x);
        end = start + (march_step*mul);

        if(bnd_max.x + EPSILON > end.x && bnd_max.x - EPSILON < end.x && bnd_min.y < end.y && bnd_max.y > end.y && bnd_min.z < end.z && bnd_max.z > end.z)
            found_match = true;
    }
    else if(false == found_match && EPSILON < dot(look_at, vec3(-1, 0, 0)))
    {
        // extend ray to -x plane, test if surface point is within y and z bounds
        float mul = abs(start.x - bnd_min.x) / abs(march_step.x);
        end = start + (march_step*mul);

        if(bnd_min.x + EPSILON > end.x && bnd_min.x - EPSILON < end.x && bnd_min.y < end.y && bnd_max.y > end.y && bnd_min.z < end.z && bnd_max.z > end.z)
            found_match = true;
    }
            
    if(false == found_match && EPSILON < dot(look_at, vec3(0, 1, 0)))
    {
        // extend ray to +y plane, test if surface point is within x and z bounds
        float mul = abs(start.y - bnd_max.y) / abs(march_step.y);
        end = start + (march_step*mul);

        if(bnd_max.y + EPSILON > end.y && bnd_max.y - EPSILON < end.y && bnd_min.x < end.x && bnd_max.x > end.x && bnd_min.z < end.z && bnd_max.z > end.z)
            found_match = true;
    }
    else if(false == found_match && EPSILON < dot(look_at, vec3(0, -1, 0)))
    {
        // extend ray to -y plane, test if surface point is within x and z bounds
        float mul = abs(start.y - bnd_min.y) / abs(march_step.y);
        end = start + (march_step*mul);

        if(bnd_min.y + EPSILON > end.y && bnd_min.y - EPSILON < end.y && bnd_min.x < end.x && bnd_max.x > end.x && bnd_min.z < end.z && bnd_max.z > end.z)
            found_match = true;
    }
            
    if(false == found_match && EPSILON < dot(look_at, vec3(0, 0, 1)))
    {
        // extend ray to +z plane, test if surface point is within x and y bounds
        float mul = abs(start.z - bnd_max.z) / abs(march_step.z);
        end = start + (march_step*mul);

        if(bnd_max.z + EPSILON > end.z && bnd_max.z - EPSILON < end.z && bnd_min.x < end.x && bnd_max.x > end.x && bnd_min.y < end.y && bnd_max.y > end.y)
            found_match = true;
    }
    else if(false == found_match && EPSILON < dot(look_at, vec3(0, 0, -1)))
    {
        // extend ray to -z plane, test if surface point is within y and z bounds
        float mul = abs(start.z - bnd_min.z) / abs(march_step.z);
        end = start + (march_step*mul);

        if(bnd_min.z + EPSILON > end.z && bnd_min.z - EPSILON < end.z && bnd_min.x < end.x && bnd_max.x > end.x && bnd_min.y < end.y && bnd_max.y > end.y)
            found_match = true;
    }

    if(false == found_match)
        end.x = INF;
}

void get_march_path(inout vec3 start, inout vec3 end, inout vec3 march_step)
{
    march_step = normalize(look_at)*march_len;

    get_start(start, march_step);
    
    // if start.x is ever INF at any point, abort early
    
    // abort early
    if(INF != start.x)
    {
        get_end(start, end, march_step);

        // set-up abort early for any further GLSL statements made in this fragment shader instance
        if(INF == end.x)
            start.x = INF;
    }
}

void main()
{
    vec3 start, end, march_step;

    // default colour
    gl_FragColor.r = 0.5;
    gl_FragColor.g = 0.5;
    gl_FragColor.b = 0.5;
    gl_FragColor.a = 1.0;

    get_march_path(start, end, march_step);

    if(INF != start.x)
    {
        // how far into the box are we??
        vec4 sample = texture3D(data, vec3(0.0, 0.0, 0.0));
        gl_FragColor.r = sample.a;
        
        sample = texture3D(data, vec3(1.0, 1.0, 1.0));
        gl_FragColor.g = sample.a;
        
        gl_FragColor.b = 0.3;
    }
}