Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

ipsviraycaster.frag 8.58 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2015, all rights reserved,
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
// 
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
// 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
// 
// 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.
// 
// ================================================================================================

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

#include "tools/gradient.frag"
#include "tools/raycasting.frag"
#include "tools/shading.frag"
#include "tools/texture2d.frag"
#include "tools/texture3d.frag"
#include "tools/transferfunction.frag"

uniform vec2 _viewportSizeRCP;
uniform float _jitterStepSizeMultiplier;


// 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;


// Illumination cache
60
61
uniform layout(rgba32f) image2D _icImageIn;
uniform layout(rgba32f) image2D _icImageOut;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
uniform vec3 _icOrigin;
uniform vec3 _icNormal;
uniform vec3 _icRightVector;
uniform vec3 _icUpVector;

uniform float _shadowIntensity = 0.5;

uniform LightSource _lightSource;
uniform vec3 _cameraPosition;

uniform float _samplingStepSize;


const float SAMPLING_BASE_INTERVAL_RCP = 200.0;

77
78
// projects a vector in world coordinates onto the IC
// returns world coordinates
79
80
81
82
ivec2 calcIcSamplePosition(vec3 worldPosition) {
    // project world position onto IC plane
    const vec3 diag = worldPosition - _icOrigin;
    const float distance = abs(dot(diag, _icNormal));
83
84
85
86
    const vec3 worldProjected = diag - (-distance * _icNormal);

    // transforms world coordinates (have to be lying on the IC plane) to IC pixel space
    return ivec2(round(dot(worldProjected, _icRightVector)), round(dot(worldProjected, _icUpVector)));
87
88
}

89
void composite(vec3 startPosition, vec3 endPosition, inout float opacity) {
90
    vec3 direction = endPosition - startPosition;
91
92
93
94
    float t = _samplingStepSize;
    jitterFloat(t, _samplingStepSize); // jitter startpoint to avoid ringing artifacts (not really effective...)

    float tend = min(length(direction), 4*_samplingStepSize);
95
96
97
98
    direction = normalize(direction);

    while (t < tend) {
        // lookup intensity and TF
99
        vec3 samplePosition = startPosition.xyz + t * direction;
100
101
102
103
        float intensity = texture(_volume, samplePosition).r;
        float tfOpacity = lookupTF(_transferFunction, _transferFunctionParams, intensity).a;
        opacity = opacity + (1.0 - opacity) * tfOpacity;

104
        t += _samplingStepSize;
105
106
107
    }
}

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

/**
 * Performs the raycasting and returns the final fragment color.
 */
vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) {
    vec4 result = vec4(0.0);
    float firstHitT = -1.0;

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

    jitterEntryPoint(entryPoint, direction, _samplingStepSize * _jitterStepSizeMultiplier);

124
    ivec2 icPositionPrev = calcIcSamplePosition(textureToWorld(_volumeTextureParams, entryPoint));
125
    vec4 icIn = imageLoad(_icImageIn, icPositionPrev);
126
    vec4 icOut = vec4(0.0);
127
    bool toBeSaved = false;
128
129
130
131

    while (t < tend) {
        // compute sample position
        vec3 samplePosition = entryPoint.rgb + t * direction;
132
133
134
        vec3 worldPos = textureToWorld(_volumeTextureParams, samplePosition);
        ivec2 icPosition = calcIcSamplePosition(worldPos);

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
        // optimization: Only store/load when the icPosition has changed
        // otherwise we can reuse the variables from the previous sample
        if (icPositionPrev != icPosition) {
            // if there is no updated illumination information to be saved, 
            // carry over the old pixel
            if (! toBeSaved)
                icOut = imageLoad(_icImageIn, icPositionPrev);

            // write illumination information
            imageStore(_icImageOut, icPositionPrev, icOut);
            toBeSaved = false;
            
            // load illumination information
            icIn = imageLoad(_icImageIn, icPosition);

            // perform a compositing from samplePosition to the samplePosition of the IC
            // Currently disabled since it leads to ringing artifacts...
            //if (icIn.xyz != vec3(0.0))
            //    composite(samplePosition, icIn.xyz, icIn.a);
        }
155
156
157
158
159
160
161
162
163

        // lookup intensity and TF
        float intensity = texture(_volume, samplePosition).r;
        vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity);

        // perform compositing
        if (color.a > 0.0) {
            // compute gradient (needed for shading and normals)
            vec3 gradient = computeGradient(_volume, _volumeTextureParams, samplePosition);
164
            color.rgb = calculatePhongShading(worldPos, _lightSource, _cameraPosition, gradient, color.rgb);
165
166
167
168
169

            // accomodate for variable sampling rates
            color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);

            // perform global illumination
170
171
172
173
            // back-to-front compositing from light-direction 
            // (for now, we ignore the color contribution and store the world position instead)
            // icOut.rgb = ((1.0 - color.a) * icIn.rgb) + (color.a * color.rgb);
            icOut.xyz = samplePosition;
174
            icOut.a   = ((1.0 - color.a) * icIn.a) + color.a;
175
            toBeSaved = true;
176
177

            // apply shadowing
178
            color.rgb *= (1.0 - icIn.a * _shadowIntensity); 
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203

            // front-to-back compositing along view direction
            result.rgb = result.rgb + color.rgb * color.a  * (1.0 - result.a);
            result.a = result.a + (1.0 -result.a) * color.a;

            icPositionPrev = icPosition;
        }

        // save first hit ray parameter for depth value calculation
        if (firstHitT < 0.0 && result.a > 0.0) {
            firstHitT = t;
            out_FHP = vec4(samplePosition, 1.0);
            out_FHN = vec4(icPosition, 0.0, 0.0);// vec4(normalize(computeGradient(_volume, _volumeTextureParams, samplePosition)), 1.0);
        }

        // early ray termination (disabled!)
        //if (result.a > 0.975) {
        //    result.a = 1.0;
        //    t = tend;
        //}

        // advance to the next evaluation point along the ray
        t += _samplingStepSize;
    }

204
205
206
207
208
209
210
    if (toBeSaved) {
        imageStore(_icImageOut, icPositionPrev, icOut);
    }
    else {
        imageStore(_icImageOut, icPositionPrev, imageLoad(_icImageIn, icPositionPrev));
    }

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
    // calculate depth value from ray parameter
    gl_FragDepth = 1.0;
    if (firstHitT >= 0.0) {
        float depthEntry = texture(_entryPointsDepth, texCoords).z;
        float depthExit = texture(_exitPointsDepth, texCoords).z;
        gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
    }
    return result;
}

/***
 * The main method.
 ***/
void main() {
    vec2 p = gl_FragCoord.xy * _viewportSizeRCP;
    vec3 frontPos = texture(_entryPoints, p).rgb;
    vec3 backPos = texture(_exitPoints, p).rgb;

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