Introducing TensorGlyphRenderer, yet work to be done...

parent b863e31c
......@@ -54,7 +54,7 @@ uniform mat4 _projectionMatrix = mat4(
void main() {
gl_Position = _projectionMatrix * (_viewMatrix * (_modelMatrix * vec4(in_Position, 1.0)));
ex_Position = gl_Position;
ex_Position = vec4(in_Position, 1.0);
ex_TexCoord = in_TexCoord;
ex_Color = in_Color;
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, 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".
//
// 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 "tools/shading.frag"
in vec3 ex_TexCoord; ///< incoming texture coordinate
in vec4 ex_Position; ///< incoming texture coordinate
out vec4 out_Color; ///< outgoing fragment color
uniform vec4 _color;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
void main() {
out_Color = _color;
#ifdef ENABLE_SHADING
// compute gradient (needed for shading and normals)
vec3 gradient = ex_TexCoord;
out_Color.rgb = calculatePhongShading(ex_Position.xyz / ex_Position.w, _lightSource, _cameraPosition, gradient, _color.rgb, _color.rgb, vec3(1.0, 1.0, 1.0));
#endif
}
......@@ -35,11 +35,21 @@ namespace campvis {
: AutoEvaluationPipeline(dc)
, _imageReader()
, _ta()
, _glyphRenderer(&_canvasSize)
, _sliceExtractor(&_canvasSize)
, _wheelHandler(&_sliceExtractor.p_zSliceNumber)
, p_camera("Camera", "Camera", tgt::Camera())
, _trackballEH(0)
{
addProperty(&p_camera);
_trackballEH = new TrackballNavigationEventListener(&p_camera, &_canvasSize);
addEventListenerToBack(_trackballEH);
addProcessor(&_imageReader);
addProcessor(&_ta);
addProcessor(&_glyphRenderer);
addProcessor(&_sliceExtractor);
addEventListenerToBack(&_wheelHandler);
}
......@@ -50,21 +60,37 @@ namespace campvis {
void TensorDemo::init() {
AutoEvaluationPipeline::init();
p_camera.addSharedProperty(&_glyphRenderer.p_camera);
_imageReader.p_url.setValue(CAMPVIS_SOURCE_DIR "/modules/tensor/sampledata/planar_tensor.mhd");
_imageReader.p_targetImageID.setValue("reader.output");
_imageReader.p_targetImageID.addSharedProperty(&_ta.p_inputImage);
_ta.p_outputProperties[0]->_imageId.addSharedProperty(&_sliceExtractor.p_sourceImageID);
_ta.p_outputProperties[0]->_imageType.selectById("MainEigenvector");
_ta.p_evalsImage.addSharedProperty(&_glyphRenderer.p_inputEigenvalues);
_ta.p_evecsImage.addSharedProperty(&_glyphRenderer.p_inputEigenvectors);
_ta.s_validated.connect(this, &TensorDemo::onProcessorValidated);
_sliceExtractor.p_xSliceNumber.setValue(0);
_glyphRenderer.p_renderOutput.setValue("glyphs");
Geometry1DTransferFunction* tf = new Geometry1DTransferFunction(128, tgt::vec2(0.f, 1.f));
tf->addGeometry(TFGeometry1D::createQuad(tgt::vec2(0.f, 1.f), tgt::col4(0, 0, 0, 0), tgt::col4(255, 255, 255, 255)));
_sliceExtractor.p_transferFunction.replaceTF(tf);
_sliceExtractor.p_targetImageID.setValue("slice");
_renderTargetID.setValue("glyphs");
//_renderTargetID.addSharedProperty(&(_sliceExtractor.p_targetImageID));
}
_renderTargetID.setValue("renderTarget");
_renderTargetID.addSharedProperty(&(_sliceExtractor.p_targetImageID));
void TensorDemo::onProcessorValidated(AbstractProcessor* processor) {
if (processor == &_ta) {
// update camera
ScopedTypedData<IHasWorldBounds> img(*_data, _ta.p_evalsImage.getValue());
if (img) {
_trackballEH->reinitializeCamera(img);
}
}
}
}
......@@ -25,11 +25,14 @@
#ifndef TENSORDEMO_H__
#define TENSORDEMO_H__
#include "core/eventhandlers/mwheeltonumericpropertyeventlistener.h"
#include "core/pipeline/autoevaluationpipeline.h"
#include "core/eventhandlers/mwheeltonumericpropertyeventlistener.h"
#include "core/eventhandlers/trackballnavigationeventlistener.h"
#include "modules/io/processors/mhdimagereader.h"
#include "modules/tensor/processors/tensoranalyzer.h"
#include "modules/tensor/processors/tensorglyphrenderer.h"
#include "modules/vis/processors/sliceextractor.h"
namespace campvis {
......@@ -54,10 +57,21 @@ namespace campvis {
static const std::string getId() { return "TensorDemo"; };
protected:
/**
* Slot getting called when one of the observed processors got validated.
* Updates the camera properties, when the input image has changed.
* \param processor The processor that emitted the signal
*/
virtual void onProcessorValidated(AbstractProcessor* processor);
MhdImageReader _imageReader;
TensorAnalyzer _ta;
TensorGlyphRenderer _glyphRenderer;
SliceExtractor _sliceExtractor;
CameraProperty p_camera;
TrackballNavigationEventListener* _trackballEH;
MWheelToNumericPropertyEventListener _wheelHandler;
};
......
......@@ -82,8 +82,8 @@ namespace campvis {
virtual void deinit();
DataNameProperty p_inputImage; ///< ID for input volume
DataNameProperty p_evalsImage; ///< ID for output gradient volume
DataNameProperty p_evecsImage; ///< ID for output gradient volume
DataNameProperty p_evalsImage; ///< ID for output eigenvalue volume
DataNameProperty p_evecsImage; ///< ID for output eigenvector volume
GenericOptionProperty<DegeneratedEvHandling> p_degeneratedHandling; ///< Handling of degenerated tensors
BoolProperty p_maskMixedTensors;
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, 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".
//
// 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 "TensorGlyphRenderer.h"
#include "tgt/tgt_math.h"
#include "tgt/logmanager.h"
#include "tgt/shadermanager.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/geometrydatafactory.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorshading.h"
namespace campvis {
static const GenericOption<TensorGlyphRenderer::GlyphType> glyphTypes[3] = {
GenericOption<TensorGlyphRenderer::GlyphType>("ellipsoid", "Ellipsoid Glyph", TensorGlyphRenderer::ELLIPSOID),
GenericOption<TensorGlyphRenderer::GlyphType>("cuboid", "Cuboid Glyph", TensorGlyphRenderer::CUBOID),
GenericOption<TensorGlyphRenderer::GlyphType>("multi", "Multi Ellipsoid Glyph", TensorGlyphRenderer::MULTI)
};
static const GenericOption<TensorGlyphRenderer::SliceOrientation> sliceOrientationOptions[3] = {
GenericOption<TensorGlyphRenderer::SliceOrientation>("z", "XY Plane", TensorGlyphRenderer::XY_PLANE),
GenericOption<TensorGlyphRenderer::SliceOrientation>("y", "XZ Plane", TensorGlyphRenderer::XZ_PLANE),
GenericOption<TensorGlyphRenderer::SliceOrientation>("x", "YZ Plane", TensorGlyphRenderer::YZ_PLANE)
};
const std::string TensorGlyphRenderer::loggerCat_ = "CAMPVis.modules.classification.TensorGlyphRenderer";
TensorGlyphRenderer::TensorGlyphRenderer(IVec2Property* viewportSizeProp)
: VisualizationProcessor(viewportSizeProp)
, p_inputEigenvalues("InputEigenvalues", "Input Eigenvalues Image", "eigenvalues", DataNameProperty::READ, INVALID_RESULT | INVALID_PROPERTIES)
, p_inputEigenvectors("InputEigenvectors", "Input Eigenvectors Image", "eigenvectors", DataNameProperty::READ, INVALID_RESULT | INVALID_PROPERTIES)
, p_renderOutput("RenderOutput", "Output Image", "TensorGlyphRenderer.output", DataNameProperty::WRITE)
, p_glyphType("GlyphType", "Glyph Type to Render", glyphTypes, 3)
, p_glyphSize("GlyphSize", "Glyph Size", 1.f, .1f, 5.f)
, p_camera("Camera", "Camera", tgt::Camera())
, p_sliceOrientation("SliceOrientation", "Slice Orientation", sliceOrientationOptions, 3, INVALID_RESULT | INVALID_PROPERTIES)
, p_sliceNumber("SliceNumber", "Slice Number", 0, 0, 0)
, _ellipsoidGeometry(0)
, _cubeGeometry(0)
{
addDecorator(new ProcessorDecoratorShading());
addProperty(&p_inputEigenvalues);
addProperty(&p_inputEigenvectors);
addProperty(&p_renderOutput);
addProperty(&p_glyphType);
addProperty(&p_glyphSize);
addProperty(&p_camera);
addProperty(&p_sliceOrientation);
addProperty(&p_sliceNumber);
decoratePropertyCollection(this);
}
TensorGlyphRenderer::~TensorGlyphRenderer() {
}
void TensorGlyphRenderer::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "modules/tensor/glsl/tensorglyphrenderer.frag", generateGlslHeader(), false);
_shader->setAttributeLocation(0, "in_Position");
_shader->setAttributeLocation(3, "in_TexCoord");
_cubeGeometry = GeometryDataFactory::createCube(tgt::Bounds(tgt::vec3(-.5f), tgt::vec3(.5f)), tgt::Bounds(tgt::vec3(0.f), tgt::vec3(1.f)));
_ellipsoidGeometry = GeometryDataFactory::createSphere(8, 16);
}
void TensorGlyphRenderer::deinit() {
ShdrMgr.dispose(_shader);
delete _ellipsoidGeometry;
_ellipsoidGeometry = 0;
delete _cubeGeometry;
_cubeGeometry = 0;
VisualizationProcessor::deinit();
}
void TensorGlyphRenderer::updateResult(DataContainer& dataContainer) {
if (_cubeGeometry == 0 || _ellipsoidGeometry == 0) {
LERROR("Error initializing glyph geometries.");
return;
}
GenericImageRepresentationLocal<float, 3>::ScopedRepresentation evals(dataContainer, p_inputEigenvalues.getValue());
GenericImageRepresentationLocal<float, 9>::ScopedRepresentation evecs(dataContainer, p_inputEigenvectors.getValue());
if (evals && evecs) {
if (evals->getSize() == evecs->getSize()) {
const tgt::Camera& cam = p_camera.getValue();
const tgt::svec3& imgSize = evals->getSize();
glEnable(GL_DEPTH_TEST);
_shader->activate();
_shader->setIgnoreUniformLocationError(true);
_shader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(getEffectiveViewportSize()));
_shader->setUniform("_projectionMatrix", cam.getProjectionMatrix());
_shader->setUniform("_viewMatrix", cam.getViewMatrix());
decorateRenderProlog(dataContainer, _shader);
FramebufferActivationGuard fag(this);
createAndAttachColorTexture();
createAndAttachDepthTexture();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
switch (p_sliceOrientation.getOptionValue()) {
case XY_PLANE:
for (size_t x = 0; x < imgSize.x; ++x) {
for (size_t y = 0; y < imgSize.y; ++y) {
renderTensorGlyph(evals, evecs, tgt::ivec3(static_cast<int>(x), static_cast<int>(y), p_sliceNumber.getValue()));
}
}
break;
case XZ_PLANE:
for (size_t x = 0; x < imgSize.x; ++x) {
for (size_t z = 0; z < imgSize.z; ++z) {
renderTensorGlyph(evals, evecs, tgt::ivec3(static_cast<int>(x), p_sliceNumber.getValue(), static_cast<int>(z)));
}
}
break;
case YZ_PLANE:
for (size_t y = 0; y < imgSize.y; ++y) {
for (size_t z = 0; z < imgSize.z; ++z) {
renderTensorGlyph(evals, evecs, tgt::ivec3(p_sliceNumber.getValue(), static_cast<int>(y), static_cast<int>(z)));
}
}
break;
}
decorateRenderEpilog(_shader);
_shader->deactivate();
glDisable(GL_DEPTH_TEST);
dataContainer.addData(p_renderOutput.getValue(), new RenderData(_fbo));
}
}
else {
LERROR("Could not find suitable input data.");
}
validate(INVALID_RESULT);
}
void TensorGlyphRenderer::updateProperties(DataContainer& dataContainer) {
GenericImageRepresentationLocal<float, 3>::ScopedRepresentation evals(dataContainer, p_inputEigenvalues.getValue());
GenericImageRepresentationLocal<float, 9>::ScopedRepresentation evecs(dataContainer, p_inputEigenvectors.getValue());
if (evals && evecs) {
if (evals->getSize() == evecs->getSize()) {
switch (p_sliceOrientation.getOptionValue()) {
case XY_PLANE:
p_sliceNumber.setMaxValue(static_cast<int>(evals->getSize().z - 1));
break;
case XZ_PLANE:
p_sliceNumber.setMaxValue(static_cast<int>(evals->getSize().y - 1));
break;
case YZ_PLANE:
p_sliceNumber.setMaxValue(static_cast<int>(evals->getSize().x - 1));
break;
}
}
else {
LERROR("Size of eigenvalue image and eigenvector image mismatch!");
}
}
validate(INVALID_PROPERTIES);
}
void TensorGlyphRenderer::updateShader() {
_shader->setHeaders(generateGlslHeader());
_shader->rebuild();
validate(INVALID_SHADER);
}
std::string TensorGlyphRenderer::generateGlslHeader() const {
std::string toReturn = getDecoratedHeader();
return toReturn;
}
void TensorGlyphRenderer::renderTensorGlyph(const GenericImageRepresentationLocal<float, 3>* evals, const GenericImageRepresentationLocal<float, 9>* evecs, const tgt::vec3& position) {
/// minimum scale factor
const float EPS = .1f;
// gather value
const tgt::vec3& eigenvalues = evals->getElement(position);
const tgt::mat3& eigenvectors = evecs->getElement(position);
if (eigenvalues == tgt::vec3::zero || eigenvectors == tgt::mat3::zero)
return;
// compute rotation matrix
tgt::vec3 rotx = tgt::normalize(eigenvectors[0]);
tgt::vec3 roty = tgt::normalize(eigenvectors[1]);
tgt::vec3 rotz = tgt::normalize(eigenvectors[2]);
tgt::mat4 rotationMatrix(rotx[0], rotx[1], rotx[2], 0.f,
roty[0], roty[1], roty[2], 0.f,
rotz[0], rotz[1], rotz[2], 0.f,
0.f , 0.f , 0.f , 1.f);
float divScale = (1.f - 2.f*EPS)/(eigenvalues[0]);
const tgt::mat4& voxelToWorldMatrix = evals->getParent()->getMappingInformation().getVoxelToWorldMatrix();
// compute model matrix (without glyph-related transformation
tgt::mat4 modelMatrix = voxelToWorldMatrix * tgt::mat4::createTranslation(position) * rotationMatrix * tgt::mat4::createScale(tgt::vec3(p_glyphSize.getValue()));
// setup shader
_shader->setUniform("_color", tgt::vec4(rotx, 1.f));
switch (p_glyphType.getOptionValue()) {
case CUBOID:
// render single cuboid
_shader->setUniform("_modelMatrix", modelMatrix * tgt::mat4::createScale(tgt::vec3((1.f - EPS), (EPS + divScale*eigenvalues[1]), (EPS + divScale*eigenvalues[2]))));
_cubeGeometry->render(GL_POLYGON);
break;
case ELLIPSOID:
// render single ellipsoid
_shader->setUniform("_modelMatrix", modelMatrix * tgt::mat4::createScale(tgt::vec3((1.f - EPS), (EPS + divScale*eigenvalues[1]), (EPS + divScale*eigenvalues[2]))));
_ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
break;
case MULTI:
// render three ellipsoids in different shapes
_shader->setUniform("_modelMatrix", modelMatrix * tgt::mat4::createScale(tgt::vec3(divScale*eigenvalues[2], divScale*eigenvalues[2], divScale*eigenvalues[2])));
_ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
_shader->setUniform("_modelMatrix", modelMatrix * tgt::mat4::createScale(tgt::vec3(divScale*eigenvalues[1], divScale*eigenvalues[1], EPS)));
_ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
_shader->setUniform("_modelMatrix", modelMatrix * tgt::mat4::createScale(tgt::vec3(divScale*eigenvalues[0], EPS, EPS)));
_ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
break;
}
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, 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".
//
// 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 TENSORGLYPHRENDERER_H__
#define TENSORGLYPHRENDERER_H__
#include <string>
#include "core/pipeline/visualizationprocessor.h"
#include "core/pipeline/abstractprocessordecorator.h"
#include "core/properties/cameraproperty.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/floatingpointproperty.h"
#include "core/properties/genericproperty.h"
#include "core/properties/numericproperty.h"
#include "core/properties/optionproperty.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
#include "core/datastructures/geometrydata.h"
namespace tgt {
class Shader;
}
namespace campvis {
/**
* Renders axis-aligned slices with tensor glyphs.
*/
class TensorGlyphRenderer : public VisualizationProcessor, public HasProcessorDecorators {
public:
/// Glyph type to render
enum GlyphType {
ELLIPSOID,
CUBOID,
MULTI
};
/// Slice orientation
enum SliceOrientation {
XY_PLANE = 0,
XZ_PLANE = 1,
YZ_PLANE = 2
};
/**
* Constructs a new TensorGlyphRenderer Processor
**/
TensorGlyphRenderer(IVec2Property* viewportSizeProp);
/**
* Destructor
**/
virtual ~TensorGlyphRenderer();
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return "TensorGlyphRenderer"; };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Renders axis-aligned slices with tensor glyphs."; };
/// \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::deinit()
virtual void init();
/// \see AbstractProcessor::deinit()
virtual void deinit();
DataNameProperty p_inputEigenvalues; ///< ID for input eigenvalues
DataNameProperty p_inputEigenvectors; ///< ID for input eigenvectors
DataNameProperty p_renderOutput; ///< ID for output rendered image
GenericOptionProperty<GlyphType> p_glyphType; ///< Glyph type to render
FloatProperty p_glyphSize; ///< Glyph render size
CameraProperty p_camera; ///< camera
GenericOptionProperty<SliceOrientation> p_sliceOrientation; ///< orientation of the slice to extract
IntProperty p_sliceNumber; ///< slice number
protected:
/// \see AbstractProcessor::updateResult
virtual void updateResult(DataContainer& dataContainer);
/// \see AbstractProcessor::updateProperties
virtual void updateProperties(DataContainer& dataContainer);
/// \see AbstractProcessor::updateShader
virtual void updateShader();
std::string generateGlslHeader() const;
/**
* Renders a single tensor glyph at the given position
* \param evals Eigenvalue image
* \param evecs Eigenvector image
* \param position Image position to render in voxel coordinates
*/
void renderTensorGlyph(const GenericImageRepresentationLocal<float, 3>* evals, const GenericImageRepresentationLocal<float, 9>* evecs, const tgt::vec3& position);
tgt::Shader* _shader; ///< Shader for glyph rendering
GeometryData* _ellipsoidGeometry; ///< Geometry for ellipsoid rendering
GeometryData* _cubeGeometry; ///< Geometry for cuboid rendering
static const std::string loggerCat_;
};
}
#endif // TENSORGLYPHRENDERER_H__
......@@ -15,3 +15,4 @@ FILE(GLOB ThisModHeaders RELATIVE ${ModulesDir}
SET(ThisModShaderDirectories "modules/pipelines/glsl")
SET(ThisModDependencies io vis)
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