tensorglyphrenderer.cpp 13 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// ================================================================================================
// 
// 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 "tensorglyphrenderer.h"

27
#include "cgt/cgt_math.h"
28
29
#include "cgt/logmanager.h"
#include "cgt/shadermanager.h"
30

31
#include "core/datastructures/cameradata.h"
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "core/datastructures/imagedata.h"
#include "core/datastructures/lightsourcedata.h"
#include "core/datastructures/geometrydatafactory.h"
#include "core/datastructures/renderdata.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)
        , p_inputEigenvectors("InputEigenvectors", "Input Eigenvectors Image", "eigenvectors", DataNameProperty::READ)
57
        , p_camera("Camera", "Camera ID", "camera", DataNameProperty::READ)
58
59
60
61
62
63
64
65
66
67
68
69
        , 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_enableShading("EnableShading", "Enable Shading", true)
        , p_lightId("LightId", "Input Light Source", "lightsource", DataNameProperty::READ)
        , p_sliceOrientation("SliceOrientation", "Slice Orientation", sliceOrientationOptions, 3)
        , p_sliceNumber("SliceNumber", "Slice Number", 0, 0, 0)
        , _ellipsoidGeometry(0)
        , _cubeGeometry(0)
    {
        addProperty(p_inputEigenvalues, INVALID_RESULT | INVALID_PROPERTIES);
        addProperty(p_inputEigenvectors, INVALID_RESULT | INVALID_PROPERTIES);
70
        addProperty(p_camera);
71
        addProperty(p_renderOutput);
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
        addProperty(p_glyphType);
        addProperty(p_glyphSize);

        addProperty(p_enableShading, INVALID_RESULT | INVALID_PROPERTIES | INVALID_SHADER);
        addProperty(p_lightId);

        addProperty(p_sliceOrientation, INVALID_RESULT | INVALID_PROPERTIES);
        addProperty(p_sliceNumber);
    }

    TensorGlyphRenderer::~TensorGlyphRenderer() {

    }

    void TensorGlyphRenderer::init() {
        VisualizationProcessor::init();

        _shader = ShdrMgr.load("modules/tensor/glsl/tensorglyphrenderer.vert", "modules/tensor/glsl/tensorglyphrenderer.frag", generateGlslHeader());
91
        _cubeGeometry = GeometryDataFactory::createCube(cgt::Bounds(cgt::vec3(-.5f), cgt::vec3(.5f)), cgt::Bounds(cgt::vec3(0.f), cgt::vec3(1.f)));
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
        _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());
115
        ScopedTypedData<CameraData> camera(dataContainer, p_camera.getValue());
116

117
        if (evals && evecs && camera) {
118
119
120
121
            if (evals->getSize() == evecs->getSize()) {
                ScopedTypedData<LightSourceData> light(dataContainer, p_lightId.getValue());

                if (p_enableShading.getValue() == false || light != nullptr) {
122
                    const cgt::Camera& cam = camera->getCamera();
123
                    const cgt::svec3& imgSize = evals->getSize();
124
125
126
127
128

                    glEnable(GL_DEPTH_TEST);
                    _shader->activate();

                    _shader->setIgnoreUniformLocationError(true);
129
                    _shader->setUniform("_viewportSizeRCP", 1.f / cgt::vec2(getEffectiveViewportSize()));
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
                    _shader->setUniform("_projectionMatrix", cam.getProjectionMatrix());
                    _shader->setUniform("_viewMatrix", cam.getViewMatrix());

                    if (p_enableShading.getValue() && light != nullptr) {
                        light->bind(_shader, "_lightSource");
                    }

                    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) {
146
                                    renderTensorGlyph(evals, evecs, cgt::ivec3(static_cast<int>(x), static_cast<int>(y), p_sliceNumber.getValue()));
147
148
149
150
151
152
                                }
                            }
                            break;
                        case XZ_PLANE:
                            for (size_t x = 0; x < imgSize.x; ++x) {
                                for (size_t z = 0; z < imgSize.z; ++z) {
153
                                    renderTensorGlyph(evals, evecs, cgt::ivec3(static_cast<int>(x), p_sliceNumber.getValue(), static_cast<int>(z)));
154
155
156
157
158
159
                                }
                            }
                            break;
                        case YZ_PLANE:
                            for (size_t y = 0; y < imgSize.y; ++y) {
                                for (size_t z = 0; z < imgSize.z; ++z) {
160
                                    renderTensorGlyph(evals, evecs, cgt::ivec3(p_sliceNumber.getValue(), static_cast<int>(y), static_cast<int>(z)));
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
                                }
                            }
                            break;
                    }


                    _shader->deactivate();
                    glDisable(GL_DEPTH_TEST);

                    dataContainer.addData(p_renderOutput.getValue(), new RenderData(_fbo));
                }
                else {
                    LDEBUG("Could not load light source from DataContainer.");
                }
            }
        }
        else {
            LERROR("Could not find suitable input data.");
        }
    }

    void TensorGlyphRenderer::updateProperties(DataContainer& dataContainer) {
        p_lightId.setVisible(p_enableShading.getValue());

        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!");
            }
        }
    }

    void TensorGlyphRenderer::updateShader() {
        _shader->setHeaders(generateGlslHeader());
        _shader->rebuild();
    }

    std::string TensorGlyphRenderer::generateGlslHeader() const {
        std::string toReturn;
        if (p_enableShading.getValue())
            toReturn += "#define ENABLE_SHADING\n";

        return toReturn;
    }

