simpleraycaster.frag 7.01 KB
Newer Older
1 2
// ================================================================================================
// 
schultezub's avatar
schultezub committed
3
// This file is part of the CAMPVis Software Framework.
4 5
// 
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7 8 9
//      Chair for Computer Aided Medical Procedures
//      Technische Universitt Mnchen
//      Boltzmannstr. 3, 85748 Garching b. Mnchen, Germany
schultezub's avatar
schultezub committed
10
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// 
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
// 
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 
// ================================================================================================

30 31 32
layout(location = 0) out vec4 out_Color;     ///< outgoing fragment color
layout(location = 1) out vec4 out_FHP;       ///< outgoing fragment first hitpoint
layout(location = 2) out vec4 out_FHN;       ///< outgoing fragment first hit normal
33

34
#include "tools/gradient.frag"
schultezub's avatar
schultezub committed
35
#include "tools/raycasting.frag"
36
#include "tools/shading.frag"
schultezub's avatar
schultezub committed
37 38 39 40 41
#include "tools/texture2d.frag"
#include "tools/texture3d.frag"
#include "tools/transferfunction.frag"

uniform vec2 _viewportSizeRCP;
42
uniform float _jitterStepSizeMultiplier;
schultezub's avatar
schultezub committed
43 44


45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
// ray entry points
uniform sampler2D _entryPoints;
uniform sampler2D _entryPointsDepth;
uniform TextureParameters2D _entryParams;

// ray exit points
uniform sampler2D _exitPoints;
uniform sampler2D _exitPointsDepth;
uniform TextureParameters2D _exitParams;

// DRR volume
uniform sampler3D _volume;
uniform TextureParameters3D _volumeTextureParams;

// Transfer function
uniform sampler1D _transferFunction;
uniform TFParameters1D _transferFunctionParams;

schultezub's avatar
schultezub committed
63

64 65 66
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;

schultezub's avatar
schultezub committed
67 68
uniform float _samplingStepSize;

69 70 71 72
#ifdef ENABLE_SHADOWING
uniform float _shadowIntensity;
#endif

schultezub's avatar
schultezub committed
73 74 75 76
// TODO: copy+paste from Voreen - eliminate or improve.
const float SAMPLING_BASE_INTERVAL_RCP = 200.0;

/**
schultezub's avatar
schultezub committed
77
 * Performs the raycasting and returns the final fragment color.
schultezub's avatar
schultezub committed
78 79 80
 */
vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) {
    vec4 result = vec4(0.0);
81
    float firstHitT = -1.0;
schultezub's avatar
schultezub committed
82 83 84 85 86 87 88

    // calculate ray parameters
    vec3 direction = exitPoint.rgb - entryPoint.rgb;
    float t = 0.0;
    float tend = length(direction);
    direction = normalize(direction);

89
    jitterEntryPoint(entryPoint, direction, _samplingStepSize * _jitterStepSizeMultiplier);
schultezub's avatar
schultezub committed
90 91

    while (t < tend) {
92
        // compute sample position
schultezub's avatar
schultezub committed
93
        vec3 samplePosition = entryPoint.rgb + t * direction;
94 95

        // lookup intensity and TF
96
        float intensity = texture(_volume, samplePosition).r;
97
        vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity);
schultezub's avatar
schultezub committed
98

99 100 101 102
#ifdef ENABLE_SHADOWING
        // simple and expensive implementation of hard shadows
        if (color.a > 0.1) {
            // compute direction from sample to light
103
            vec3 L = normalize(_lightSource._position - textureToWorld(_volumeTextureParams, samplePosition).xyz) * _samplingStepSize;
104 105 106 107 108 109 110 111

            bool finished = false;
            vec3 position = samplePosition + L;
            float shadowFactor = 0.0;

            // traverse ray from sample to light
            while (! finished) {
                // grab intensity and TF opacity
112
                intensity = texture(_volume, position).r;
113
                shadowFactor += lookupTF(_transferFunction, _transferFunctionParams, intensity).a;
114 115 116 117 118 119 120

                position += L;
                finished = (shadowFactor > 0.95)
                         || any(lessThan(position, vec3(0.0, 0.0, 0.0)))
                         || any(greaterThan(position, vec3(1.0, 1.0, 1.0)));
            }
            // apply shadow to color
121
            color.rgb *= (1.0 - shadowFactor * _shadowIntensity);
122 123 124
        }
#endif

schultezub's avatar
schultezub committed
125 126
        // perform compositing
        if (color.a > 0.0) {
127 128
#ifdef ENABLE_SHADING
            // compute gradient (needed for shading and normals)
129 130
            vec3 gradient = computeGradient(_volume, _volumeTextureParams, samplePosition);
            color.rgb = calculatePhongShading(textureToWorld(_volumeTextureParams, samplePosition).xyz, _lightSource, _cameraPosition, gradient, color.rgb, color.rgb, vec3(1.0, 1.0, 1.0));
131
#endif
132

133
            // accomodate for variable sampling rates
schultezub's avatar
schultezub committed
134
            color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
135
            result.rgb = mix(color.rgb, result.rgb, result.a);
schultezub's avatar
schultezub committed
136 137 138 139
            result.a = result.a + (1.0 -result.a) * color.a;
        }

        // save first hit ray parameter for depth value calculation
140
        if (firstHitT < 0.0 && result.a > 0.0) {
141
            firstHitT = t;
142
            out_FHP = vec4(samplePosition, 1.0);
143
            out_FHN = vec4(normalize(computeGradient(_volume, _volumeTextureParams, samplePosition)), 1.0);
144
        }
schultezub's avatar
schultezub committed
145 146

        // early ray termination
schultezub's avatar
schultezub committed
147
        if (result.a > 0.975) {
schultezub's avatar
schultezub committed
148 149 150 151
            result.a = 1.0;
            t = tend;
        }

152
        // advance to the next evaluation point along the ray
schultezub's avatar
schultezub committed
153 154 155 156 157
        t += _samplingStepSize;
    }

    // calculate depth value from ray parameter
    gl_FragDepth = 1.0;
158
    if (firstHitT >= 0.0) {
159 160
        float depthEntry = texture(_entryPointsDepth, texCoords).z;
        float depthExit = texture(_exitPointsDepth, texCoords).z;
161 162
        gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
    }
schultezub's avatar
schultezub committed
163 164 165 166 167 168 169 170
    return result;
}

/***
 * The main method.
 ***/
void main() {
    vec2 p = gl_FragCoord.xy * _viewportSizeRCP;
171 172
    vec3 frontPos = texture(_entryPoints, p).rgb;
    vec3 backPos = texture(_exitPoints, p).rgb;
schultezub's avatar
schultezub committed
173 174 175 176 177 178 179

    //determine whether the ray has to be casted
    if (frontPos == backPos) {
        //background need no raycasting
        discard;
    } else {
        //fragCoords are lying inside the boundingbox
180
        out_Color = performRaycasting(frontPos, backPos, p);
schultezub's avatar
schultezub committed
181 182
    }
}