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
    }
}