Shader fails totally (but no error) on changes

Hi,

I’m having severe problems with this shader, which does a volume rendering of a 3d-texture and optionally checks against the z-buffer.

It works well enough as written, but if I try to remove the texture-fetch from the z-buffer it fails, and goes black (or some other color). I’ve checked that len and len2 are similar, and I can plot each, and I use len2 in the for loop, but … I still can’t remove the lines doing the z-buffer step, that kills the output just stops completely.

If I replace the texture lookup with 1, 0 or anything in between, it fails. (The value should be 1, since the z-buffer is cleared and nothing is drawn there.)

I can’t for the life figure out why this happens, and why I don’t get an error message in that case.

Do I trigger some compiler bug, or is it just an error in my code?

This is on an NVIDIA GTX 260, Vista 32-bit sp2, driver 185.85.


#version 120

uniform sampler3D volume;
uniform sampler2D depth;

uniform bool inverse;
uniform float min_intensity;
uniform float max_intensity;
uniform float resolution;
uniform float texture_lod;

uniform float far;
uniform float near;
uniform vec2 viewport_size;

centroid varying vec3 tex;
varying vec3 vtx;
varying vec3 plane_n_model;

float convertZ(in float depthBufferValue)
{
    float clipZ = ( depthBufferValue - 0.5 ) * 2.0;
    return -(2.0 * far * near) / ( clipZ * ( far - near ) - ( far + near ));
}

void rayPlaneIntersection(vec3 r_pos, vec3 r_dir, vec3 p_normal, float p_dist, inout float len)
{
    // assume r_dir & p_normal are normalized
    // from http://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm
    
    float x = dot(r_dir, p_normal);
    
    if (x < 0.0) {
        float t = (dot(r_pos, p_normal) + p_dist) / -x;        
        len = min(len, t);
    }
} 

// intersect with [0,0,0] - [1,1,1] cube
void computeRayLength(vec3 p, vec3 v, inout float len)
{
    rayPlaneIntersection(p, v, vec3(-1.0, 0.0,  0.0),  1.0, len);
    rayPlaneIntersection(p, v, vec3(1.0,  0.0,  0.0),  0.0, len);
    rayPlaneIntersection(p, v, vec3(0.0,  -1.0, 0.0),  1.0, len);
    rayPlaneIntersection(p, v, vec3(0.0,  1.0,  0.0),  0.0, len);
    rayPlaneIntersection(p, v, vec3(0.0,  0.0,  -1.0), 1.0, len);
    rayPlaneIntersection(p, v, vec3(0.0,  0.0,  1.0),  0.0, len);
}

void main()
{      
    // precompute useful coord
    vec2 fbo_tc = gl_FragCoord.xy * viewport_size;
                     
    // intersect with unit cube
    vec3 view_v = vtx - gl_ModelViewMatrixInverse[3].xyz; // camera to surface point
    vec3 view = normalize(view_v); // direction through volume
    
    float len = sqrt(3.0);
    computeRayLength(vtx, view, len); 

    float len2 = len;
    
    // intersect with z-plane at z-buffer value (not needed here, but shader fails to produce pixels otherwise!?!)    
    float z = texture2D(depth, fbo_tc).r;    
    float plane_dist = convertZ(z);
    vec3 plane_p_model = (gl_ModelViewMatrixInverse * vec4(0, 0, -plane_dist, 1)).xyz; // plane point in model 
    float plane_dist_model = -dot(plane_n_model, plane_p_model); // distance from origo to plane in model
    rayPlaneIntersection(vtx, view, plane_n_model, plane_dist_model, len); 

    // setup iteration parameters
    float step = 1.0 / resolution; // step length
    float end = len2 * resolution;  // max iterations
    float acc = 0.0;               // intensity accumulator
    vec3 v = view * step;          // texture step vector
    vec3 p = tex;                  // texture coordinate

    // do large steps for majority of the volume
    float i = 0.0;        
    for(; i < end - 8.0; i += 8.0) {
        acc += texture3D(volume, p += v, texture_lod).r;
        acc += texture3D(volume, p += v, texture_lod).r;
        acc += texture3D(volume, p += v, texture_lod).r;
        acc += texture3D(volume, p += v, texture_lod).r;
        acc += texture3D(volume, p += v, texture_lod).r;
        acc += texture3D(volume, p += v, texture_lod).r; 
        acc += texture3D(volume, p += v, texture_lod).r;
        acc += texture3D(volume, p += v, texture_lod).r;
    } 

    // compute the last parts (important if limited by solid geometry, less so at edge)
    for(; i < end; i++) {
        acc += texture3D(volume, p += v, texture_lod).r;
    }

    // normalize and rangify
    acc *= step;      
    acc -= min_intensity;
    acc *= 1.0 / (max_intensity - min_intensity);
    
    // output
    // gl_FragColor.rgb = vec3(inverse);
    // gl_FragColor.a = acc

    gl_FragColor.r = len;
    gl_FragColor.b = len2;
    gl_FragColor.g = inverse ? 1.0 : 0.0;
    gl_FragColor.a = acc;
}  


When you remove the texture fetch, both ‘depth’ and ‘viewport_size’ uniform variables are optimized out.
So, If you, by any chance, not binding your ‘volume’ sampler properly, it’s binding might change causing usage of the incorrect texture unit (which might not be 3d texture at all).

Sorry for the distrust, but could you post shader initialization code, please?

Distrust is good, as something is evidently not right. :slight_smile:

I’m using OpenSG to setup texture units & uniforms, and the code is a bit spread out, but looking at it I can’t find where I actually add the texture to the material on unit 0 !?!

Why did it ever work?!? :mad:

Many thanks for pointing that out. I didn’t think properly that texture bindings could change. (And I was fairly sure I had it correct, since it did the right thing, mostly. :slight_smile: