Commit 205031c5 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Introducing DTI module with FiberReader, FiberTracker and FiberRenderer...

Introducing DTI module with FiberReader, FiberTracker and FiberRenderer processors (code base copied over from columbia module branch, generalized and fit into the DTI module).
parent b256feb9
// ================================================================================================
//
// 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 "fiberdata.h"
#include "cgt/buffer.h"
#include "cgt/logmanager.h"
#include "cgt/vertexarrayobject.h"
namespace campvis {
namespace dti {
FiberData::FiberData()
: AbstractData()
, _vertexBuffer(0)
, _tangentBuffer(0)
, _buffersInitialized(false)
, _vboFiberStartIndices(0)
, _vboFiberCounts(0)
{
}
FiberData::FiberData(const FiberData& rhs)
: AbstractData(rhs)
, _vertices(rhs._vertices)
, _fibers(rhs._fibers)
, _vertexBuffer(0)
, _tangentBuffer(0)
, _buffersInitialized(false)
, _vboFiberStartIndices(0)
, _vboFiberCounts(0)
{}
FiberData::~FiberData() {
delete _vertexBuffer;
delete _tangentBuffer;
delete [] _vboFiberStartIndices;
delete [] _vboFiberCounts;
}
FiberData& FiberData::operator=(const FiberData& rhs) {
if (this == &rhs)
return *this;
AbstractData::operator=(rhs);
_vertices = rhs._vertices;
_fibers = rhs._fibers;
// delete old VBOs and null pointers
delete _vertexBuffer;
delete _tangentBuffer;
_vertexBuffer = 0;
_tangentBuffer = 0;
_buffersInitialized = false;
return *this;
}
void FiberData::addFiber(const std::deque<cgt::vec3>& vertices) {
_vertices.insert(_vertices.end(), vertices.begin(), vertices.end());
_fibers.push_back(Fiber(_vertices.size() - vertices.size(), _vertices.size()));
_buffersInitialized = false;
}
void FiberData::addFiber(const std::vector<cgt::vec3>& vertices) {
_vertices.insert(_vertices.end(), vertices.begin(), vertices.end());
_fibers.push_back(Fiber(_vertices.size() - vertices.size(), _vertices.size()));
_buffersInitialized = false;
}
void FiberData::clear() {
_fibers.clear();
_vertices.clear();
_buffersInitialized = false;
}
void FiberData::updateLengths() const {
for (size_t i = 0; i < _fibers.size(); ++i) {
_fibers[i]._length = 0.0f;
for (size_t j = _fibers[i]._startIndex + 1; j < _fibers[i]._endIndex; ++j)
_fibers[i]._length += distance(_vertices[j-1], _vertices[j]);
}
}
size_t FiberData::numFibers() const {
return _fibers.size();
}
size_t FiberData::numSegments() const {
size_t sum = 0;
for (std::vector<Fiber>::const_iterator it = _fibers.begin(); it != _fibers.end(); ++it)
sum += (it->_endIndex - it->_startIndex);
return sum;
}
bool FiberData::empty() const {
return _fibers.empty();
}
FiberData* FiberData::clone() const {
FiberData* toReturn = new FiberData(*this);
return toReturn;
}
size_t FiberData::getLocalMemoryFootprint() const {
size_t sum = _vertices.size() * sizeof(cgt::vec3);
sum += _fibers.size() * sizeof(Fiber);
sum += sizeof(*this);
return sum;
}
size_t FiberData::getVideoMemoryFootprint() const {
size_t sum = 0;
if (_vertexBuffer != 0)
sum += _vertexBuffer->getBufferSize();
if (_tangentBuffer != 0)
sum += _tangentBuffer->getBufferSize();
return sum;
}
void FiberData::createGlBuffers() const {
if (_buffersInitialized || _fibers.empty() || _vertices.empty())
return;
// reset everything
delete _vertexBuffer;
delete _tangentBuffer;
delete [] _vboFiberStartIndices;
delete [] _vboFiberCounts;
_vboFiberArraySize = 0;
_vboFiberStartIndices = new GLint[_vertices.size()];
_vboFiberCounts = new GLint[_vertices.size()];
std::vector<cgt::vec3> tangents;
tangents.resize(_vertices.size());
for (std::vector<Fiber>::const_iterator it = _fibers.begin(); it != _fibers.end(); ++it) {
if (it->_visible) {
_vboFiberStartIndices[_vboFiberArraySize] = static_cast<GLint>(it->_startIndex);
_vboFiberCounts[_vboFiberArraySize] = static_cast<GLsizei>(it->_endIndex - it->_startIndex);
++_vboFiberArraySize;
}
cgt::vec3 dirPrev = cgt::vec3::zero;
cgt::vec3 dirNext = cgt::vec3::zero;
for (size_t i = it->_startIndex; i < it->_endIndex-1; ++i) {
dirNext = _vertices[i+1] - _vertices[i];
tangents[i] = cgt::normalize(dirPrev + dirNext);
dirPrev = dirNext;
}
tangents[it->_endIndex - 1] = dirPrev;
}
try {
_vertexBuffer = new cgt::BufferObject(cgt::BufferObject::ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_vertexBuffer->data(&_vertices.front(), _vertices.size() * sizeof(cgt::vec3), cgt::BufferObject::FLOAT, 3);
_tangentBuffer = new cgt::BufferObject(cgt::BufferObject::ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_tangentBuffer->data(&tangents.front(), tangents.size() * sizeof(cgt::vec3), cgt::BufferObject::FLOAT, 3);
}
catch (cgt::Exception& e) {
LERRORC("CAMPVis.modules.columbia.FiberData", "Error creating OpenGL Buffer objects: " << e.what());
_buffersInitialized = false;
return;
}
LGL_ERROR;
_buffersInitialized = true;
}
void FiberData::render(GLenum mode /*= GL_LINE_STRIP*/) const {
if (_fibers.empty() || _vertices.empty())
return;
createGlBuffers();
if (! _buffersInitialized) {
LERRORC("CAMPVis.modules.columbia.FiberData", "Cannot render without initialized OpenGL buffers.");
return;
}
cgt::VertexArrayObject vao;
vao.setVertexAttributePointer(0, _vertexBuffer);
vao.setVertexAttributePointer(1, _tangentBuffer);
LGL_ERROR;
glMultiDrawArrays(mode, _vboFiberStartIndices, _vboFiberCounts, _vboFiberArraySize);
LGL_ERROR;
}
cgt::Bounds FiberData::getWorldBounds() const {
cgt::Bounds toReturn;
for (std::vector<cgt::vec3>::const_iterator it = _vertices.begin(); it != _vertices.end(); ++it)
toReturn.addPoint(*it);
return toReturn;
}
void FiberData::setVisible(size_t index, bool visibility) {
_fibers[index]._visible = visibility;
_buffersInitialized = false;
}
const std::vector<FiberData::Fiber>& FiberData::getFibers() const {
return _fibers;
}
const std::vector<cgt::vec3>& FiberData::getVertices() const {
return _vertices;
}
std::string FiberData::getTypeAsString() const {
return "FiberData";
}
}
}
// ================================================================================================
//
// 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 FIBERDATA_H__
#define FIBERDATA_H__
#include "cgt/bounds.h"
#include "cgt/cgt_gl.h"
#include "cgt/vector.h"
#include "core/datastructures/abstractdata.h"
#include "modules/modulesapi.h"
#include <deque>
#include <vector>
namespace cgt {
class BufferObject;
}
namespace campvis {
namespace dti {
/**
* Data object storing fiber data.
*/
class CAMPVIS_MODULES_API FiberData : public AbstractData, public IHasWorldBounds {
public:
/**
* Struct storing meta information about a single fiber.
*/
struct Fiber {
size_t _startIndex; ///< Start index of the fiber
size_t _endIndex; ///< End index of the fiber (as in STL iterators: points to the element _behind_ the last vertex)
mutable float _length; ///< Length of the fiber (cached)
int _segmentId; ///< Label of the fiber
bool _visible; ///< Visibility flag of the fiber
bool _selected; ///< Selected flag of the fiber
Fiber(size_t startIndex, size_t endIndex)
: _startIndex(startIndex), _endIndex(endIndex), _length(0.f), _segmentId(0), _visible(true), _selected(false)
{};
};
/**
* Constructor.
*/
FiberData();
/**
* Copy Constructor.
* \param rhs source
*/
FiberData(const FiberData& rhs);
/**
* Destructor.
*/
virtual ~FiberData();
/**
* Assignment Operator
* \param rhs Source
* \return *this
*/
FiberData& operator=(const FiberData& rhs);
/**
* Generates a new fiber from the given vertices and adds it to this data structure.
* \param vertices Coordinates of the fiber points.
*/
void addFiber(const std::deque<cgt::vec3>& vertices);
/**
* Generates a new fiber from the given vertices and adds it to this data structure.
* \param vertices Coordinates of the fiber points.
*/
void addFiber(const std::vector<cgt::vec3>& vertices);
/**
* Sets the visibility flag of the fiber with index \a index to \a visibility.
* \param index Index of fiber to update.
* \param visibility New visibility flag of fiber \a index.
*/
void setVisible(size_t index, bool visibility);
/**
* Clears this data structure.
*/
void clear();
/**
* Computes the lengths of each fiber in this data structure and stores it in the
* corresponding field.
* \note Since there is currently not automatism to do this, you're responsible to do
* this yourself when needed.
*/
void updateLengths() const;
/**
* Returns the number of fibers in this data structure.
* \return _fibers.size()
*/
size_t numFibers() const;
/**
* Returns the number of fiber segments in this data structure.
* \return (i.e. the number of vertices - number of fibers)
*/
size_t numSegments() const;
/**
* Returns the vector of fibers.
* \return _fibers
*/
const std::vector<Fiber>& getFibers() const;
/**
* Returns the vector of fiber vertices
* \return _vertices
*/
const std::vector<cgt::vec3>& getVertices() const;
/**
* Returns whether this data structure is empty (i.e. has no fibers).
*/
bool empty() const;
/**
* Returns the fiber data extent in world coordinates.
* \note Caution: Calling this method is expensive as the bounds are computed each time.
* \return The fiber data extent in world coordinates.
*/
virtual cgt::Bounds getWorldBounds() const;
/**
* Renders the Fiber geometry of this data set in the current OpenGL context.
* \note Must be called from a valid openGL context!
* \param mode OpenGL render mode (defaults to GL_LINE_STRIP).
*/
void render(GLenum mode = GL_LINE_STRIP) const;
/// \see AbstractData::clone()
virtual FiberData* clone() const;
/// \see AbstractData::getLocalMemoryFootprint()
virtual size_t getLocalMemoryFootprint() const;
/// \see AbstractData::getVideoMemoryFootprint()
virtual size_t getVideoMemoryFootprint() const;
/// \see AbstractData::getReadableType()
virtual std::string getTypeAsString() const;
protected:
/**
* Creates the OpenGL buffers with vertex and tangent data.
*/
void createGlBuffers() const;
std::vector<cgt::vec3> _vertices; ///< The fiber vertex (coordinates) data
std::vector<Fiber> _fibers; ///< The fiber meta data
mutable cgt::BufferObject* _vertexBuffer; ///< Pointer to OpenGL buffer with vertex data (lazy-instantiated)
mutable cgt::BufferObject* _tangentBuffer; ///< Pointer to OpenGL buffer with tangent data (lazy-instantiated)
mutable bool _buffersInitialized; ///< flag whether all OpenGL buffers were successfully initialized
mutable GLint* _vboFiberStartIndices; ///< VBO start indices for each fiber
mutable GLsizei* _vboFiberCounts; ///< number of indices for each fiber
mutable GLsizei _vboFiberArraySize; ///< number of elements in the above two lists
};
}
}
#endif // FIBERDATA_H__
# CMake file for dti module
IF(${ModuleEnabled})
# Source files:
FILE(GLOB ThisModSources RELATIVE ${ModulesDir}
modules/dti/datastructures/*.cpp
modules/dti/pipelines/*.cpp
modules/dti/processors/*.cpp
)
# Header files (including GLSL files so that they'll appear in VS projects)
FILE(GLOB ThisModHeaders RELATIVE ${ModulesDir}
modules/dti/datastructures/*.h
modules/dti/glsl/*.frag
modules/dti/glsl/*.geom
modules/dti/glsl/*.vert
modules/dti/pipelines/*.h
modules/dti/processors/*.h
)
SET(ThisModShaderDirectories "modules/dti/glsl")
ENDIF(${ModuleEnabled})
SET(ThisModStatus EXPERIMENTAL)
SET(ThisModExternalDependencies FALSE)
// ================================================================================================
//
// 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 "tools/shading.frag"
#include "tools/texture3d.frag"
in vec3 geom_Normal; ///< incoming texture coordinate
in vec4 geom_Position;
in vec4 geom_Color;
in float geom_SineFlag;
out vec4 out_Color; ///< outgoing fragment color
uniform int _coloringMode = 0;
uniform vec3 _apex;
uniform vec3 _base;
uniform vec4 _color;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
const float PI = 3.1415926535897932384626433832795;
/**
* Calculate Phong terms for simple OpenGL line primitives according to
* the work of Zöckler, Stalling and Hege in "Interactive Visualization Of
* 3D-Vector Fields Using Illuminated Stream Lines", from 1996.
*/
vec3 phongShadingForLines(vec3 tangent, vec3 view, vec3 light, float shininess) {
// normalize the vectors again which are interpolated per pixel and are
// therefore different for each fragment when transfered from vertex to
// fragment shader!
// light does not need to be re-normalized, as it remains the same for
// all fragments.
//
vec3 t = normalize(tangent); // normalize again as the normal is interpolated per pixel!
vec3 v = normalize(view); // the same for the view vector: it is interpolated per pixel!
float LdotT = clamp(dot(light, t), -1.0, 1.0);
float NdotL = max(sqrt(1.0 - (LdotT * LdotT)), 0.0);
float VdotT = clamp(dot(v, t), -1.0, 1.0);
float VdotN = max(sqrt(1.0 - (VdotT * VdotT)), 0.0);
float RdotV = (LdotT * VdotT) - (NdotL * VdotN);
float specular = max(pow(RdotV, shininess), 0.0);
//const float p = 2.0;
const float p = 4.8;
return vec3(1.0, pow(NdotL, p), specular);
}
vec3 phongShadingForFaces(vec3 normal, vec3 view, vec3 light, float shininess) {
vec3 n = normalize(normal);
vec3 v = normalize(view);
vec3 l = normalize(light);
const float p = 4.8;
float NdotL = max(dot(n, l), 0.0);
vec3 halfVector = normalize(v+l);
float NdotH = max(dot(n, halfVector), 0.0);
return vec3(1.0, pow(NdotL, p), pow(NdotH, shininess));
}
/**
* Applies tube-like texture to triangle strip
*/
vec4 applyTubeTexture(vec4 color) {
float val = max(sin(geom_SineFlag * PI), .4f);
return vec4(color.rgb * (val + pow(val, 16.f)), color.a);
}
void main() {
out_Color = geom_Color;
#ifdef DO_STRIPES
out_Color = applyTubeTexture(out_Color);
#endif
#ifdef ENABLE_SHADING
// compute tangent (needed for shading and normals)
//vec3 tangent = geom_Normal.rgb;
//vec3 phongTerms = phongShadingForLines(tangent, (geom_Position.xyz / geom_Position.z) - _cameraPosition, _lightSource._position, _lightSource._shininess);
//out_Color.rbg = (color.rbg * _lightSource._ambientColor) + (color.rbg * _lightSource._diffuseColor * phongTerms.y) + (color.rbg * _lightSource._specularColor * phongTerms.z);
out_Color.rgb = calculatePhongShading(geom_Position.xyz, _lightSource, _cameraPosition, geom_Normal, out_Color.rgb, out_Color.rgb, vec3(1.0, 1.0, 1.0));
#endif
gl_FragDepth = gl_FragCoord.z;
}
// ================================================================================================
//
// 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