Commit 93cdefc6 authored by schultezub's avatar schultezub

more work on Columbia module, introducing StrainRaycaster

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@522 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent ae1a997d
......@@ -34,7 +34,6 @@
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
......@@ -132,13 +131,13 @@ namespace campvis {
if (! _bindEntryExitDepthTextures) {
entryPoints->bindColorTexture(_shader, entryUnit, "_entryPoints", "_entryParams");
exitPoints->bindColorTexture(_shader, exitUnit, "_exitPoints", "_exitParams");
processImpl(data);
processImpl(data, img);
}
else {
tgt::TextureUnit entryUnitDepth, exitUnitDepth;
entryPoints->bind(_shader, entryUnit, entryUnitDepth, "_entryPoints", "_entryPointsDepth", "_entryParams");
exitPoints->bind(_shader, exitUnit, exitUnitDepth, "_exitPoints", "_exitPointsDepth", "_exitParams");
processImpl(data);
processImpl(data, img);
}
decorateRenderEpilog(_shader);
......
......@@ -40,6 +40,8 @@
#include "core/properties/numericproperty.h"
#include "core/properties/transferfunctionproperty.h"
#include "core/datastructures/imagerepresentationgl.h"
namespace tgt {
class Shader;
}
......@@ -116,8 +118,9 @@ namespace campvis {
*
* \sa RaycastingProcessor::process()
* \param data DataContainer to work on.
* \param image The image to render
*/
virtual void processImpl(DataContainer& data) = 0;
virtual void processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) = 0;
/**
* Returns an additional header that will be linked into the fragment shader.
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitt Mnchen
// Boltzmannstr. 3, 85748 Garching b. Mnchen, Germany
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
//
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// ================================================================================================
layout(location = 0) out vec4 out_Color; ///< outgoing fragment color
#include "tools/gradient.frag"
#include "tools/raycasting.frag"
#include "tools/shading.frag"
#include "tools/texture2d.frag"
#include "tools/texture3d.frag"
#include "tools/transferfunction.frag"
uniform vec2 _viewportSizeRCP;
uniform bool _jitterEntryPoints;
uniform float _jitterStepSizeMultiplier;
// ray entry points
uniform sampler2D _entryPoints;
uniform sampler2D _entryPointsDepth;
uniform TextureParameters2D _entryParams;
// ray exit points
uniform sampler2D _exitPoints;
uniform sampler2D _exitPointsDepth;
uniform TextureParameters2D _exitParams;
// DRR volume
uniform sampler3D _volume;
uniform TextureParameters3D _volumeTextureParams;
// Transfer function
uniform sampler1D _transferFunction;
uniform TFParameters1D _transferFunctionParams;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
uniform float _samplingStepSize;
#ifdef ENABLE_ADAPTIVE_STEPSIZE
bool _inVoid = false;
#endif
// TODO: copy+paste from Voreen - eliminate or improve.
const float SAMPLING_BASE_INTERVAL_RCP = 200.0;
/**
* Performs the raycasting and returns the final fragment color.
*/
vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) {
vec4 result = vec4(0.0);
float firstHitT = -1.0;
// calculate ray parameters
vec3 direction = exitPoint.rgb - entryPoint.rgb;
float t = 0.0;
float tend = length(direction);
direction = normalize(direction);
if (_jitterEntryPoints)
jitterEntryPoint(entryPoint, direction, _samplingStepSize * _jitterStepSizeMultiplier);
while (t < tend) {
// compute sample position
vec3 samplePosition = entryPoint.rgb + t * direction;
// lookup intensity and TF
vec4 strain = getElement3DNormalized(_volume, _volumeTextureParams, samplePosition);
vec4 color = (_volumeTextureParams._numChannels == 4) ? strain : vec4(strain.xyz, 0.2);
#ifdef ENABLE_ADAPTIVE_STEPSIZE
if (color.a <= 0.0) {
// we're within void, make the steps bigger
_inVoid = true;
}
else {
if (_inVoid) {
float formerT = t - _samplingStepSize;
// we just left the void, perform intersection refinement
for (float stepPower = 0.5; stepPower > 0.1; stepPower /= 2.0) {
// compute refined sample position
float newT = formerT + _samplingStepSize * stepPower;
vec3 newSamplePosition = entryPoint.rgb + newT * direction;
// lookup refined intensity + TF
vec4 newStrain = getElement3DNormalized(_volume, _volumeTextureParams, newSamplePosition);
vec4 newColor = (_volumeTextureParams._numChannels == 4) ? newStrain : vec4(newStrain.xyz, 0.2);
if (newColor.a <= 0.0) {
// we're back in the void - look on the right-hand side
formerT = newT;
}
else {
// we're still in the matter - look on the left-hand side
samplePosition = newSamplePosition;
color = newColor;
t -= _samplingStepSize * stepPower;
}
}
_inVoid = false;
}
}
#endif
// perform compositing
if (color.a > 0.0) {
#ifdef ENABLE_SHADING
// compute gradient (needed for shading and normals)
vec3 gradient = computeGradient(_volume, _volumeTextureParams, samplePosition);
color.rgb = calculatePhongShading(textureToWorld(_volumeTextureParams, samplePosition).xyz, _lightSource, _cameraPosition, gradient, color.rgb, color.rgb, vec3(1.0, 1.0, 1.0));
#endif
// accomodate for variable sampling rates
color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
result.rgb = mix(color.rgb, result.rgb, result.a);
result.a = result.a + (1.0 -result.a) * color.a;
}
// save first hit ray parameter for depth value calculation
if (firstHitT < 0.0 && result.a > 0.0) {
firstHitT = t;
}
// early ray termination
if (result.a > 0.975) {
result.a = 1.0;
t = tend;
}
#ifdef ENABLE_ADAPTIVE_STEPSIZE
t += _samplingStepSize * (_inVoid ? 1.0 : 0.125);
#else
t += _samplingStepSize;
#endif
}
// calculate depth value from ray parameter
gl_FragDepth = 1.0;
if (firstHitT >= 0.0) {
float depthEntry = getElement2DNormalized(_entryPointsDepth, _entryParams, texCoords).z;
float depthExit = getElement2DNormalized(_exitPointsDepth, _exitParams, texCoords).z;
gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
}
return result;
}
/***
* The main method.
***/
void main() {
vec2 p = gl_FragCoord.xy * _viewportSizeRCP;
vec3 frontPos = getElement2DNormalized(_entryPoints, _entryParams, p).rgb;
vec3 backPos = getElement2DNormalized(_exitPoints, _exitParams, p).rgb;
//determine whether the ray has to be casted
if (frontPos == backPos) {
//background need no raycasting
discard;
} else {
//fragCoords are lying inside the boundingbox
out_Color = performRaycasting(frontPos, backPos, p);
}
}
......@@ -45,6 +45,7 @@ namespace campvis {
, _imageReader()
, _vr(_effectiveRenderTargetSize)
, _sr(_effectiveRenderTargetSize)
, _src(_effectiveRenderTargetSize)
, _trackballEH(0)
{
addProperty(&_camera);
......@@ -55,6 +56,7 @@ namespace campvis {
addProcessor(&_imageReader);
addProcessor(&_splitter);
addProcessor(&_vr);
addProcessor(&_src);
addProcessor(&_sr);
}
......@@ -68,8 +70,10 @@ namespace campvis {
_splitter.s_validated.connect(this, &Columbia1::onProcessorValidated);
_camera.addSharedProperty(&_vr.p_camera);
_camera.addSharedProperty(&_src.p_camera);
_vr.p_outputImage.setValue("vr");
_sr.p_targetImageID.setValue("sr");
_src.p_targetImageID.setValue("src");
_renderTargetID.setValue("vr");
_imageReader.p_url.setValue("D:/Medical Data/Columbia/inputs/FullVolumeLV_3D_25Hz_[IM_0004]_NIF_diffused_crop_00.ltf");
......@@ -78,6 +82,7 @@ namespace campvis {
_imageReader.p_targetImageID.connect(&_splitter.p_inputID);
_splitter.p_outputID.connect(&_vr.p_inputVolume);
_splitter.p_outputID.connect(&_src.p_sourceImageID);
_splitter.p_outputID.connect(&_sr.p_sourceImageID);
Geometry1DTransferFunction* dvrTF = new Geometry1DTransferFunction(128, tgt::vec2(0.f, 1.f));
......@@ -110,11 +115,13 @@ namespace campvis {
DataContainer::ScopedTypedData<ImageData> img(_data, _splitter.p_outputID.getValue());
if (img != 0) {
tgt::Bounds volumeExtent = img->getWorldBounds();
tgt::vec3 pos = volumeExtent.center() - tgt::vec3(0, 0, tgt::length(volumeExtent.diagonal()));
if (_trackballEH->getSceneBounds() != volumeExtent) {
tgt::vec3 pos = volumeExtent.center() - tgt::vec3(0, 0, tgt::length(volumeExtent.diagonal()));
_trackballEH->setSceneBounds(volumeExtent);
_trackballEH->setCenter(volumeExtent.center());
_trackballEH->reinitializeCamera(pos, volumeExtent.center(), _camera.getValue().getUpVector());
_trackballEH->setSceneBounds(volumeExtent);
_trackballEH->setCenter(volumeExtent.center());
_trackballEH->reinitializeCamera(pos, volumeExtent.center(), _camera.getValue().getUpVector());
}
}
}
}
......
......@@ -37,6 +37,7 @@
#include "modules/io/processors/ltfimagereader.h"
#include "modules/columbia/processors/imageseriessplitter.h"
#include "modules/columbia/processors/strainraycaster.h"
#include "modules/vis/processors/sliceextractor.h"
#include "modules/vis/processors/volumerenderer.h"
......@@ -78,6 +79,7 @@ namespace campvis {
LtfImageReader _imageReader;
ImageSeriesSplitter _splitter;
VolumeRenderer _vr;
StrainRaycaster _src;
SliceExtractor _sr;
TrackballNavigationEventHandler* _trackballEH;
......
......@@ -54,6 +54,7 @@ namespace campvis {
if (series != 0) {
if (hasInvalidProperties()) {
p_imageIndex.setMaxValue(series->getNumImages());
validate(INVALID_PROPERTIES);
}
if (p_imageIndex.getValue() < static_cast<int>(series->getNumImages())) {
data.addDataHandle(p_outputID.getValue(), series->getImage(p_imageIndex.getValue()));
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitt Mnchen
// Boltzmannstr. 3, 85748 Garching b. Mnchen, Germany
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
//
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// ================================================================================================
#include "strainraycaster.h"
#include "core/tools/quadrenderer.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/pipeline/processordecoratorshading.h"
namespace campvis {
const std::string StrainRaycaster::loggerCat_ = "CAMPVis.modules.vis.StrainRaycaster";
StrainRaycaster::StrainRaycaster(IVec2Property& canvasSize)
: RaycastingProcessor(canvasSize, "modules/columbia/glsl/strainraycaster.frag", true)
, p_targetImageID("targetImageID", "Output Image", "", DataNameProperty::WRITE)
, p_enableShadowing("EnableShadowing", "Enable Hard Shadows", false, AbstractProcessor::INVALID_SHADER)
, p_shadowIntensity("ShadowIntensity", "Shadow Intensity", .5f, .0f, 1.f)
, p_enableAdaptiveStepsize("EnableAdaptiveStepSize", "Enable Adaptive Step Size", true, AbstractProcessor::INVALID_SHADER)
{
addDecorator(new ProcessorDecoratorShading());
addProperty(&p_targetImageID);
addProperty(&p_enableShadowing);
addProperty(&p_shadowIntensity);
addProperty(&p_enableAdaptiveStepsize);
decoratePropertyCollection(this);
}
StrainRaycaster::~StrainRaycaster() {
}
void StrainRaycaster::processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) {
if (image.getImageData()->getNumChannels() == 3 || image.getImageData()->getNumChannels() == 4) {
std::pair<ImageData*, ImageRepresentationRenderTarget*> output = ImageRepresentationRenderTarget::createWithImageData(_renderTargetSize.getValue());
output.second->activate();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad();
LGL_ERROR;
output.second->deactivate();
data.addData(p_targetImageID.getValue(), output.first);
p_targetImageID.issueWrite();
}
else {
LERROR("Wrong Number of Channels in Input Volume.");
}
}
std::string StrainRaycaster::generateHeader() const {
std::string toReturn = RaycastingProcessor::generateHeader();
if (p_enableShadowing.getValue())
toReturn += "#define ENABLE_SHADOWING\n";
if (p_enableAdaptiveStepsize.getValue())
toReturn += "#define ENABLE_ADAPTIVE_STEPSIZE\n";
return toReturn;
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
//
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// ================================================================================================
#ifndef STRAINRAYCASTER_H__
#define STRAINRAYCASTER_H__
#include "core/pipeline/raycastingprocessor.h"
#include "core/properties/genericproperty.h"
#include "core/properties/numericproperty.h"
#include "core/properties/transferfunctionproperty.h"
#include <string>
namespace tgt {
class Shader;
}
namespace campvis {
/**
* Performs strain volume ray casting.
*/
class StrainRaycaster : public RaycastingProcessor {
public:
/**
* Constructs a new StrainRaycaster Processor
**/
StrainRaycaster(IVec2Property& canvasSize);
/**
* Destructor
**/
virtual ~StrainRaycaster();
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return "StrainRaycaster"; };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Performs a simple volume ray casting."; };
DataNameProperty p_targetImageID; ///< image ID for output image
BoolProperty p_enableShadowing;
FloatProperty p_shadowIntensity;
BoolProperty p_enableAdaptiveStepsize;
protected:
/// \see RaycastingProcessor::processImpl()
virtual void processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image);
/// \see RaycastingProcessor::generateHeader()
virtual std::string generateHeader() const;
static const std::string loggerCat_;
};
}
#endif // STRAINRAYCASTER_H__
......@@ -52,7 +52,7 @@ namespace campvis {
}
void DRRRaycaster::processImpl(DataContainer& data) {
void DRRRaycaster::processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) {
_shader->setUniform("_shift", p_shift.getValue());
_shader->setUniform("_scale", p_scale.getValue());
......
......@@ -72,7 +72,7 @@ namespace campvis {
protected:
/// \see RaycastingProcessor::processImpl()
virtual void processImpl(DataContainer& data);
virtual void processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image);
/**
* \see RaycastingProcessor::generateHeader()
......
......@@ -56,7 +56,7 @@ namespace campvis {
}
void SimpleRaycaster::processImpl(DataContainer& data) {
void SimpleRaycaster::processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) {
std::pair<ImageData*, ImageRepresentationRenderTarget*> output = ImageRepresentationRenderTarget::createWithImageData(_renderTargetSize.getValue());
output.second->createAndAttachTexture(GL_RGBA32F);
output.second->createAndAttachTexture(GL_RGBA32F);
......
......@@ -72,7 +72,7 @@ namespace campvis {
protected:
/// \see RaycastingProcessor::processImpl()
virtual void processImpl(DataContainer& data);
virtual void processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image);
/// \see RaycastingProcessor::generateHeader()
virtual std::string generateHeader() const;
......
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