Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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