Notice: If you are member of any public project or group, please make sure that your GitLab username is not the same as the LRZ identifier/Kennung (see https://gitlab.lrz.de/profile/account). Please change your username if necessary. For more information see the section "Public projects / Öffentliche Projekte" at https://doku.lrz.de/display/PUBLIC/GitLab . Thank you!

Commit 5cbfe490 authored by Jakob Weiss's avatar Jakob Weiss

Merge branch 'advanced-raycasting' into campvis-nx

parents e20da19c cd918f81
......@@ -109,7 +109,7 @@ namespace campvis {
return new TFGeometry1D(keyPoints);
}
TFGeometry1D* TFGeometry1D::crateRamp(const cgt::vec2& interval, const cgt::col4& color) {
TFGeometry1D* TFGeometry1D::createRamp(const cgt::vec2& interval, const cgt::col4& color) {
return createQuad(interval, cgt::col4(color.xyz(), 0), cgt::col4(color.xyz(), 255));
}
......@@ -163,4 +163,4 @@ namespace campvis {
return cgt::vec2(_keyPoints.front()._position, _keyPoints.back()._position);
}
}
\ No newline at end of file
}
......@@ -132,7 +132,7 @@ namespace campvis {
* \param color Color for ramp
* \return A TFGeometry1D modelling a ramp with two KeyPoints.
*/
static TFGeometry1D* crateRamp(const cgt::vec2& interval, const cgt::col4& color);
static TFGeometry1D* createRamp(const cgt::vec2& interval, const cgt::col4& color);
/**
* Creates a diverging color map of two diverging colors blending over white.
......
......@@ -171,4 +171,22 @@ float getPhongShadingIntensity(in vec3 position, in LightSource light, in vec3 c
toReturn *= computeAttenuation(light._attenuation, d);
#endif
return (toReturn.x + toReturn.y + toReturn.z) / 3.0;
}
\ No newline at end of file
}
vec3 calculateContourShading(in vec3 position, in vec3 camera, in vec3 normal, in vec3 materialColor, in vec3 outlineColor, in float contourExponent) {
float outlineStrength = 1. - pow(clamp(-dot(normalize(normal), normalize(position - camera)), 0, 1), contourExponent);
return mix(materialColor, outlineColor, outlineStrength);
}
vec4 calculateContourShading2(in vec3 position, in vec3 camera, in vec3 normal, in vec4 materialColor, in vec4 outlineColor, in float contourExponent) {
float outlineStrength = 1. - pow(clamp(dot(normal, normalize(camera - position)), 0, 1), contourExponent);
return outlineStrength * outlineColor;
}
void blendUnder(inout vec4 colorAbove, in vec4 colorBelow)
{
colorAbove.rgb = colorAbove.rgb + colorBelow.rgb * colorBelow.a * (1.0 - colorAbove.a);
colorAbove.a = colorAbove.a + (1.0 -colorAbove.a) * colorBelow.a;
}
# CMake file for vis module
SET(ThisModStatus EXPERIMENTAL)
IF(${ModuleEnabled})
# Source files:
FILE(GLOB ThisModSources RELATIVE ${ModulesDir}
modules/advancedraycasting/decorators/*.cpp
modules/advancedraycasting/pipelines/*.cpp
modules/advancedraycasting/processors/*.cpp
modules/advancedraycasting/tools/*.cpp
modules/advancedraycasting/*.cpp
)
# Header files (including GLSL files so that they'll appear in VS projects)
FILE(GLOB ThisModHeaders RELATIVE ${ModulesDir}
modules/advancedraycasting/glsl/*.frag
modules/advancedraycasting/glsl/*.geom
modules/advancedraycasting/glsl/*.vert
modules/advancedraycasting/glsl/*.comp
modules/advancedraycasting/decorators/*.h
modules/advancedraycasting/pipelines/*.h
modules/advancedraycasting/processors/*.h
modules/advancedraycasting/tools/*.h
)
LIST(APPEND ThisModShaderDirectories "modules/vis/glsl")
SET(ThisModDependencies base vis)
ENDIF(${ModuleEnabled})
SET(ThisModStatus STABLE)
SET(ThisModExternalDependencies FALSE)
// ================================================================================================
//
// 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.
//
// ================================================================================================
#include "core/pipeline/pipelinefactory.h"
#include "core/pipeline/processorfactory.h"
#include "modules/advancedraycasting/pipelines/preintegratedraycasterdemo.h"
#include "modules/advancedraycasting/processors/ambientvolumegenerator.h"
#include "modules/advancedraycasting/processors/laoraycaster.h"
#include "modules/advancedraycasting/processors/preintegratedraycaster.h"
#include "modules/advancedraycasting/processors/tfpreintegrator.h"
namespace campvis {
// explicitly instantiate templates to register the pipelines
template class PipelineRegistrar<PreintegratedRayCasterDemo>;
template class SmartProcessorRegistrar<AmbientVolumeGenerator>;
template class SmartProcessorRegistrar<LAORaycaster>;
template class SmartProcessorRegistrar<PreintegratedRaycaster>;
template class SmartProcessorRegistrar<TFPreIntegrator>;
}
// ================================================================================================
//
// 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.
//
// ================================================================================================
#include "localambientocclusiondecorator.h"
#include "cgt/shadermanager.h"
#include "cgt/textureunit.h"
#include "core/properties/propertycollection.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/renderdata.h"
#include "core/classification/geometry1dtransferfunction.h"
namespace campvis {
LocalAmbientOcclusionDecorator::LocalAmbientOcclusionDecorator()
: AbstractProcessorDecorator()
, p_aoRays("AORays", "Number of directional samples", 8, 0, 50)
, p_aoSamples("AOSamples", "Number of Samples per ray (controls size of AO sphere)", 10, 0, 80)
, p_aoSphereRadius("AOSphereRadius", "AO Sphere Radius [voxels]", 8.0f, 0.1f, 50.0f, 0.25f)
, p_aoOpacityScale("OpacityScale", "Opacity Scaling", 1.0f, 0.0f, 5.f)
, p_aoEffectGamma("AOEffectGamma", "AO Scale Gamma", 1.0f, .0f, 5.f)
, p_aoEmissiveTransferFunction("AOTransferFunction", "Emissive Transfer Function", new Geometry1DTransferFunction(128))
, p_aoEmissiveScale("EmissiveScale", "Emissive Color Scaling", 1.0f, 0.0f, 10.f)
{
}
LocalAmbientOcclusionDecorator::~LocalAmbientOcclusionDecorator() {
}
void LocalAmbientOcclusionDecorator::addProperties(AbstractProcessor* propCollection) {
propCollection->addProperty(p_aoRays, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_PROPERTIES | AbstractProcessor::INVALID_SHADER);
propCollection->addProperty(p_aoSamples, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_PROPERTIES | AbstractProcessor::INVALID_SHADER);
propCollection->addProperty(p_aoSphereRadius);
propCollection->addProperty(p_aoOpacityScale);
propCollection->addProperty(p_aoEffectGamma);
propCollection->addProperty(p_aoEmissiveTransferFunction);
propCollection->addProperty(p_aoEmissiveScale);
}
void LocalAmbientOcclusionDecorator::renderProlog(const DataContainer& dataContainer, cgt::Shader* shader) {
auto aotf = p_aoEmissiveTransferFunction.getTF();
_aoTFUnit = std::make_unique<cgt::TextureUnit>();
aotf->bind(shader, *_aoTFUnit, "_aoEmissiveTF", "_aoEmissiveTFParams");
shader->setUniform("_aoSphereRadius", p_aoSphereRadius.getValue());
shader->setUniform("_aoGamma", p_aoEffectGamma.getValue());
shader->setUniform("_aoEmissiveScale", p_aoEmissiveScale.getValue());
shader->setUniform("_aoOpacityScale", p_aoOpacityScale.getValue());
}
void LocalAmbientOcclusionDecorator::renderEpilog(cgt::Shader * shader)
{
// delete the TF texture unit
_aoTFUnit = nullptr;
}
std::string LocalAmbientOcclusionDecorator::generateHeader() const
{
std::string toReturn;
// the defines need to exist before the include
toReturn +=
"#define NUM_AO_RAYS " + std::to_string(p_aoRays.getValue()) + "\n"
"#define NUM_AO_RAY_STEPS " + std::to_string(p_aoSamples.getValue()) + "\n"
"\n"
"uniform float _aoSphereRadius;\n"
"uniform float _aoGamma;\n"
"uniform float _aoOpacityScale;\n"
"uniform float _aoEmissiveScale;\n"
"\n"
"#define AO_GAMMA _aoGamma\n"
"#define AO_OPACITY_SCALE _aoOpacityScale\n"
"#define AO_EMISSIVE_SCALE _aoEmissiveScale\n";
// the include has the actual functions
toReturn += "#include \"modules/advancedraycasting/glsl/localambientocclusion.frag\"\n";
return toReturn;
}
}
// ================================================================================================
//
// 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.
//
// ================================================================================================
#ifndef LOCALAMBIENTOCCLUSIONDECORATOR_H__
#define LOCALAMBIENTOCCLUSIONDECORATOR_H__
#include "core/pipeline/abstractprocessordecorator.h"
#include "core/properties/floatingpointproperty.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/colorproperty.h"
#include "core/properties/optionproperty.h"
#include "core/properties/transferfunctionproperty.h"
#include "modules/modulesapi.h"
namespace cgt {
class TextureUnit;
}
namespace campvis {
/**
* \class RaycastingGridDecorator
* Provides a fragment shader function that can test samples and modify their opacity valued to
*/
class CAMPVIS_MODULES_API LocalAmbientOcclusionDecorator : public AbstractProcessorDecorator {
public:
LocalAmbientOcclusionDecorator();
virtual ~LocalAmbientOcclusionDecorator();
protected:
void addProperties(AbstractProcessor* propCollection) override;
virtual void renderProlog(const DataContainer& dataContainer, cgt::Shader* shader) override;
virtual void renderEpilog(cgt::Shader* shader) override;
virtual std::string generateHeader() const override;
IntProperty p_aoRays; ///< Number of directional AO samples
IntProperty p_aoSamples; ///< Number of steps per directional sample
FloatProperty p_aoSphereRadius; ///< The AO Sphere radius in voxels
FloatProperty p_aoEffectGamma; ///< Gamma controls the strength of the AO effect
FloatProperty p_aoOpacityScale; ///< Scales opacity when sampling for AO rays
TransferFunctionProperty p_aoEmissiveTransferFunction;
FloatProperty p_aoEmissiveScale; ///< Scales the emissive color to increase/decrease the emissive effect
std::unique_ptr<cgt::TextureUnit> _aoTFUnit;
};
}
#endif // LOCALAMBIENTOCCLUSIONDECORATOR_H__
// ================================================================================================
//
// 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.
//
// ================================================================================================
// (c) 2017 Jakob Weiss <jakob.weiss@tum.de>
// ==================== Shader for median filtering. ====================
// Expects the following dynamic defines:
//
// #define OUTPUT_TEXTURE_FORMAT
// The texture format of the output texture. Preferrably specified through Texture::calcMatchingWriteFormat()
//
// uniform _outputImage
// dynamically defined (i|u)image(1|2|3)D uniform to allow imageStore operation of the output
// #define TEXTURE_DIMENSIONALITY
// The dimensionality of the texture [1,2,3]
// The work group size can be overridden by dynamic defines
#ifndef WORK_GROUP_SIZE_X
#define WORK_GROUP_SIZE_X 1
#endif
#ifndef WORK_GROUP_SIZE_Y
#define WORK_GROUP_SIZE_Y 1
#endif
#ifndef WORK_GROUP_SIZE_Z
#define WORK_GROUP_SIZE_Z 1
#endif
#include "tools/transferfunction.frag"
// volume
uniform sampler3D _volume;
uniform TextureParameters3D _volumeTextureParams;
// Transfer function
uniform sampler1D _transferFunction;
uniform TFParameters1D _transferFunctionParams;
// Transfer function
uniform sampler1D _aoEmissiveTF;
uniform TFParameters1D _aoEmissiveTFParams;
layout(local_size_x = WORK_GROUP_SIZE_X, local_size_y = WORK_GROUP_SIZE_Y, local_size_z = WORK_GROUP_SIZE_Z) in;
void main() {
// get index in global work group i.e x,y position
ivec3 pixel_coords = ivec3(gl_GlobalInvocationID.xyz);
vec3 samplePosition = vec3(pixel_coords)*_volumeTextureParams._sizeRCP;
float sampleIntensity = texture(_volume, samplePosition).r;
vec4 sampleTFColor = lookupTF(_transferFunction, _transferFunctionParams, sampleIntensity);
// precompute the LAO ray directions
vec4 aoRayDirs[NUM_AO_RAYS];
initLAODirs(aoRayDirs, _aoSphereRadius, _volumeTextureParams);
vec3 ambientOcclusion = computeLAO(samplePosition, aoRayDirs, _volume, _transferFunction, _transferFunctionParams, _aoEmissiveTF, _aoEmissiveTFParams);
vec4 result = vec4(ambientOcclusion, sampleTFColor.a);
// output to a specific pixel in the image
#if TEXTURE_DIMENSIONALITY == 1
imageStore(_outputImage, pixel_coords.x, vec4(result));
#elif TEXTURE_DIMENSIONALITY == 2
imageStore(_outputImage, pixel_coords.xy, vec4(result));
#else
imageStore(_outputImage, pixel_coords, vec4(result));
#endif
}
// (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;
}
// ================================================================================================
//
// 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;
// volume
uniform sampler3D _volume;
uniform TextureParameters3D _volumeTextureParams;
// Transfer function
uniform sampler1D _transferFunction;
uniform TFParameters1D _transferFunctionParams;
// Transfer function
uniform sampler1D _aoEmissiveTF;
uniform TFParameters1D _aoEmissiveTFParams;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
uniform float _samplingStepSize;
const float SAMPLING_BASE_INTERVAL_RCP = 200.0;
//#define DEBUG_AO_DIRECTIONS
/**
* 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);
// precompute the LAO ray directions
vec4 aoRayDirs[NUM_AO_RAYS];
initLAODirs(aoRayDirs, _aoSphereRadius, _volumeTextureParams);
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 DEBUG_AO_DIRECTIONS
// allows to quickly check if the ray directions are uniformly distributed even for non-uniform volume/voxel sizes
color = vec4(0);
for(int i=0; i < NUM_AO_RAYS; ++i) {
//vec3 dir = nthSphereSample(1.0, i, NUM_AO_RAYS);
vec4 dir = aoRayDirs[i];
vec3 p = samplePosition - vec3(0.5);// + dir.xyz*200;
float d = 1. - clamp(dot(normalize(p), normalize(dir.xyz)), 0, 1);
float r = length(p) - 10*length(dir.xyz);
//r *= smoothstep(0.4, 0.5, length(p));
float a= clamp(exp(-d*d/0.01) * exp(-r*r/0.001), 0, 1);
if(r > 0 && color.a < a) {
color.rgb = abs(normalize(dir.xyz));
color.a = a;
}
}
// accomodate for variable sampling rates
color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
blendUnder(result, color);
#else
// perform compositing
if (color.a > 0.0) {
vec3 n;
vec3 ambientOcclusion = computeLAO(samplePosition, aoRayDirs, _volume, _transferFunction, _transferFunctionParams, _aoEmissiveTF, _aoEmissiveTFParams, n);
vec4 aoSampleColor = lookupTF(_aoEmissiveTF, _aoEmissiveTFParams, intensity);
// emissive transfer function overrides the original TF color
if(aoSampleColor.a > 0) {
color.rgb = aoSampleColor.rgb;
}
#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
vec3 normal = -normalize(_volumeTextureParams._textureToWorldMatrixInvTransp * vec4(n, 0.0)).xyz; // negated because gradient is along increasing intensity but we want a surface normal
color.rgb = calculatePhongShading(worldPos.xyz / worldPos.w, ambientOcclusion, _lightSource, _cameraPosition, normal, color.rgb);
#else
color.rgb *= ambientOcclusion;//*normalize(abs(n));
#endif
// With this enabled, raycaster will show the influence of the AO comptuation. useful for parameter tuning and debugging
#ifdef SHOW_AO_ONLY
color.rgb = ambientOcclusion;
#endif
// accomodate for variable sampling rates
color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
blendUnder(result, color);
}
#endif
// 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