The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated 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 6747c124 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Removed obsolete OptimizedRaycaster processor.

parent 6667deec
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, 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 "volumebricking.h"
#include "cgt/assert.h"
#include "cgt/glmath.h"
#include "cgt/texture.h"
#include "cgt/textureunit.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
#define DIV_CEIL(x,y) ((x) > 0) ? (1 + ((x) - 1)/(y)) : ((x) / (y))
namespace campvis {
BinaryBrickedVolume::BinaryBrickedVolume(const ImageData* referenceImage, size_t brickSize)
: _referenceImage(referenceImage)
, _brickSize(brickSize)
, _bricks(0)
{
cgtAssert(_referenceImage != 0, "Reference Image must not be 0!");
// perform ceiling integer division:
_dimBricks = referenceImage->getSize();
for (int i = 0; i < 3; ++i)
_dimBricks.elem[i] = DIV_CEIL(_dimBricks.elem[i], _brickSize);
// 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 = cgt::hmul(_dimBricks);
_dimPackedBricks = _dimBricks;
_dimPackedBricks.x = _dimPackedBricks.x / 8;
_numElementsInBricksArray = cgt::hmul(_dimPackedBricks);
_bricks = new uint8_t[_numElementsInBricksArray];
memset(_bricks, 0, _numElementsInBricksArray);
}
BinaryBrickedVolume::~BinaryBrickedVolume() {
delete _bricks;
}
std::vector<cgt::svec3> BinaryBrickedVolume::getAllVoxelsForBrick(size_t brickIndex) const {
cgt::ivec3 refImageSize = _referenceImage->getSize();
std::vector<cgt::svec3> toReturn;
toReturn.reserve((_brickSize+2) * (_brickSize+2) * (_brickSize+2));
// traverse each dimension, check that voxel is within reference image size
cgt::ivec3 startVoxel = indexToBrick(brickIndex) * _brickSize;
for (int x = -1; x < static_cast<int>(_brickSize + 1); ++x) {
int xx = startVoxel.x + x;
if (xx < 0)
continue;
else if (xx >= refImageSize.x)
break;
for (int y = -1; y < static_cast<int>(_brickSize + 1); ++y) {
int yy = startVoxel.y + y;
if (yy < 0)
continue;
else if (yy >= refImageSize.y)
break;
for (int z = -1; z < static_cast<int>(_brickSize + 1); ++z) {
int zz = startVoxel.z + z;
if (zz < 0)
continue;
else if (zz >= refImageSize.z)
break;
toReturn.push_back(cgt::svec3(xx, yy, zz));
}
}
}
return toReturn;
}
cgt::svec3 BinaryBrickedVolume::indexToBrick(size_t brickIndex) const {
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 cgt::svec3(x, y, z);
}
size_t BinaryBrickedVolume::brickToIndex(const cgt::svec3& brick) const {
return brick.x + (_dimBricks.x * brick.y) + (_dimBricks.x * _dimBricks.y * brick.z);
}
bool BinaryBrickedVolume::getValueForIndex(size_t brickIndex) const {
size_t byte = brickIndex / 8;
size_t bit = brickIndex % 8;
cgtAssert(brickIndex < _numElementsInBricksArray, "Brick brickIndex out of bounds!");
return (_bricks[byte] & (1 << bit)) != 0;
}
void BinaryBrickedVolume::setValueForIndex(size_t brickIndex, bool value) {
size_t byte = brickIndex / 8;
size_t bit = brickIndex % 8;
cgtAssert(byte < _numElementsInBricksArray, "Brick brickIndex out of bounds!");
if (value)
_bricks[byte] |= (1 << bit);
else
_bricks[byte] &= ~(1 << bit);
}
cgt::Texture* BinaryBrickedVolume::exportToImageData() const {
cgt::TextureUnit tempUnit;
tempUnit.activate();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
cgt::Texture* toReturn = new cgt::Texture(GL_TEXTURE_3D, _dimPackedBricks, GL_R8UI, _bricks, GL_RED_INTEGER, GL_UNSIGNED_BYTE, cgt::Texture::NEAREST);
toReturn->setWrapping(cgt::Texture::CLAMP);
cgt::TextureUnit::setZeroUnit();
LGL_ERROR;
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 cgt::svec3& BinaryBrickedVolume::getNumBricks() const {
return _dimBricks;
}
size_t BinaryBrickedVolume::getNumBrickIndices() const {
return _numBrickIndices;
}
size_t BinaryBrickedVolume::getBrickSize() const {
return _brickSize;
}
}
\ No newline at end of file
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, 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 VOLUMEBRICKING_H__
#define VOLUMEBRICKING_H__
#include "cgt/vector.h"
#include "core/coreapi.h"
#include "core/datastructures/imagedata.h"
#include <vector>
namespace cgt {
class Texture;
}
namespace campvis {
class CAMPVIS_CORE_API BinaryBrickedVolume {
public:
BinaryBrickedVolume(const ImageData* referenceImage, size_t brickSize);
~BinaryBrickedVolume();
/**
* Gets the number of bricks in each dimension.
* \return _dimBricks
*/
const cgt::svec3& getNumBricks() const;
/**
* Gets the number of brick indices (= hmul(_dimBricks)).
* \return _numBrickIndices
*/
size_t getNumBrickIndices() const;
/**
* Gets the number of voxels a brick is covering in each dimension.
* \return _brickSize
*/
size_t getBrickSize() const;
/**
* Returns the boolean value for the brick with index \a brickIndex.
* \param brickIndex Lookup brick index
* \return The boolean value for the brick with index \a brickIndex.
*/
bool getValueForIndex(size_t brickIndex) const;
/**
* Sets the boolean value for the brick with index \a brickIndex to \a value.
* \param brickIndex Lookup brick index
* \param value The new boolean value for this brick.
*/
void setValueForIndex(size_t brickIndex, bool value);
/**
* Return a vector of all voxels positions in the reference image that are in the brick with the index \a brickIndex.
* \param brickIndex Lookup brick index.
* \return A vector of all voxels positions in the reference image that are in the brick with the index \a brickIndex.
*/
std::vector<cgt::svec3> getAllVoxelsForBrick(size_t brickIndex) const;
cgt::Texture* exportToImageData() const;
private:
/**
* Returns the brick coordinates for the brick with index \a brickIndex.
* \param brickIndex The Brick index to look up
* \return The corresponding 3D brick coordinates.
*/
cgt::svec3 indexToBrick(size_t brickIndex) const;
/**
* Transforms brick coordinates to the corresponding index.
* \param brick Brick coordinates.
* \return The corresponding index in if all bricks are in contiguous storage.
*/
size_t brickToIndex(const cgt::svec3& brick) const;
const ImageData* _referenceImage; ///< the reference image
size_t _brickSize; ///< number of voxels a brick is covering in each dimension
cgt::svec3 _dimBricks; ///< number of bricks in each dimension
size_t _numBrickIndices; ///< number of brick indices (= hmul(_dimPackedBricks))
uint8_t* _bricks; ///< the densly packed bricks
cgt::svec3 _dimPackedBricks; ///< number of elements when bricks are tightly packed
size_t _numElementsInBricksArray; ///< number of elements in _bricks
};
}
#endif // VOLUMEBRICKING_H__
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, 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 "optimizedraycaster.h"
#include "core/tools/quadrenderer.h"
#include "core/datastructures/lightsourcedata.h"
#include "core/datastructures/imagerepresentationlocal.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorgradient.h"
#include <tbb/tbb.h>
namespace campvis {
const std::string OptimizedRaycaster::loggerCat_ = "CAMPVis.modules.vis.OptimizedRaycaster";
OptimizedRaycaster::OptimizedRaycaster(IVec2Property* viewportSizeProp)
: RaycastingProcessor(viewportSizeProp, "modules/vis/glsl/optimizedraycaster.frag", true)
, p_enableShading("EnableShading", "Enable Shading", true)
, p_lightId("LightId", "Input Light Source", "lightsource", DataNameProperty::READ)
, p_enableShadowing("EnableShadowing", "Enable Hard Shadows (Expensive!)", false)
, p_shadowIntensity("ShadowIntensity", "Shadow Intensity", .5f, .0f, 1.f)
, p_enableIntersectionRefinement("EnableIntersectionRefinement", "Enable Intersection Refinement", false)
, p_useEmptySpaceSkipping("EnableEmptySpaceSkipping", "Enable Empty Space Skipping", true)
, _bbv(0)
, _vvTex(0)
{
addDecorator(new ProcessorDecoratorGradient());
addProperty(p_enableShading, INVALID_RESULT | INVALID_PROPERTIES | INVALID_SHADER);
addProperty(p_lightId);
addProperty(p_enableIntersectionRefinement, INVALID_RESULT | INVALID_SHADER);
addProperty(p_useEmptySpaceSkipping, INVALID_RESULT | INVALID_BBV);
addProperty(p_enableShadowing, INVALID_RESULT | INVALID_SHADER | INVALID_PROPERTIES);
addProperty(p_shadowIntensity);
p_shadowIntensity.setVisible(false);
// p_transferFunction.setInvalidationLevel(p_transferFunction.getInvalidationLevel() | INVALID_BBV);
// p_sourceImageID.setInvalidationLevel(p_sourceImageID.getInvalidationLevel() | INVALID_BBV);
decoratePropertyCollection(this);
}
OptimizedRaycaster::~OptimizedRaycaster() {
}
void OptimizedRaycaster::init() {
RaycastingProcessor::init();
invalidate(INVALID_BBV);
}
void OptimizedRaycaster::deinit() {
delete _bbv;
delete _vvTex;
RaycastingProcessor::deinit();
}
void OptimizedRaycaster::processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) {
cgt::TextureUnit bbvUnit;
if (getInvalidationLevel() & INVALID_BBV){
DataHandle dh = DataHandle(const_cast<ImageData*>(image->getParent())); // HACK HACK HACK
generateBbv(dh);
validate(INVALID_BBV);
}
if (_vvTex != 0 && p_useEmptySpaceSkipping.getValue()){
// bind
bbvUnit.activate();
_vvTex->bind();
_shader->setIgnoreUniformLocationError(true);
_shader->setUniform("_bbvTexture", bbvUnit.getUnitNumber());
_shader->setUniform("_bbvTextureParams._size", cgt::vec3(_vvTex->getDimensions()));
_shader->setUniform("_bbvTextureParams._sizeRCP", cgt::vec3(1.f) / cgt::vec3(_vvTex->getDimensions()));
_shader->setUniform("_bbvTextureParams._numChannels", static_cast<int>(1));
_shader->setUniform("_bbvBrickSize", static_cast<int>(_bbv->getBrickSize()));
_shader->setUniform("_hasBbv", true);
_shader->setIgnoreUniformLocationError(false);
}
else{
_shader->setUniform("_hasBbv", false);
}
ScopedTypedData<LightSourceData> light(data, p_lightId.getValue());
if (p_enableShading.getValue() == false || light != nullptr) {
FramebufferActivationGuard fag(this);
createAndAttachTexture(GL_RGBA8);
createAndAttachTexture(GL_RGBA32F);
createAndAttachTexture(GL_RGBA32F);
createAndAttachDepthTexture();
static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, buffers);
if (p_enableShading.getValue() && light != nullptr) {
light->bind(_shader, "_lightSource");
}
if (p_enableShadowing.getValue())
_shader->setUniform("_shadowIntensity", p_shadowIntensity.getValue());
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad();
glDrawBuffers(1, buffers);
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
data.addData(p_targetImageID.getValue(), new RenderData(_fbo));
}
else {
LDEBUG("Could not load light source from DataContainer.");
}
}
std::string OptimizedRaycaster::generateHeader() const {
std::string toReturn = RaycastingProcessor::generateHeader();
if (p_enableShading.getValue())
toReturn += "#define ENABLE_SHADING\n";
if (p_enableShadowing.getValue())
toReturn += "#define ENABLE_SHADOWING\n";
if (p_enableIntersectionRefinement.getValue())
toReturn += "#define INTERSECTION_REFINEMENT\n";
return toReturn;
}
void OptimizedRaycaster::updateProperties(DataContainer& dataContainer) {
RaycastingProcessor::updateProperties(dataContainer);
p_lightId.setVisible(p_enableShading.getValue());
p_shadowIntensity.setVisible(p_enableShadowing.getValue());
}
void OptimizedRaycaster::generateBbv(DataHandle dh) {
delete _bbv;
_bbv = 0;
delete _vvTex;
_vvTex = 0;
if (dh.getData() == 0){
return;
}
else{
if (const ImageData* id = dynamic_cast<const ImageData*>(dh.getData())){
if (const ImageRepresentationLocal* rep = id->getRepresentation<ImageRepresentationLocal>(true)){
_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;
LDEBUG("Start computing brick visibilities...");
// parallelly traverse the bricks
// 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 cgt::vec2& tfIntensityDomain = p_transferFunction.getTF()->getIntensityDomain();
for (size_t i = range.begin(); i != range.end(); ++i){
// for each brick, get all corresponding voxels in the reference volume
std::vector<cgt::svec3> voxels = _bbv->getAllVoxelsForBrick(i);
// traverse the voxels to check whether their intensities are mapped to some opacity
for (size_t v = 0; v < voxels.size(); ++v){
// apply same TF lookup as in shader...
float intensity = rep->getElementNormalized(voxels[v], 0);
if (intensity >= tfIntensityDomain.x || intensity <= tfIntensityDomain.y){
float mappedIntensity = (intensity - tfIntensityDomain.x) / (tfIntensityDomain.y - tfIntensityDomain.x);
// ...but with nearest neighbour interpolation
size_t scaled = static_cast<size_t>(mappedIntensity * static_cast<float>(tfNumElements - 1));
GLubyte opacity = tfBuffer[(4 * (scaled)) + 3];
if (opacity != 0){
_bbv->setValueForIndex(i, true);
break;
}
}
}
}
});
LDEBUG("...finished computing brick visibilities.");
// export to texture:
_vvTex = _bbv->exportToImageData();
}
else {
LERROR("Could not convert to a local representation.");
}
}
else {
cgtAssert(false, "The data type in the given DataHandle is WRONG!");
}
}
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, 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 OPTIMIZEDRAYCASTER_H__
#define OPTIMIZEDRAYCASTER_H__
#include "core/pipeline/raycastingprocessor.h"
#include "core/properties/floatingpointproperty.h"
#include "core/properties/genericproperty.h"
#include "core/properties/transferfunctionproperty.h"
#include "core/tools/volumebricking.h"
#include "modules/modulesapi.h"
#include "modules/processorfactory.h"
#include <string>
namespace cgt {
class Shader;
}
namespace campvis {
/**
* Performs a simple volume ray casting.
*/
class CAMPVIS_MODULES_API OptimizedRaycaster : public RaycastingProcessor {
public:
enum AdditionalInvalidationLevels {
INVALID_BBV = AbstractProcessor::FIRST_FREE_TO_USE_INVALIDATION_LEVEL
};
/**
* Constructs a new OptimizedRaycaster Processor
**/
OptimizedRaycaster(IVec2Property* viewportSizeProp);
/**
* Destructor
**/
virtual ~OptimizedRaycaster();
/**
* To be used in ProcessorFactory static methods
*/
static const std::string getId() { return "OptimizedRaycaster"; };
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return getId(); };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Performs a simple volume ray casting."; };
/// \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::EXPERIMENTAL; };
/// \see AbstractProcessor::init
virtual void init();
/// \see AbstractProcessor::deinit
virtual void deinit();
BoolProperty p_enableShading; ///< Flag whether to enable shading
DataNameProperty p_lightId; ///< Name/ID for the LightSource to use
BoolProperty p_enableShadowing;
FloatProperty p_shadowIntensity;
BoolProperty p_enableIntersectionRefinement;
BoolProperty p_useEmptySpaceSkipping;
protected:
/// \see AbstractProcessor::updateProperties()
virtual void updateProperties(DataContainer& dataContainer);
/// \see RaycastingProcessor::processImpl()
virtual void processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image);
/// \see RaycastingProcessor::generateHeader()
virtual std::string generateHeader() const;