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 {
*/
size_t getNumBrickIndices() const;
/**
* Gets the number of voxels a brick is covering in each dimension.
* \return _brickSize
*/
size_t getBrickSize() const;
......
......@@ -73,7 +73,7 @@ uniform vec3 _cameraPosition;
uniform float _samplingStepSize;
#ifdef ENABLE_ADAPTIVE_STEPSIZE
#ifdef INTERSECTION_REFINEMENT
bool _inVoid = false;
#endif
......@@ -101,15 +101,21 @@ bool lookupInBbv(in vec3 samplePosition) {
return (texel & (1U << bit)) != 0U;
}
float rayBoxIntersection(in vec3 rayOrigin, in vec3 rayDirection, in vec3 box[2], in float t) {
vec3 rayInverseDirection = 1.f / rayDirection;
ivec3 raySign = ivec3(lessThan(rayDirection, vec3(0.0, 0.0, 0.0));
float rayBoxIntersection(in vec3 rayOrigin, in vec3 rayDirection, in vec3 boxLlf, in vec3 boxUrb, in float t) {
vec3 tMin = (boxLlf - rayOrigin) / rayDirection;
vec3 tMax = (boxUrb - rayOrigin) / rayDirection;
vec3 tMin = (box[raySign] - rayOrigin) / rayInverseDirection;
vec3 tMax = (box[1 - raySign] - rayOrigin) / rayInverseDirection;
// TODO: these many ifs are expensive - the lessThan bvec solution below should be faster but does not work for some reason...
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;
tMax *= vec3(lessThan(tMax, vec3(t, t, t)) * positiveInfinity;
if (tMax.x < t) tMax.x = 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)));
}
......@@ -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 result = vec4(0.0);
float firstHitT = -1.0;
#ifdef ENABLE_ADAPTIVE_STEPSIZE
float samplingRateCompensationMultiplier = 1.0;
#endif
// calculate ray parameters
vec3 direction = exitPoint.rgb - entryPoint.rgb;
......@@ -136,17 +139,15 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
// compute sample position
vec3 samplePosition = entryPoint.rgb + t * direction;
// check whether we have a lookup volume for empty space skipping
if (_hasBbv) {
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 += 4.0*_samplingStepSize;
#ifdef ENABLE_ADAPTIVE_STEPSIZE
samplingRateCompensationMultiplier = 1.0;
#endif
continue;
t = rayBoxIntersection(entryPoint, direction, boxLlf, boxUrb, t);
}
}
......@@ -154,7 +155,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
float intensity = getElement3DNormalized(_volume, _volumeTextureParams, samplePosition).a;
vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity);
#ifdef ENABLE_ADAPTIVE_STEPSIZE
#ifdef INTERSECTION_REFINEMENT
if (color.a <= 0.0) {
// we're within void, make the steps bigger
_inVoid = true;
......@@ -189,32 +190,6 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
}
#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
if (color.a > 0.0) {
#ifdef ENABLE_SHADING
......@@ -224,11 +199,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
#endif
// 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);
#endif
result.rgb = mix(color.rgb, result.rgb, result.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)
}
// 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;
#endif
}
// calculate depth value from ray parameter
......@@ -263,6 +228,7 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
float depthExit = getElement2DNormalized(_exitPointsDepth, _exitParams, texCoords).z;
gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
}
return result;
}
......
......@@ -43,15 +43,15 @@ namespace campvis {
, 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_shadowIntensity("ShadowIntensity", "Shadow Intensity", .5f, .0f, 1.f)
, p_enableAdaptiveStepsize("EnableAdaptiveStepSize", "Enable Adaptive Step Size", true, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_SHADER)
, p_useEmptySpaceSkipping("EnableEmptySpaceSkipping", "Enable Empty Space Skipping", false, AbstractProcessor::INVALID_RESULT | INVALID_BBV)
, p_enableIntersectionRefinement("EnableIntersectionRefinement", "Enable Intersection Refinement", false, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_SHADER)
, p_useEmptySpaceSkipping("EnableEmptySpaceSkipping", "Enable Empty Space Skipping", true, AbstractProcessor::INVALID_RESULT | INVALID_BBV)
, _bbv(0)
, _t(0)
{
addDecorator(new ProcessorDecoratorShading());
addProperty(&p_targetImageID);
addProperty(&p_enableAdaptiveStepsize);
addProperty(&p_enableIntersectionRefinement);
addProperty(&p_useEmptySpaceSkipping);
addProperty(&p_enableShadowing);
......@@ -69,6 +69,8 @@ namespace campvis {
void OptimizedRaycaster::init() {
RaycastingProcessor::init();
invalidate(INVALID_BBV);
}
void OptimizedRaycaster::deinit() {
......@@ -112,12 +114,12 @@ namespace campvis {
FramebufferActivationGuard fag(this);
createAndAttachTexture(GL_RGBA8);
// createAndAttachTexture(GL_RGBA32F);
// createAndAttachTexture(GL_RGBA32F);
createAndAttachTexture(GL_RGBA32F);
createAndAttachTexture(GL_RGBA32F);
createAndAttachDepthTexture();
// static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 };
// glDrawBuffers(3, buffers);
static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, buffers);
if (p_enableShadowing.getValue())
_shader->setUniform("_shadowIntensity", p_shadowIntensity.getValue());
......@@ -125,6 +127,8 @@ namespace campvis {
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad();
glDrawBuffers(1, buffers);
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
......@@ -135,8 +139,8 @@ namespace campvis {
std::string toReturn = RaycastingProcessor::generateHeader();
if (p_enableShadowing.getValue())
toReturn += "#define ENABLE_SHADOWING\n";
if (p_enableAdaptiveStepsize.getValue())
toReturn += "#define ENABLE_ADAPTIVE_STEPSIZE\n";
if (p_enableIntersectionRefinement.getValue())
toReturn += "#define INTERSECTION_REFINEMENT\n";
return toReturn;
}
......@@ -157,7 +161,7 @@ namespace campvis {
else {
if (const ImageData* id = dynamic_cast<const ImageData*>(dh.getData())) {
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);
size_t tfNumElements = p_transferFunction.getTF()->getTexture()->getDimensions().x;
......
......@@ -69,7 +69,7 @@ namespace campvis {
/// \see AbstractProcessor::getAuthor()
virtual const std::string getAuthor() const { return "Christian Schulte zu Berge <christian.szb@in.tum.de>"; };
/// \see AbstractProcessor::getProcessorState()
virtual ProcessorState getProcessorState() const { return AbstractProcessor::TESTING; };
virtual ProcessorState getProcessorState() const { return AbstractProcessor::EXPERIMENTAL; };
/// \see AbstractProcessor::init
virtual void init();
......@@ -79,7 +79,7 @@ namespace campvis {
DataNameProperty p_targetImageID; ///< image ID for output image
BoolProperty p_enableShadowing;
FloatProperty p_shadowIntensity;
BoolProperty p_enableAdaptiveStepsize;
BoolProperty p_enableIntersectionRefinement;
BoolProperty p_useEmptySpaceSkipping;
......
......@@ -34,7 +34,6 @@
#include "core/properties/floatingpointproperty.h"
#include "core/properties/genericproperty.h"
#include "core/properties/transferfunctionproperty.h"
#include "core/tools/volumebricking.h"
#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