Commit 148ab63c authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Further work on OptimizedRaycaster:

 * Finished implementation of empty space skipping
 * Renamed Adaptive Step Size to Intersection Refinement (which is more precise in terms of what it's doing)
parent c38abe1a
...@@ -32,6 +32,10 @@ namespace campvis { ...@@ -32,6 +32,10 @@ namespace campvis {
*/ */
size_t getNumBrickIndices() const; size_t getNumBrickIndices() const;
/**
* Gets the number of voxels a brick is covering in each dimension.
* \return _brickSize
*/
size_t getBrickSize() const; size_t getBrickSize() const;
......
...@@ -73,7 +73,7 @@ uniform vec3 _cameraPosition; ...@@ -73,7 +73,7 @@ uniform vec3 _cameraPosition;
uniform float _samplingStepSize; uniform float _samplingStepSize;
#ifdef ENABLE_ADAPTIVE_STEPSIZE #ifdef INTERSECTION_REFINEMENT
bool _inVoid = false; bool _inVoid = false;
#endif #endif
...@@ -101,15 +101,21 @@ bool lookupInBbv(in vec3 samplePosition) { ...@@ -101,15 +101,21 @@ bool lookupInBbv(in vec3 samplePosition) {
return (texel & (1U << bit)) != 0U; return (texel & (1U << bit)) != 0U;
} }
float rayBoxIntersection(in vec3 rayOrigin, in vec3 rayDirection, in vec3 box[2], in float t) { float rayBoxIntersection(in vec3 rayOrigin, in vec3 rayDirection, in vec3 boxLlf, in vec3 boxUrb, in float t) {
vec3 rayInverseDirection = 1.f / rayDirection; vec3 tMin = (boxLlf - rayOrigin) / rayDirection;
ivec3 raySign = ivec3(lessThan(rayDirection, vec3(0.0, 0.0, 0.0)); vec3 tMax = (boxUrb - rayOrigin) / rayDirection;
vec3 tMin = (box[raySign] - rayOrigin) / rayInverseDirection; // TODO: these many ifs are expensive - the lessThan bvec solution below should be faster but does not work for some reason...
vec3 tMax = (box[1 - raySign] - rayOrigin) / rayInverseDirection; if (tMin.x < t) tMin.x = positiveInfinity;
if (tMin.y < t) tMin.y = positiveInfinity;
if (tMin.z < t) tMin.z = positiveInfinity;
tMin *= vec3(lessThan(tMin, vec3(t, t, t)) * positiveInfinity; if (tMax.x < t) tMax.x = positiveInfinity;
tMax *= vec3(lessThan(tMax, vec3(t, t, t)) * positiveInfinity; if (tMax.y < t) tMax.y = positiveInfinity;
if (tMax.z < t) tMax.z = positiveInfinity;
//tMin += vec3(lessThan(tMin, vec3(t, t, t))) * positiveInfinity;
//tMax += vec3(lessThan(tMax, vec3(t, t, t))) * positiveInfinity;
return min(min(tMin.x, min(tMin.y, tMin.z)) , min(tMax.x, min(tMax.y, tMax.z))); return min(min(tMin.x, min(tMin.y, tMin.z)) , min(tMax.x, min(tMax.y, tMax.z)));
} }
...@@ -120,9 +126,6 @@ float rayBoxIntersection(in vec3 rayOrigin, in vec3 rayDirection, in vec3 box[2] ...@@ -120,9 +126,6 @@ float rayBoxIntersection(in vec3 rayOrigin, in vec3 rayDirection, in vec3 box[2]
vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) { vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) {
vec4 result = vec4(0.0); vec4 result = vec4(0.0);
float firstHitT = -1.0; float firstHitT = -1.0;
#ifdef ENABLE_ADAPTIVE_STEPSIZE
float samplingRateCompensationMultiplier = 1.0;
#endif
// calculate ray parameters // calculate ray parameters
vec3 direction = exitPoint.rgb - entryPoint.rgb; vec3 direction = exitPoint.rgb - entryPoint.rgb;
...@@ -136,17 +139,15 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) ...@@ -136,17 +139,15 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
// compute sample position // compute sample position
vec3 samplePosition = entryPoint.rgb + t * direction; vec3 samplePosition = entryPoint.rgb + t * direction;
// check whether we have a lookup volume for empty space skipping
if (_hasBbv) { if (_hasBbv) {
if (! lookupInBbv(samplePosition)) { if (! lookupInBbv(samplePosition)) {
// advance the ray to the intersection point with the current brick
vec3 brickVoxel = floor((samplePosition * _volumeTextureParams._size) / _bbvBrickSize) * _bbvBrickSize;
vec3 boxLlf = brickVoxel * _volumeTextureParams._sizeRCP;
vec3 boxUrb = boxLlf + (_volumeTextureParams._sizeRCP * _bbvBrickSize);
// advance to the next evaluation point along the ray t = rayBoxIntersection(entryPoint, direction, boxLlf, boxUrb, t);
t += 4.0*_samplingStepSize;
#ifdef ENABLE_ADAPTIVE_STEPSIZE
samplingRateCompensationMultiplier = 1.0;
#endif
continue;
} }
} }
...@@ -154,7 +155,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) ...@@ -154,7 +155,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
float intensity = getElement3DNormalized(_volume, _volumeTextureParams, samplePosition).a; float intensity = getElement3DNormalized(_volume, _volumeTextureParams, samplePosition).a;
vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity); vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity);
#ifdef ENABLE_ADAPTIVE_STEPSIZE #ifdef INTERSECTION_REFINEMENT
if (color.a <= 0.0) { if (color.a <= 0.0) {
// we're within void, make the steps bigger // we're within void, make the steps bigger
_inVoid = true; _inVoid = true;
...@@ -189,32 +190,6 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) ...@@ -189,32 +190,6 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
} }
#endif #endif
#ifdef ENABLE_SHADOWING
// simple and expensive implementation of hard shadows
if (color.a > 0.1) {
// compute direction from sample to light
vec3 L = normalize(_lightSource._position - textureToWorld(_volumeTextureParams, samplePosition).xyz) * _samplingStepSize;
bool finished = false;
vec3 position = samplePosition + L;
float shadowFactor = 0.0;
// traverse ray from sample to light
while (! finished) {
// grab intensity and TF opacity
intensity = getElement3DNormalized(_volume, _volumeTextureParams, position).a;
shadowFactor += lookupTF(_transferFunction, _transferFunctionParams, intensity).a;
position += L;
finished = (shadowFactor > 0.95)
|| 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 *= (1.0 - shadowFactor * _shadowIntensity);
}
#endif
// perform compositing // perform compositing
if (color.a > 0.0) { if (color.a > 0.0) {
#ifdef ENABLE_SHADING #ifdef ENABLE_SHADING
...@@ -224,11 +199,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) ...@@ -224,11 +199,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
#endif #endif
// accomodate for variable sampling rates // accomodate for variable sampling rates
#ifdef ENABLE_ADAPTIVE_STEPSIZE
color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * samplingRateCompensationMultiplier * SAMPLING_BASE_INTERVAL_RCP);
#else
color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP); color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
#endif
result.rgb = mix(color.rgb, result.rgb, result.a); result.rgb = mix(color.rgb, result.rgb, result.a);
result.a = result.a + (1.0 -result.a) * color.a; result.a = result.a + (1.0 -result.a) * color.a;
} }
...@@ -247,13 +218,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) ...@@ -247,13 +218,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
} }
// advance to the next evaluation point along the ray // advance to the next evaluation point along the ray
#ifdef ENABLE_ADAPTIVE_STEPSIZE
samplingRateCompensationMultiplier = (_inVoid ? 1.0 : 0.25);
t += _samplingStepSize * (_inVoid ? 1.0 : 0.125);
#else
t += _samplingStepSize; t += _samplingStepSize;
#endif
} }
// calculate depth value from ray parameter // calculate depth value from ray parameter
...@@ -263,6 +228,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) ...@@ -263,6 +228,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
float depthExit = getElement2DNormalized(_exitPointsDepth, _exitParams, texCoords).z; float depthExit = getElement2DNormalized(_exitPointsDepth, _exitParams, texCoords).z;
gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit); gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
} }
return result; return result;
} }
......
...@@ -43,15 +43,15 @@ namespace campvis { ...@@ -43,15 +43,15 @@ namespace campvis {
, p_targetImageID("targetImageID", "Output Image", "", DataNameProperty::WRITE) , p_targetImageID("targetImageID", "Output Image", "", DataNameProperty::WRITE)
, p_enableShadowing("EnableShadowing", "Enable Hard Shadows (Expensive!)", false, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_SHADER | AbstractProcessor::INVALID_PROPERTIES) , p_enableShadowing("EnableShadowing", "Enable Hard Shadows (Expensive!)", false, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_SHADER | AbstractProcessor::INVALID_PROPERTIES)
, p_shadowIntensity("ShadowIntensity", "Shadow Intensity", .5f, .0f, 1.f) , p_shadowIntensity("ShadowIntensity", "Shadow Intensity", .5f, .0f, 1.f)
, p_enableAdaptiveStepsize("EnableAdaptiveStepSize", "Enable Adaptive Step Size", true, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_SHADER) , p_enableIntersectionRefinement("EnableIntersectionRefinement", "Enable Intersection Refinement", false, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_SHADER)
, p_useEmptySpaceSkipping("EnableEmptySpaceSkipping", "Enable Empty Space Skipping", false, AbstractProcessor::INVALID_RESULT | INVALID_BBV) , p_useEmptySpaceSkipping("EnableEmptySpaceSkipping", "Enable Empty Space Skipping", true, AbstractProcessor::INVALID_RESULT | INVALID_BBV)
, _bbv(0) , _bbv(0)
, _t(0) , _t(0)
{ {
addDecorator(new ProcessorDecoratorShading()); addDecorator(new ProcessorDecoratorShading());
addProperty(&p_targetImageID); addProperty(&p_targetImageID);
addProperty(&p_enableAdaptiveStepsize); addProperty(&p_enableIntersectionRefinement);
addProperty(&p_useEmptySpaceSkipping); addProperty(&p_useEmptySpaceSkipping);
addProperty(&p_enableShadowing); addProperty(&p_enableShadowing);
...@@ -69,6 +69,8 @@ namespace campvis { ...@@ -69,6 +69,8 @@ namespace campvis {
void OptimizedRaycaster::init() { void OptimizedRaycaster::init() {
RaycastingProcessor::init(); RaycastingProcessor::init();
invalidate(INVALID_BBV);
} }
void OptimizedRaycaster::deinit() { void OptimizedRaycaster::deinit() {
...@@ -112,12 +114,12 @@ namespace campvis { ...@@ -112,12 +114,12 @@ namespace campvis {
FramebufferActivationGuard fag(this); FramebufferActivationGuard fag(this);
createAndAttachTexture(GL_RGBA8); createAndAttachTexture(GL_RGBA8);
// createAndAttachTexture(GL_RGBA32F); createAndAttachTexture(GL_RGBA32F);
// createAndAttachTexture(GL_RGBA32F); createAndAttachTexture(GL_RGBA32F);
createAndAttachDepthTexture(); createAndAttachDepthTexture();
// static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 }; static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 };
// glDrawBuffers(3, buffers); glDrawBuffers(3, buffers);
if (p_enableShadowing.getValue()) if (p_enableShadowing.getValue())
_shader->setUniform("_shadowIntensity", p_shadowIntensity.getValue()); _shader->setUniform("_shadowIntensity", p_shadowIntensity.getValue());
...@@ -125,6 +127,8 @@ namespace campvis { ...@@ -125,6 +127,8 @@ namespace campvis {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad(); QuadRdr.renderQuad();
glDrawBuffers(1, buffers);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
LGL_ERROR; LGL_ERROR;
...@@ -135,8 +139,8 @@ namespace campvis { ...@@ -135,8 +139,8 @@ namespace campvis {
std::string toReturn = RaycastingProcessor::generateHeader(); std::string toReturn = RaycastingProcessor::generateHeader();
if (p_enableShadowing.getValue()) if (p_enableShadowing.getValue())
toReturn += "#define ENABLE_SHADOWING\n"; toReturn += "#define ENABLE_SHADOWING\n";
if (p_enableAdaptiveStepsize.getValue()) if (p_enableIntersectionRefinement.getValue())
toReturn += "#define ENABLE_ADAPTIVE_STEPSIZE\n"; toReturn += "#define INTERSECTION_REFINEMENT\n";
return toReturn; return toReturn;
} }
...@@ -157,7 +161,7 @@ namespace campvis { ...@@ -157,7 +161,7 @@ namespace campvis {
else { else {
if (const ImageData* id = dynamic_cast<const ImageData*>(dh.getData())) { if (const ImageData* id = dynamic_cast<const ImageData*>(dh.getData())) {
if (const ImageRepresentationLocal* rep = id->getRepresentation<ImageRepresentationLocal>(true)) { if (const ImageRepresentationLocal* rep = id->getRepresentation<ImageRepresentationLocal>(true)) {
_bbv = new BinaryBrickedVolume(rep->getParent(), 2); _bbv = new BinaryBrickedVolume(rep->getParent(), 4);
GLubyte* tfBuffer = p_transferFunction.getTF()->getTexture()->downloadTextureToBuffer(GL_RGBA, GL_UNSIGNED_BYTE); GLubyte* tfBuffer = p_transferFunction.getTF()->getTexture()->downloadTextureToBuffer(GL_RGBA, GL_UNSIGNED_BYTE);
size_t tfNumElements = p_transferFunction.getTF()->getTexture()->getDimensions().x; size_t tfNumElements = p_transferFunction.getTF()->getTexture()->getDimensions().x;
......
...@@ -69,7 +69,7 @@ namespace campvis { ...@@ -69,7 +69,7 @@ namespace campvis {
/// \see AbstractProcessor::getAuthor() /// \see AbstractProcessor::getAuthor()
virtual const std::string getAuthor() const { return "Christian Schulte zu Berge <christian.szb@in.tum.de>"; }; virtual const std::string getAuthor() const { return "Christian Schulte zu Berge <christian.szb@in.tum.de>"; };
/// \see AbstractProcessor::getProcessorState() /// \see AbstractProcessor::getProcessorState()
virtual ProcessorState getProcessorState() const { return AbstractProcessor::TESTING; }; virtual ProcessorState getProcessorState() const { return AbstractProcessor::EXPERIMENTAL; };
/// \see AbstractProcessor::init /// \see AbstractProcessor::init
virtual void init(); virtual void init();
...@@ -79,7 +79,7 @@ namespace campvis { ...@@ -79,7 +79,7 @@ namespace campvis {
DataNameProperty p_targetImageID; ///< image ID for output image DataNameProperty p_targetImageID; ///< image ID for output image
BoolProperty p_enableShadowing; BoolProperty p_enableShadowing;
FloatProperty p_shadowIntensity; FloatProperty p_shadowIntensity;
BoolProperty p_enableAdaptiveStepsize; BoolProperty p_enableIntersectionRefinement;
BoolProperty p_useEmptySpaceSkipping; BoolProperty p_useEmptySpaceSkipping;
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "core/properties/floatingpointproperty.h" #include "core/properties/floatingpointproperty.h"
#include "core/properties/genericproperty.h" #include "core/properties/genericproperty.h"
#include "core/properties/transferfunctionproperty.h" #include "core/properties/transferfunctionproperty.h"
#include "core/tools/volumebricking.h"
#include <string> #include <string>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment