Commit 3a53f60e authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Further work on empty space skipping implementation for SimpleRaycaster

parent 52c645ed
......@@ -31,6 +31,8 @@
#include "tgt/assert.h"
#include "tgt/glmath.h"
#include "tgt/texture.h"
#include "tgt/textureunit.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
......@@ -49,12 +51,19 @@ namespace campvis {
tgtAssert(_referenceImage != 0, "Reference Image must not be 0!");
// perform ceiling integer division:
_numBricks = referenceImage->getSize();
_dimBricks = referenceImage->getSize();
for (int i = 0; i < 3; ++i)
_numBricks.elem[i] = DIV_CEIL(_numBricks.elem[i], _brickSize);
_dimBricks.elem[i] = DIV_CEIL(_dimBricks.elem[i], _brickSize);
_numBrickIndices = tgt::hmul(_numBricks);
_numElementsInBricksArray = DIV_CEIL(_numBrickIndices, 8);
// since we will pack eight values along the x axis into one byte, the _dimBricks.x must be congruent 0 mod 8.
if (_dimBricks.x % 8 != 0)
_dimBricks.x += 8 - (_dimBricks.x % 8);
_numBrickIndices = tgt::hmul(_dimBricks);
_dimPackedBricks = _dimBricks;
_dimPackedBricks.x = _dimPackedBricks.x / 8;
_numElementsInBricksArray = tgt::hmul(_dimPackedBricks);
_bricks = new uint8_t[_numElementsInBricksArray];
memset(_bricks, 0, _numElementsInBricksArray);
}
......@@ -82,14 +91,14 @@ namespace campvis {
}
tgt::svec3 BinaryBrickedVolume::indexToBrick(size_t brickIndex) const {
size_t z = brickIndex / (_numBricks.x * _numBricks.y);
size_t y = (brickIndex % (_numBricks.x * _numBricks.y)) / _numBricks.x;
size_t x = brickIndex % _numBricks.x;
size_t z = brickIndex / (_dimBricks.x * _dimBricks.y);
size_t y = (brickIndex % (_dimBricks.x * _dimBricks.y)) / _dimBricks.x;
size_t x = brickIndex % _dimBricks.x;
return tgt::svec3(x, y, z);
}
size_t BinaryBrickedVolume::brickToIndex(const tgt::svec3& brick) const {
return brick.x + (_numBricks.x * brick.y) + (_numBricks.x * _numBricks.y * brick.z);
return brick.x + (_dimBricks.x * brick.y) + (_dimBricks.x * _dimBricks.y * brick.z);
}
bool BinaryBrickedVolume::getValueForIndex(size_t brickIndex) const {
......@@ -111,22 +120,33 @@ namespace campvis {
_bricks[byte] &= ~(1 << bit);
}
ImageData* BinaryBrickedVolume::exportToImageData() const {
tgt::svec3 size = _numBricks;
size.z = DIV_CEIL(size.z, 8);
size_t numElementsInCopy = tgt::hmul(size);
uint8_t* copy = new uint8_t[numElementsInCopy];
memset(copy, 0, numElementsInCopy);
memcpy(copy, _bricks, _numElementsInBricksArray);
tgt::Texture* BinaryBrickedVolume::exportToImageData() const {
tgt::Texture* toReturn = new tgt::Texture(_bricks, _dimPackedBricks, GL_RED_INTEGER, GL_R8UI, GL_UNSIGNED_BYTE, tgt::Texture::NEAREST);
LGL_ERROR;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
tgt::TextureUnit tempUnit;
tempUnit.activate();
toReturn->bind();
toReturn->uploadTexture();
LGL_ERROR;
toReturn->setWrapping(tgt::Texture::CLAMP);
toReturn->setPixelData(0);
tgt::TextureUnit::setZeroUnit();
LGL_ERROR;
ImageData* toReturn = new ImageData(_referenceImage->getDimensionality(), size, 1);
GenericImageRepresentationLocal<uint8_t, 1>::create(toReturn, copy);
return toReturn;
// uint8_t* copy = new uint8_t[_numElementsInBricksArray];
// memcpy(copy, _bricks, _numElementsInBricksArray);
//
// ImageData* toReturn = new ImageData(_referenceImage->getDimensionality(), _dimPackedBricks, 1);
// GenericImageRepresentationLocal<uint8_t, 1>::create(toReturn, copy);
// return toReturn;
}
const tgt::svec3& BinaryBrickedVolume::getNumBricks() const {
return _numBricks;
return _dimBricks;
}
size_t BinaryBrickedVolume::getNumBrickIndices() const {
......
......@@ -7,6 +7,10 @@
#include <vector>
namespace tgt {
class Texture;
}
namespace campvis {
class BinaryBrickedVolume {
......@@ -18,12 +22,12 @@ namespace campvis {
/**
* Gets the number of bricks in each dimension.
* \return _numBricks
* \return _dimBricks
*/
const tgt::svec3& getNumBricks() const;
/**
* Gets the number of brick indices (= hmul(_numBricks)).
* Gets the number of brick indices (= hmul(_dimBricks)).
* \return _numBrickIndices
*/
size_t getNumBrickIndices() const;
......@@ -51,7 +55,7 @@ namespace campvis {
std::vector<tgt::svec3> getAllVoxelsForBrick(size_t brickIndex) const;
ImageData* exportToImageData() const;
tgt::Texture* exportToImageData() const;
private:
/**
......@@ -73,10 +77,11 @@ namespace campvis {
const ImageData* _referenceImage; ///< the reference image
size_t _brickSize; ///< number of voxels a brick is covering in each dimension
tgt::svec3 _numBricks; ///< number of bricks in each dimension
size_t _numBrickIndices; ///< number of brick indices (= hmul(_numBricks))
tgt::svec3 _dimBricks; ///< number of bricks in each dimension
size_t _numBrickIndices; ///< number of brick indices (= hmul(_dimPackedBricks))
uint8_t* _bricks; ///< the densly packed bricks
tgt::svec3 _dimPackedBricks; ///< number of elements when bricks are tightly packed
size_t _numElementsInBricksArray; ///< number of elements in _bricks
};
......
......@@ -219,6 +219,7 @@ int Texture::calcNumChannels(GLint format) {
case 1:
case GL_COLOR_INDEX:
case GL_RED:
case GL_RED_INTEGER:
case GL_GREEN:
case GL_BLUE:
case GL_ALPHA:
......
......@@ -61,6 +61,13 @@ uniform sampler1D _transferFunction;
uniform TFParameters1D _transferFunctionParams;
// BBV Lookup volume
uniform usampler3D _bbvTexture;
uniform TextureParameters3D _bbvTextureParams;
uniform int _bbvBrickSize;
uniform bool _hasBbv;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
......@@ -77,6 +84,25 @@ uniform float _shadowIntensity;
// TODO: copy+paste from Voreen - eliminate or improve.
const float SAMPLING_BASE_INTERVAL_RCP = 200.0;
ivec3 voxelToBrick(in vec3 voxel) {
return ivec3(floor(voxel / _bbvBrickSize));
}
int brickToIndex(in ivec3 brick) {
return int(brick.x + (_bbvTextureParams._size.x * brick.y) + (_bbvTextureParams._size.x * _bbvTextureParams._size.y * brick.z));
}
// samplePosition is in texture coordiantes [0, 1]
bool lookupInBbv(in vec3 samplePosition) {
ivec3 brick = voxelToBrick(samplePosition * _volumeTextureParams._size);
ivec3 byte = brick;
byte.x /= 8;
uint bit = uint(brick.x % 8);
uint texel = texelFetch(_bbvTexture, byte, 0).r;
return (texel & (1U << bit)) != 0U;
}
/**
* Performs the raycasting and returns the final fragment color.
......@@ -100,6 +126,19 @@ vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords)
// compute sample position
vec3 samplePosition = entryPoint.rgb + t * direction;
if (_hasBbv) {
if (lookupInBbv(samplePosition)) {
// advance to the next evaluation point along the ray
#ifdef ENABLE_ADAPTIVE_STEPSIZE
samplingRateCompensationMultiplier = 1.0;
t += _samplingStepSize;
#else
t += _samplingStepSize;
#endif
continue;
}
}
// lookup intensity and TF
float intensity = getElement3DNormalized(_volume, _volumeTextureParams, samplePosition).a;
vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity);
......
......@@ -44,12 +44,15 @@ namespace campvis {
, 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)
, _bbv(0)
, _t(0)
{
addDecorator(new ProcessorDecoratorShading());
addProperty(&p_targetImageID);
addProperty(&p_enableAdaptiveStepsize);
addProperty(&p_useEmptySpaceSkipping);
addProperty(&p_enableShadowing);
addProperty(&p_shadowIntensity);
......@@ -60,6 +63,7 @@ namespace campvis {
SimpleRaycaster::~SimpleRaycaster() {
delete _bbv;
delete _t;
}
void SimpleRaycaster::init() {
......@@ -71,20 +75,42 @@ namespace campvis {
}
void SimpleRaycaster::processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) {
DataHandle dh = DataHandle(const_cast<ImageData*>(image->getParent())); // HACK HACK HACK
generateBbv(dh);
if (_bbv != 0) {
data.addData("nanananana BATMAN!", _bbv->exportToImageData());
tgt::TextureUnit bbvUnit;
if (getInvalidationLevel() & INVALID_BBV) {
DataHandle dh = DataHandle(const_cast<ImageData*>(image->getParent())); // HACK HACK HACK
generateBbv(dh);
validate(INVALID_BBV);
}
if (_t != 0 && p_useEmptySpaceSkipping.getValue()) {
// bind
bbvUnit.activate();
_t->bind();
_shader->setIgnoreUniformLocationError(true);
_shader->setUniform("_bbvTexture", bbvUnit.getUnitNumber());
_shader->setUniform("_bbvTextureParams._size", tgt::vec3(_t->getDimensions()));
_shader->setUniform("_bbvTextureParams._sizeRCP", tgt::vec3(1.f) / tgt::vec3(_t->getDimensions()));
_shader->setUniform("_bbvTextureParams._numChannels", static_cast<int>(1));
_shader->setUniform("_bbvBrickSize", 2);
_shader->setUniform("_hasBbv", true);
_shader->setIgnoreUniformLocationError(false);
}
else {
_shader->setUniform("_hasBbv", false);
}
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());
......@@ -114,9 +140,11 @@ namespace campvis {
void SimpleRaycaster::generateBbv(DataHandle dh) {
delete _bbv;
_bbv = 0;
delete _t;
_t = 0;
if (dh.getData() == 0) {
_bbv = 0;
return;
}
else {
......@@ -128,7 +156,8 @@ namespace campvis {
size_t tfNumElements = p_transferFunction.getTF()->getTexture()->getDimensions().x;
// parallelly traverse the bricks
tbb::parallel_for(tbb::blocked_range<size_t>(0, _bbv->getNumBrickIndices()), [&] (const tbb::blocked_range<size_t>& range) {
// have minimum group size 8 to avoid race conditions (every 8 neighbor bricks write to the same byte)!
tbb::parallel_for(tbb::blocked_range<size_t>(0, _bbv->getNumBrickIndices(), 8), [&] (const tbb::blocked_range<size_t>& range) {
const tgt::vec2& tfIntensityDomain = p_transferFunction.getTF()->getIntensityDomain();
for (size_t i = range.begin(); i != range.end(); ++i) {
......@@ -155,6 +184,9 @@ namespace campvis {
}
}
});
// export to texture:
_t = _bbv->exportToImageData();
}
else {
LERROR("Could not convert to a local representation.");
......
......@@ -48,6 +48,10 @@ namespace campvis {
*/
class SimpleRaycaster : public RaycastingProcessor {
public:
enum AdditionalInvalidationLevels {
INVALID_BBV = AbstractProcessor::FIRST_FREE_TO_USE_INVALIDATION_LEVEL
};
/**
* Constructs a new SimpleRaycaster Processor
**/
......@@ -77,6 +81,7 @@ namespace campvis {
FloatProperty p_shadowIntensity;
BoolProperty p_enableAdaptiveStepsize;
BoolProperty p_useEmptySpaceSkipping;
protected:
/// \see HasProperyCollection::updateProperties()
......@@ -92,6 +97,7 @@ namespace campvis {
void generateBbv(DataHandle dh);
BinaryBrickedVolume* _bbv;
tgt::Texture* _t;
static const std::string loggerCat_;
};
......
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