// ================================================================================================ // // 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 // 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; uniform LightSource _lightSource; uniform vec3 _cameraPosition; uniform float _samplingStepSize; #ifdef ENABLE_SHADOWING uniform float _shadowIntensity; #endif const float SAMPLING_BASE_INTERVAL_RCP = 200.0; 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; } /** * 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); while (t < tend) { // compute sample position vec3 samplePosition = entryPoint.rgb + t * direction; // lookup intensity and TF float intensity = texture(_volume, samplePosition).r; vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity); #ifdef ENABLE_SHADOWING float shadowSamplingStepSize = 2 * _samplingStepSize; // simple and expensive implementation of hard shadows if (color.a > 0.1) { bool finished = false; // compute direction from sample to light vec3 L = normalize(worldToTexture(_volumeTextureParams, _lightSource._position) - samplePosition) * shadowSamplingStepSize; vec3 position = samplePosition + L; 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 float shadowFactor = 0.0; // traverse ray from sample to light while (! finished) { // grab intensity and TF opacity intensity = texture(_volume, position).r; shadowFactor += lookupTF(_transferFunction, _transferFunctionParams, intensity).a; position += L; finished = //(shadowFactor > 0.95) --lightSamples < 0 || any(lessThan(position, vec3(0.0, 0.0, 0.0))) || any(greaterThan(position, vec3(1.0, 1.0, 1.0))); } // apply shadow to color color.rgb *= exp(- shadowFactor * shadowSamplingStepSize * _shadowIntensity * 1000.0); #endif // ENABLE_COLORED_SHADOWING } #endif // ENABLE_SHADOWS // perform compositing if (color.a > 0.0) { #ifdef ENABLE_SHADING // compute gradient (needed for shading and normals) vec3 gradient = computeGradient(_volume, _volumeTextureParams, 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(_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); #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.0) { firstHitT = t; out_FHP = vec4(samplePosition, 1.0); out_FHN = vec4(normalize(computeGradient(_volume, _volumeTextureParams, 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; } /*** * 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); } }