221
    void TensorGlyphRenderer::renderTensorGlyph(const GenericImageRepresentationLocal<float, 3>* evals, const GenericImageRepresentationLocal<float, 9>* evecs, const cgt::vec3& position) {
222
223
224
225
        /// minimum scale factor
        const float EPS = .1f;

        // gather value
226
227
228
        const cgt::vec3& eigenvalues = evals->getElement(position);
        const cgt::mat3& eigenvectors = evecs->getElement(position);
        if (eigenvalues == cgt::vec3::zero || eigenvectors == cgt::mat3::zero)
229
230
231
            return;

        // compute rotation matrix
232
233
234
235
        cgt::vec3 rotx = cgt::normalize(eigenvectors[0]);
        cgt::vec3 roty = cgt::normalize(eigenvectors[1]);
        cgt::vec3 rotz = cgt::normalize(eigenvectors[2]);
        cgt::mat4 rotationMatrix(rotx[0], rotx[1], rotx[2], 0.f,
236
237
238
239
240
            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]);
241
        const cgt::mat4& voxelToWorldMatrix = evals->getParent()->getMappingInformation().getVoxelToWorldMatrix();
242
243

        // compute model matrix (without glyph-related transformation
244
        cgt::mat4 modelMatrix = voxelToWorldMatrix * cgt::mat4::createTranslation(position) * rotationMatrix * cgt::mat4::createScale(cgt::vec3(p_glyphSize.getValue()));
245
246

        // setup shader
247
        _shader->setUniform("_color", cgt::vec4(rotx, 1.f));
248
249
250
251

        switch (p_glyphType.getOptionValue()) {
            case CUBOID:
                // render single cuboid
252
                _shader->setUniform("_modelMatrix", modelMatrix * cgt::mat4::createScale(cgt::vec3((1.f - EPS), (EPS + divScale*eigenvalues[1]), (EPS + divScale*eigenvalues[2]))));
253
254
255
256
257
                _cubeGeometry->render(GL_POLYGON);
                break;

            case ELLIPSOID:
                // render single ellipsoid
258
                _shader->setUniform("_modelMatrix", modelMatrix * cgt::mat4::createScale(cgt::vec3((1.f - EPS), (EPS + divScale*eigenvalues[1]), (EPS + divScale*eigenvalues[2]))));
259
260
261
262
263
                _ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
                break;

            case MULTI:
                // render three ellipsoids in different shapes
264
                _shader->setUniform("_modelMatrix", modelMatrix * cgt::mat4::createScale(cgt::vec3(divScale*eigenvalues[2], divScale*eigenvalues[2], divScale*eigenvalues[2])));
265
                _ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
266
                _shader->setUniform("_modelMatrix", modelMatrix * cgt::mat4::createScale(cgt::vec3(divScale*eigenvalues[1], divScale*eigenvalues[1], EPS)));
267
                _ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
268
                _shader->setUniform("_modelMatrix", modelMatrix * cgt::mat4::createScale(cgt::vec3(divScale*eigenvalues[0], EPS, EPS)));
269
270
271
272
273
274
                _ellipsoidGeometry->render(GL_TRIANGLE_STRIP);
                break;
        }
    }

}