genericraycastingloop.frag 4.21 KB
Newer Older
Jakob Weiss's avatar
Jakob Weiss committed
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124


// (c) 2017 Jakob Weiss

/**
 ** Prerequisites: **

  - _samplingStepSize
  - _jitterStepSizeMultiplier
  - _lightSource

  - vec4 getSampleColor(vec3 sampleTexPos)
  - float getSampleAlpha(vec3 sampleTexPos)
  - vec3 getSampleGradient(vec3 sampleTexPos)
  
  If ENABLE_SHADOWING is set:
  - _lightSource
  - _shadowIntensity

  If ENABLE_SHADING is set:
  - _lightSource
  - _cameraPosition

 */

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

#ifdef ENABLE_SHADOWING
    vec3 lightSourcePositionInTex = worldToTexture(_volumeTextureParams, _lightSource._position);
#endif

    while (t < tend) {
        // compute sample position
        vec3 samplePosition = entryPoint.rgb + t * direction;

        // lookup intensity and TF
        vec4 color = getSampleColor(samplePosition);

#ifdef ENABLE_SHADOWING
        float shadowSamplingStepSize = 2 * _samplingStepSize;
        // compute direction from sample to light
        vec3 L = normalize(lightSourcePositionInTex - samplePosition) * shadowSamplingStepSize;

        // simple and expensive implementation of hard shadows
        if (color.a > 0.01) {
            bool finished = false;

            vec3 shadowSamplePosition = samplePosition + L;
            jitterEntryPoint(shadowSamplePosition, L, _jitterStepSizeMultiplier);

            int lightSamples = SHADOW_STEPS;

            float shadowFactor = 0.0;

            // traverse ray from sample to light
            while (! finished) {
                // grab transparency for the shadow sample
                shadowFactor += getSampleAlpha(shadowSamplePosition);

                shadowSamplePosition += L;
                finished = //(shadowFactor > 0.95)
                        --lightSamples < 0
                         || any(lessThan(shadowSamplePosition, vec3(0.0, 0.0, 0.0)))
                         || any(greaterThan(shadowSamplePosition, vec3(1.0, 1.0, 1.0)));
            }
            // apply shadow to color
            color.rgb *= exp(- shadowFactor * shadowSamplingStepSize * _shadowIntensity * SAMPLING_BASE_INTERVAL_RCP);
        }
#endif // ENABLE_SHADOWS

        // perform compositing
        if (color.a > 0.0) {
#ifdef ENABLE_SHADING
            // compute gradient (needed for shading and normals)
            vec3 gradient = getSampleGradient(samplePosition);
            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...
            vec3 normal = -normalize(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);
#endif

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

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

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

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

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