Commit 8d1ce85c authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge branch 'dev-velocityfield-mr' into 'development'

VectorField

VectorField renderer, pipepline, and nice sampledata.
parents a2ef0ef2 7ed86da9
......@@ -230,4 +230,114 @@ namespace campvis {
return toReturn;
}
MultiIndexedGeometry* GeometryDataFactory::createArrow(uint16_t numSlices, float tipLen, float cylRadius, float tipRadius) {
tgtAssert(numSlices > 2, "Arrow shaft must have minimum 3 slices!");
tgtAssert(tipRadius > cylRadius, "Tip radius must exceed cyclinder radius (for correct normals)!");
tgtAssert(tipLen > 0, "Tip length must be between 0 and 1!");
tgtAssert(tipLen < 1, "Tip length must be between 0 and 1!");
std::vector<tgt::vec3> vertices;
std::vector<tgt::vec3> normals;
// add bottom vertex
vertices.push_back(tgt::vec3(0.f, 0.f, 0.f));
normals.push_back(tgt::vec3(0.f, 0.f, -1.f));
// add shaft floor vertices
for (int i = 0; i < numSlices; ++i) {
float theta = static_cast<float>(i) * 2.f*tgt::PIf / static_cast<float>(numSlices);
vertices.push_back(tgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 0.f));
normals.push_back(tgt::vec3(0.f, 0.f, -1.f));
}
for (int i = 0; i < numSlices; ++i) {
float theta = static_cast<float>(i) * 2.f*tgt::PIf / static_cast<float>(numSlices);
vertices.push_back(tgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 0.f));
normals.push_back(tgt::vec3(cos(theta), sin(theta), 0.f));
}
// add shaft top vertices
for (int i = 0; i < numSlices; ++i) {
float theta = static_cast<float>(i) * 2.f*tgt::PIf / static_cast<float>(numSlices);
vertices.push_back(tgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 1.f - tipLen));
normals.push_back(tgt::vec3(cos(theta), sin(theta), 0.f));
}
for (int i = 0; i < numSlices; ++i) {
float theta = static_cast<float>(i) * 2.f*tgt::PIf / static_cast<float>(numSlices);
vertices.push_back(tgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 1.f - tipLen));
normals.push_back(tgt::vec3(0.f, 0.f, -1.f));
}
// add arrow tip outer cone vertices
for (int i = 0; i < numSlices; ++i) {
float theta = static_cast<float>(i) * 2.f*tgt::PIf / static_cast<float>(numSlices);
vertices.push_back(tgt::vec3(tipRadius * cos(theta), tipRadius * sin(theta), 1.f - tipLen));
normals.push_back(tgt::vec3(0.f, 0.f, -1.f));
}
float phi = atan2f(tipRadius, tipLen);
for (int i = 0; i < numSlices; ++i) {
float theta = static_cast<float>(i) * 2.f*tgt::PIf / static_cast<float>(numSlices);
vertices.push_back(tgt::vec3(tipRadius * cos(theta), tipRadius * sin(theta), 1.f - tipLen));
normals.push_back(tgt::vec3(cos(theta) * cos(phi), sin(theta) * cos(phi), sin(phi)));
}
// add top vertex
vertices.push_back(tgt::vec3(0.f, 0.f, 1.f));
normals.push_back(tgt::vec3(0.f, 0.f, 1.f));
// create geometry
MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(vertices, std::vector<tgt::vec3>(), std::vector<tgt::vec4>(), normals);
// add indices for primitives to geometry:
{
// cylinder floor
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
indices.push_back(0);
indices.push_back(j+1);
}
indices.push_back(0);
indices.push_back(1);
toReturn->addPrimitive(indices);
}
{
// cylinder shaft
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices);
indices.push_back(j+1+numSlices*2);
}
indices.push_back(1+numSlices);
indices.push_back(1+numSlices*2);
toReturn->addPrimitive(indices);
}
{
// arrow tip bottom area
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices*3);
indices.push_back(j+1+numSlices*4);
}
indices.push_back(1+numSlices*3);
indices.push_back(1+numSlices*4);
toReturn->addPrimitive(indices);
}
{
// arrow tip cone
uint16_t m = (uint16_t)vertices.size() - 1;
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices*5);
indices.push_back(m);
}
indices.push_back(1+numSlices*5);
indices.push_back(m);
toReturn->addPrimitive(indices);
}
return toReturn;
}
}
\ No newline at end of file
......@@ -68,11 +68,22 @@ namespace campvis {
/**
* Creates an MultiIndexedGeometry storing a unit sphere around the origin.
* \param llf Number of stacks in the sphere
* \param urb Number of slices in the sphere
* \param numStacks Number of stacks in the sphere
* \param numSlices Number of slices in the sphere
* \return MultiIndexedGeometry storing a unit sphere around the origin.
*/
static MultiIndexedGeometry* createSphere(uint16_t numStacks = 6, uint16_t numSlices = 12);
/**
* Creates an MultiIndexedGeometry storing a unit length arrow in Z direction starting from the origin.
* \param numSlices Number of slices in the cylinder and cone
* \param tipLen Length of arrow tip (between 0 and 1)
* \param cylRadius Radius of the cylinder (arrow shaft)
* \param tipRadius Radius of the bottom of the arrow tip
* \return MultiIndexedGeometry storing a unit arrow in Z direction starting from the origin.
*/
static MultiIndexedGeometry* createArrow(uint16_t numSlices = 12, float tipLen = 0.35, float cylRadius = 0.05, float tipRadius = 0.15);
};
}
......
// ================================================================================================
//
// 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_Position; ///< incoming texture coordinate
in vec3 ex_Normal; ///< 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_Normal;
out_Color.rgb = calculatePhongShading(ex_Position, _lightSource, _cameraPosition, gradient, _color.rgb, _color.rgb, vec3(1.0, 1.0, 1.0));
#endif
//out_Color = vec4(ex_Normal, 1.0);
}
// ================================================================================================
//
// 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.
//
// ================================================================================================
layout(location = 0) in vec3 in_Position; ///< incoming vertex position
layout(location = 3) in vec3 in_Normal; ///< incoming normal direction
out vec3 ex_Position; ///< outgoing world coordinates
out vec3 ex_Normal; ///< outgoing normal direction
/// Matrix defining model-to-world transformation
uniform mat4 _modelMatrix = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
/// Matrix defining view transformation
uniform mat4 _viewMatrix = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
/// Matrix defining projection transformation
uniform mat4 _projectionMatrix = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
void main() {
gl_Position = _projectionMatrix * (_viewMatrix * (_modelMatrix * vec4(in_Position, 1.0)));
ex_Position = in_Position;
mat4 normalMatrix = transpose(inverse(_modelMatrix));
vec4 normalTmp = (normalMatrix * vec4(in_Normal, 0.0));
ex_Normal = normalize((normalTmp).xyz);
}
// ================================================================================================
//
// 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 "vectorfielddemo.h"
#include "tgt/event/keyevent.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
namespace campvis {
VectorFieldDemo::VectorFieldDemo(DataContainer* dc)
: AutoEvaluationPipeline(dc)
, _imageReader()
, _vectorFieldReader()
, _vectorFieldRenderer(&_canvasSize)
, _sliceRenderer(&_canvasSize)
, _rtc(&_canvasSize)
, p_camera("Camera", "Camera", tgt::Camera())
, p_sliceNumber("SliceNuber", "Slice Number", 0, 0, 1024)
, _trackballEH(0)
{
addProperty(&p_camera);
addProperty(&p_sliceNumber);
_trackballEH = new TrackballNavigationEventListener(&p_camera, &_canvasSize);
addEventListenerToBack(_trackballEH);
addProcessor(&_imageReader);
addProcessor(&_vectorFieldReader);
addProcessor(&_vectorFieldRenderer);
addProcessor(&_sliceRenderer);
addProcessor(&_rtc);
}
VectorFieldDemo::~VectorFieldDemo() {
}
void VectorFieldDemo::init() {
AutoEvaluationPipeline::init();
p_camera.addSharedProperty(&_vectorFieldRenderer.p_camera);
p_camera.addSharedProperty(&_sliceRenderer.p_camera);
p_sliceNumber.addSharedProperty(&_vectorFieldRenderer.p_sliceNumber);
p_sliceNumber.addSharedProperty(&_sliceRenderer.p_sliceNumber);
_imageReader.p_url.setValue(CAMPVIS_SOURCE_DIR "/modules/vectorfield/sampledata/rec1_2D_comp.mhd");
_imageReader.p_targetImageID.setValue("reader.output");
_imageReader.p_targetImageID.addSharedProperty(&_sliceRenderer.p_sourceImageID);
_imageReader.s_validated.connect(this, &VectorFieldDemo::onProcessorValidated);
_vectorFieldReader.p_url.setValue(CAMPVIS_SOURCE_DIR "/modules/vectorfield/sampledata/result_vec.mhd");
_vectorFieldReader.p_targetImageID.setValue("vectors");
_vectorFieldReader.p_targetImageID.addSharedProperty(&_vectorFieldRenderer.p_inputVectors);
_vectorFieldRenderer.p_renderOutput.addSharedProperty(&_rtc.p_firstImageId);
_vectorFieldRenderer.p_arrowSize.setValue(0.03f);
_vectorFieldRenderer.p_lenThresholdMin.setValue(100.f);
_vectorFieldRenderer.p_flowProfile1.setValue(0.4716088614374652f);
_vectorFieldRenderer.p_flowProfile2.setValue(0.0638348311845516f);
_vectorFieldRenderer.p_flowProfile3.setValue(0.1713471562960614f);
_vectorFieldRenderer.p_flowProfile4.setValue(0.1019371804834016f);
_vectorFieldRenderer.p_lenThresholdMax.setValue(400.f);
_vectorFieldRenderer.p_sliceOrientation.setValue(3);
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)));
_sliceRenderer.p_transferFunction.replaceTF(tf);
_sliceRenderer.p_targetImageID.setValue("slice");
_sliceRenderer.p_targetImageID.addSharedProperty(&_rtc.p_secondImageId);
_rtc.p_compositingMethod.selectById("depth");
_rtc.p_targetImageId.setValue("composed");
_renderTargetID.setValue("composed");
}
void VectorFieldDemo::onProcessorValidated(AbstractProcessor* processor) {
if (processor == &_imageReader) {
// update camera
ScopedTypedData<IHasWorldBounds> img(*_data, _sliceRenderer.p_sourceImageID.getValue());
if (img) {
_trackballEH->reinitializeCamera(img);
}
}
}
}
// ================================================================================================
//
// 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 VECTORFIELDDEMO_H__
#define VECTORFIELDDEMO_H__
#include "core/pipeline/autoevaluationpipeline.h"
#include "core/eventhandlers/mwheeltonumericpropertyeventlistener.h"
#include "core/eventhandlers/trackballnavigationeventlistener.h"
#include "modules/io/processors/mhdimagereader.h"
#include "modules/vectorfield/processors/vectorfieldrenderer.h"
#include "modules/vis/processors/slicerenderer3d.h"
#include "modules/vis/processors/rendertargetcompositor.h"
namespace campvis {
class VectorFieldDemo : public AutoEvaluationPipeline {
public:
/**
* Small demo pipeline for vector field visualization.
*/
VectorFieldDemo(DataContainer* dc);
/**
* Virtual Destructor
**/
virtual ~VectorFieldDemo();
/// \see AutoEvaluationPipeline::init()
virtual void init();
/// \see AbstractPipeline::getName()
virtual const std::string getName() const { return getId(); };
/// \see AbstractPipeline::getId()
static const std::string getId() { return "VectorFieldDemo"; };
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;
MhdImageReader _vectorFieldReader;
VectorFieldRenderer _vectorFieldRenderer;
SliceRenderer3D _sliceRenderer;
RenderTargetCompositor _rtc;
CameraProperty p_camera;
IntProperty p_sliceNumber;
TrackballNavigationEventListener* _trackballEH;
};
}
#endif // VECTORFIELDDEMO_H__
// ================================================================================================
//
// 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 "vectorfieldrenderer.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<VectorFieldRenderer::SliceOrientation> sliceOrientationOptions[4] = {
GenericOption<VectorFieldRenderer::SliceOrientation>("z", "XY Plane", VectorFieldRenderer::XY_PLANE),
GenericOption<VectorFieldRenderer::SliceOrientation>("y", "XZ Plane", VectorFieldRenderer::XZ_PLANE),
GenericOption<VectorFieldRenderer::SliceOrientation>("x", "YZ Plane", VectorFieldRenderer::YZ_PLANE),
GenericOption<VectorFieldRenderer::SliceOrientation>("a", "XYZ Volume", VectorFieldRenderer::XYZ_VOLUME)
};
const std::string VectorFieldRenderer::loggerCat_ = "CAMPVis.modules.classification.VectorFieldRenderer";
VectorFieldRenderer::VectorFieldRenderer(IVec2Property* viewportSizeProp)
: VisualizationProcessor(viewportSizeProp)
, p_inputVectors("InputImage", "Input Image Vectors", "vectors", DataNameProperty::READ, INVALID_RESULT | INVALID_PROPERTIES)
, p_renderOutput("RenderOutput", "Output Image", "VectorFieldRenderer.output", DataNameProperty::WRITE)
, p_arrowSize("ArrowSize", "Arrow Size", 1.f, .001f, 5.f)
, p_lenThresholdMin("LenThresholdMin", "Length Threshold Min", .001f, 0.f, 1000.f, 0.005f)
, p_lenThresholdMax("LenThresholdMax", "Length Threshold Max", 10.f, 0.f, 10000.f, 10.f)
, p_flowProfile1("FlowSpline1", "Flow Profile - Spline 1", 1.f, .0f, 2.f)
, p_flowProfile2("FlowSpline2", "Flow Profile - Spline 2", 1.f, .0f, 2.f)
, p_flowProfile3("FlowSpline3", "Flow Profile - Spline 3", 1.f, .0f, 2.f)
, p_flowProfile4("FlowSpline4", "Flow Profile - Spline 4", 1.f, .0f, 2.f)
, p_Time("time", "Time", 0, 0, 100)
, p_camera("Camera", "Camera", tgt::Camera())
, p_sliceOrientation("SliceOrientation", "Slice Orientation", sliceOrientationOptions, 4, INVALID_RESULT | INVALID_PROPERTIES)
, p_sliceNumber("SliceNumber", "Slice Number", 0, 0, 0)
, _arrowGeometry(0)
{
addDecorator(new ProcessorDecoratorShading());
addProperty(&p_inputVectors);
addProperty(&p_renderOutput);
addProperty(&p_arrowSize);
addProperty(&p_lenThresholdMin);
addProperty(&p_lenThresholdMax);
addProperty(&p_camera);
addProperty(&p_sliceOrientation);
addProperty(&p_sliceNumber);
addProperty(&p_Time);
addProperty(&p_flowProfile1);
addProperty(&p_flowProfile2);
addProperty(&p_flowProfile3);
addProperty(&p_flowProfile4);
decoratePropertyCollection(this);
}
VectorFieldRenderer::~VectorFieldRenderer() {
}
void VectorFieldRenderer::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.load("modules/vectorfield/glsl/vectorfieldrenderer.vert", "modules/vectorfield/glsl/vectorfieldrenderer.frag", generateGlslHeader());
_arrowGeometry = GeometryDataFactory::createArrow(12, 0.35f, 0.05f, 0.09f);
}
void VectorFieldRenderer::deinit() {
ShdrMgr.dispose(_shader);
delete _arrowGeometry;
_arrowGeometry = 0;
VisualizationProcessor::deinit();
}
void VectorFieldRenderer::updateResult(DataContainer& dataContainer) {
if (_arrowGeometry == 0 ) {
LERROR("Error initializing arrow geometry.");
return;
}
GenericImageRepresentationLocal<float, 3>::ScopedRepresentation vectors(dataContainer, p_inputVectors.getValue());
if(vectors) {
const tgt::Camera& cam = p_camera.getValue();
const tgt::svec3& imgSize = vectors->getSize();
const int sliceNumber = p_sliceNumber.getValue();
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);
float scale = getTemporalFlowScaling((float)p_Time.getValue() / 100.f,
p_flowProfile1.getValue(),
p_flowProfile2.getValue(),
p_flowProfile3.getValue(),
p_flowProfile4.getValue());
switch (p_sliceOrientation.getOptionValue()) {
case XY_PLANE: