New Paste :: Recent Pastes:: No Line Numbers
bbox shader w/ single channel 3d texture by taby
1
// // 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; } }