simpleraycaster.frag 8.37 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-2015, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
//      Chair for Computer Aided Medical Procedures
8
9
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
10
// 
schultezub's avatar
schultezub committed
11
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
12
// 
13
14
15
16
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
17
// 
18
19
20
21
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
22
23
24
// 
// ================================================================================================

25
26
27
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
28

29
#include "tools/gradient.frag"
schultezub's avatar
schultezub committed
30
#include "tools/raycasting.frag"
31
#include "tools/shading.frag"
schultezub's avatar
schultezub committed
32
33
34
35
36
#include "tools/texture2d.frag"
#include "tools/texture3d.frag"
#include "tools/transferfunction.frag"

uniform vec2 _viewportSizeRCP;
37
uniform float _jitterStepSizeMultiplier;
schultezub's avatar
schultezub committed
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 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
58

59
60
61
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;

schultezub's avatar
schultezub committed
62
63
uniform float _samplingStepSize;

64
65
66
67
#ifdef ENABLE_SHADOWING
uniform float _shadowIntensity;
#endif

schultezub's avatar
schultezub committed
68
69
const float SAMPLING_BASE_INTERVAL_RCP = 200.0;

70
71
72
73
74
void blendUnder(inout vec4 result, in vec4 color) {
    result.rgb = result.rgb + color.rgb * color.a  * (1.0 - result.a);
    result.a = result.a + (1.0 -result.a) * color.a;
}

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

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

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

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

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

98
#ifdef ENABLE_SHADOWING
99
        float shadowSamplingStepSize = 2 * _samplingStepSize;
100
101
        // simple and expensive implementation of hard shadows
        if (color.a > 0.1) {
102
            bool finished = false;
103
            // compute direction from sample to light
104
            vec3 L = normalize(worldToTexture(_volumeTextureParams, _lightSource._position) - samplePosition) * shadowSamplingStepSize;
105
106

            vec3 position = samplePosition + L;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
            jitterEntryPoint(position, L, _jitterStepSizeMultiplier);

            int lightSamples = SHADOW_STEPS;
#ifdef ENABLE_COLORED_SHADOWING
// NOTE: This is probably still somehow wrong..
            vec4 shadowFactor = vec4(0.0);

            // traverse ray from sample to light
            while (! finished) {
                // grab intensity and TF opacity
                intensity = texture(_volume, position).r;
                vec4 shadowSample = lookupTF(_transferFunction, _transferFunctionParams, intensity);

                //shadowSample.rgb = shadowSample.rgb;
                shadowSample.a = 1.0 - pow(1.0 - shadowSample.a, shadowSamplingStepSize * SAMPLING_BASE_INTERVAL_RCP * _shadowIntensity * 10);
                //shadowSample.a *= _shadowIntensity;
                blendUnder(shadowFactor, shadowSample);

                position += L;
                finished = /*(shadowFactor.a > 0.95)
                         ||*/ --lightSamples < 0
                         || any(lessThan(position, vec3(0.0, 0.0, 0.0)))
                         || any(greaterThan(position, vec3(1.0, 1.0, 1.0)));
            }
            blendUnder(shadowFactor, vec4(_lightSource._diffuseColor, 1.f));
            //blendUnder(shadowFactor, vec4(1.f, 1.f, 1.f, 1.f));
            // apply shadow to color
            color.rgb *= shadowFactor.rgb;
#else
136
137
138
139
140
            float shadowFactor = 0.0;

            // traverse ray from sample to light
            while (! finished) {
                // grab intensity and TF opacity
141
                intensity = texture(_volume, position).r;
142
                shadowFactor += lookupTF(_transferFunction, _transferFunctionParams, intensity).a;
143
144

                position += L;
145
146
                finished = //(shadowFactor > 0.95)
                        --lightSamples < 0
147
148
149
150
                         || any(lessThan(position, vec3(0.0, 0.0, 0.0)))
                         || any(greaterThan(position, vec3(1.0, 1.0, 1.0)));
            }
            // apply shadow to color
151
152
            color.rgb *= exp(- shadowFactor * shadowSamplingStepSize * _shadowIntensity * 1000.0);
#endif // ENABLE_COLORED_SHADOWING
153
        }
154
#endif // ENABLE_SHADOWS
155

schultezub's avatar
schultezub committed
156
157
        // perform compositing
        if (color.a > 0.0) {
158
159
#ifdef ENABLE_SHADING
            // compute gradient (needed for shading and normals)
160
            vec3 gradient = computeGradient(_volume, _volumeTextureParams, samplePosition);
161
            vec4 worldPos = _volumeTextureParams._textureToWorldMatrix * vec4(samplePosition, 1.0); // calling textureToWorld here crashes Intel HD driver and nVidia driver in debug mode, hence, let's calc it manually...
162
163
            vec3 normal = -normalize(_volumeTextureParams._textureToWorldMatrixInvTransp * vec4(gradient, 0.0)).xyz; // negated because gradient is along increasing intensity but we want a surface normal
            color.rgb = calculatePhongShading(worldPos.xyz / worldPos.w, _lightSource, _cameraPosition, normal, color.rgb);
164
#endif
165

166
            // accomodate for variable sampling rates
schultezub's avatar
schultezub committed
167
            color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
168
            blendUnder(result, color);
schultezub's avatar
schultezub committed
169
170
171
        }

        // save first hit ray parameter for depth value calculation
172
        if (firstHitT < 0.0 && result.a > 0.0) {
173
            firstHitT = t;
174
            out_FHP = vec4(samplePosition, 1.0);
175
            out_FHN = vec4(normalize(computeGradient(_volume, _volumeTextureParams, samplePosition)), 1.0);
176
        }
schultezub's avatar
schultezub committed
177
178

        // early ray termination
schultezub's avatar
schultezub committed
179
        if (result.a > 0.975) {
schultezub's avatar
schultezub committed
180
181
182
183
            result.a = 1.0;
            t = tend;
        }

184
        // advance to the next evaluation point along the ray
schultezub's avatar
schultezub committed
185
186
187
188
189
        t += _samplingStepSize;
    }

    // calculate depth value from ray parameter
    gl_FragDepth = 1.0;
190
    if (firstHitT >= 0.0) {
191
192
        float depthEntry = texture(_entryPointsDepth, texCoords).z;
        float depthExit = texture(_exitPointsDepth, texCoords).z;
193
194
        gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
    }
schultezub's avatar
schultezub committed
195
196
197
198
199
200
201
202
    return result;
}

/***
 * The main method.
 ***/
void main() {
    vec2 p = gl_FragCoord.xy * _viewportSizeRCP;
203
204
    vec3 frontPos = texture(_entryPoints, p).rgb;
    vec3 backPos = texture(_exitPoints, p).rgb;
schultezub's avatar
schultezub committed
205
206
207
208
209
210
211

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