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
        , 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)
65
        , _shader(nullptr)
66
67
        , _ellipsoidGeometry(nullptr)
        , _cubeGeometry(nullptr)
68
69
70
    {
        addProperty(p_inputEigenvalues, INVALID_RESULT | INVALID_PROPERTIES);
        addProperty(p_inputEigenvectors, INVALID_RESULT | INVALID_PROPERTIES);
71
        addProperty(p_camera);
72
        addProperty(p_renderOutput);
73

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
        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());
92
        _cubeGeometry = GeometryDataFactory::createCube(cgt::Bounds(cgt::vec3(-.5f), cgt::vec3(.5f)), cgt::Bounds(cgt::vec3(0.f), cgt::vec3(1.f)));
93
94
95
96
97
98
        _ellipsoidGeometry = GeometryDataFactory::createSphere(8, 16);
    }

    void TensorGlyphRenderer::deinit() {
        ShdrMgr.dispose(_shader);

99
100
        _ellipsoidGeometry = nullptr;
        _cubeGeometry = nullptr;
101
102
103
104
105
106
107
108
109
110
111
112
113


        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());
114
        ScopedTypedData<CameraData> camera(dataContainer, p_camera.getValue());
115

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

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

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

                    _shader->setIgnoreUniformLocationError(true);
128
                    _shader->setUniform("_viewportSizeRCP", 1.f / cgt::vec2(getEffectiveViewportSize()));
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
                    _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) {
145
                                    renderTensorGlyph(evals, evecs, cgt::ivec3(static_cast<int>(x), static_cast<int>(y), p_sliceNumber.getValue()));
146
147
148
149
150
151
                                }
                            }
                            break;
                        case XZ_PLANE:
                            for (size_t x = 0; x < imgSize.x; ++x) {
                                for (size_t z = 0; z < imgSize.z; ++z) {
152
                                    renderTensorGlyph(evals, evecs, cgt::ivec3(static_cast<int>(x), p_sliceNumber.getValue(), static_cast<int>(z)));
153
154
155
156
157
158
                                }
                            }
                            break;
                        case YZ_PLANE:
                            for (size_t y = 0; y < imgSize.y; ++y) {
                                for (size_t z = 0; z < imgSize.z; ++z) {
159
                                    renderTensorGlyph(evals, evecs, cgt::ivec3(p_sliceNumber.getValue(), static_cast<int>(y), static_cast<int>(z)));
160
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
                                }
                            }
                            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;
    }

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

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

        // compute rotation matrix
231
232
233
234
        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,
235
236
237
238
239
            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]);
240
        const cgt::mat4& voxelToWorldMatrix = evals->getParent()->getMappingInformation().getVoxelToWorldMatrix();
241
242

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

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

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

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

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

}