24.09., 9:00 - 11:00: Due to updates GitLab will be unavailable for some minutes between 09:00 and 11:00.

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