eepgenerator.cpp 10.2 KB
Newer Older
1 2
// ================================================================================================
// 
schultezub's avatar
schultezub committed
3
// This file is part of the CAMPVis Software Framework.
4
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
//      Chair for Computer Aided Medical Procedures
8 9
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
10
// 
schultezub's avatar
schultezub committed
11
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
12
// 
13 14 15 16
// 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
17
// 
18 19 20 21
// 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.
22 23 24
// 
// ================================================================================================

25 26
#include "eepgenerator.h"

27 28 29 30
#include "cgt/glmath.h"
#include "cgt/logmanager.h"
#include "cgt/shadermanager.h"
#include "cgt/textureunit.h"
31

32
#include "core/datastructures/cameradata.h"
33 34
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
35
#include "core/datastructures/renderdata.h"
36
#include "core/datastructures/renderdata.h"
37
#include "core/datastructures/meshgeometry.h"
38
#include "core/pipeline/processordecoratormasking.h"
39

schultezub's avatar
schultezub committed
40 41
namespace campvis {
    const std::string EEPGenerator::loggerCat_ = "CAMPVis.modules.vis.EEPGenerator";
42

43 44
    EEPGenerator::EEPGenerator(IVec2Property* viewportSizeProp)
        : VisualizationProcessor(viewportSizeProp)
45
        , p_sourceImageID("sourceImageID", "Input Image", "", DataNameProperty::READ)
46
        , p_geometryID("geometryID", "Input Proxy Geometry ID", "proxygeometry", DataNameProperty::READ)
47
        , p_geometryImageId("GeometryImageId", "Rendered Geometry to Integrate (optional)", "", DataNameProperty::READ)
48
        , p_camera("Camera", "Camera ID", "camera", DataNameProperty::READ)
49 50
        , p_entryImageID("entryImageID", "Output Entry Points Image", "eep.entry", DataNameProperty::WRITE)
        , p_exitImageID("exitImageID", "Output Exit Points Image", "eep.exit", DataNameProperty::WRITE)
51
        , p_enableMirror("enableMirror", "Enable Virtual Mirror Feature", false)
52
        , p_mirrorID("mirrorID", "Input Mirror ID", "", DataNameProperty::READ)
53 54
        , _shader(0)
    {
55 56
        addDecorator(new ProcessorDecoratorMasking());

57 58 59
        addProperty(p_sourceImageID);
        addProperty(p_geometryID);
        addProperty(p_geometryImageId);
60
        addProperty(p_camera);
61 62
        addProperty(p_entryImageID);
        addProperty(p_exitImageID);
63

64 65
        addProperty(p_enableMirror, INVALID_RESULT | INVALID_PROPERTIES);
        addProperty(p_mirrorID);
66
        p_mirrorID.setVisible(false);
67 68

        decoratePropertyCollection(this);
69 70 71 72 73 74 75 76
    }

    EEPGenerator::~EEPGenerator() {

    }

    void EEPGenerator::init() {
        VisualizationProcessor::init();
77
        _shader = ShdrMgr.load("core/glsl/passthrough.vert", "modules/vis/glsl/eepgenerator.frag", generateHeader());
78 79 80 81
    }

    void EEPGenerator::deinit() {
        ShdrMgr.dispose(_shader);
schultezub's avatar
schultezub committed
82
        _shader = 0;
83 84 85
        VisualizationProcessor::deinit();
    }

86
    void EEPGenerator::updateResult(DataContainer& data) {
87
        ImageRepresentationGL::ScopedRepresentation img(data, p_sourceImageID.getValue());
88
        ScopedTypedData<MeshGeometry> proxyGeometry(data, p_geometryID.getValue());
89
        ScopedTypedData<CameraData> camera(data, p_camera.getValue());
90

91
        if (img != nullptr && proxyGeometry != nullptr && _shader != nullptr && camera != nullptr) {
92
            if (img->getDimensionality() == 3) {
93
                const cgt::Camera& cam = camera->getCamera();
94
                ScopedTypedData<RenderData> geometryImage(data, p_geometryImageId.getValue(), true);
95

96
                cgt::Bounds textureBounds(cgt::vec3(0.f), cgt::vec3(1.f));
97

98 99
                // clip proxy geometry against near-plane to support camera in volume
                // FIXME:   In some cases, the near plane is not rendered correctly...
100 101
                float nearPlaneDistToOrigin = cgt::dot(cam.getPosition(), -cam.getLook()) - cam.getNearDist() - .002f;
                MeshGeometry clipped = proxyGeometry->clipAgainstPlane(nearPlaneDistToOrigin, -cam.getLook(), true, 0.02f);
102

103
                // start render setup
104
                _shader->activate();
105

106
                // setup virtual mirror if necessary
107
                cgt::mat4 mirrorMatrix = cgt::mat4::identity;
108
                if (p_enableMirror.getValue()) {
109
                    ScopedTypedData<FaceGeometry> mirrorGeometry(data, p_mirrorID.getValue());
schultezub's avatar
schultezub committed
110
                    if (mirrorGeometry && mirrorGeometry->size() > 0) {
111 112 113
                        const cgt::vec3& p = mirrorGeometry->getVertices()[0];
                        cgt::vec3 n = cgt::normalize(cgt::cross(mirrorGeometry->getVertices()[1] - mirrorGeometry->getVertices()[0], mirrorGeometry->getVertices()[2] - mirrorGeometry->getVertices()[0]));
                        float k = cgt::dot(p, n);
schultezub's avatar
schultezub committed
114 115 116

                        // mirror matrix sponsored by:
                        // Jiang 
117
                        mirrorMatrix = cgt::transpose(cgt::mat4(
schultezub's avatar
schultezub committed
118 119 120
                            1 - 2*n.x*n.x, -2*n.y*n.x   , -2*n.z*n.x   , 0, 
                            -2*n.x*n.y   , 1 - 2*n.y*n.y, -2*n.z*n.y   , 0, 
                            -2*n.x*n.z   , -2*n.y*n.z   , 1 - 2*n.z*n.z, 0, 
121
                            2*n.x*k      , 2*n.y*k      , 2*n.z*k      , 1));
schultezub's avatar
schultezub committed
122 123 124 125
                    }
                    else {
                        LERROR("No suitable virtual mirror geometry found.");
                    }
126
                }
127
                
128
                cgt::TextureUnit geometryDepthUnit, entryDepthUnit;
schultezub's avatar
schultezub committed
129

130
                _shader->setIgnoreUniformLocationError(true);
131
                _shader->setUniform("_viewportSizeRCP", 1.f / cgt::vec2(getEffectiveViewportSize()));
132
                _shader->setUniform("_modelMatrix", mirrorMatrix);
133 134 135 136
                _shader->setUniform("_projectionMatrix", cam.getProjectionMatrix());
                _shader->setUniform("_viewMatrix", cam.getViewMatrix());

                if (geometryImage != 0) {
137
                    geometryImage->bindDepthTexture(_shader, geometryDepthUnit, "_geometryDepthTexture", "_geometryDepthTexParams");
138 139 140 141 142

                    _shader->setUniform("_integrateGeometry", true);
                    _shader->setUniform("_near", cam.getNearDist());
                    _shader->setUniform("_far", cam.getFarDist());

143
                    cgt::mat4 inverseView = cgt::mat4::identity;
144 145 146
                    if (cam.getViewMatrix().invert(inverseView))
                        _shader->setUniform("_inverseViewMatrix", inverseView);

147
                    cgt::mat4 inverseProjection = cgt::mat4::identity;
148 149 150
                    if (cam.getProjectionMatrix().invert(inverseProjection))
                        _shader->setUniform("_inverseProjectionMatrix", inverseProjection);

151
                    _shader->setUniform("_volumeWorldToTexture", img->getParent()->getMappingInformation().getWorldToTextureMatrix());
152 153 154 155 156
                }
                else {
                    _shader->setUniform("_integrateGeometry", false);
                }

157
                _shader->setIgnoreUniformLocationError(false);
158

159 160
                FramebufferActivationGuard fag(this);
                decorateRenderProlog(data, _shader);
161
                glEnable(GL_CULL_FACE);
162
                glEnable(GL_DEPTH_TEST);
163 164

                // create entry points texture
165 166
                createAndAttachTexture(GL_RGBA16);
                createAndAttachDepthTexture();
167
                _shader->setUniform("_isEntrypoint", true);
168

169 170
                glDepthFunc(GL_LESS);
                glClearDepth(1.0f);
171
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
172
                glCullFace(p_enableMirror.getValue() ? GL_FRONT : GL_BACK);
173
                clipped.render(GL_TRIANGLE_FAN);
174

175
                RenderData* entrypoints = new RenderData(_fbo);
176
                _fbo->detachAll();
177 178

                // create exit points texture
179 180
                createAndAttachTexture(GL_RGBA16);
                createAndAttachDepthTexture();
181 182 183
                _shader->setUniform("_isEntrypoint", false);

                if (geometryImage != 0) {
184
                    entrypoints->bindDepthTexture(_shader, entryDepthUnit, "_entryDepthTexture", "_entryDepthTexParams");
185
                }
186

187 188
                glDepthFunc(GL_GREATER);
                glClearDepth(0.0f);
189
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
190
                glCullFace(p_enableMirror.getValue() ? GL_BACK : GL_FRONT);
191
                clipped.render(GL_TRIANGLE_FAN);
192

193
                RenderData* exitpoints = new RenderData(_fbo);
194
                decorateRenderEpilog(_shader);
195
                _shader->deactivate();
196 197 198 199 200 201 202

                glDepthFunc(GL_LESS);
                glClearDepth(1.0f);
                glCullFace(GL_BACK);
                glDisable(GL_CULL_FACE);
                glDisable(GL_DEPTH_TEST);

schultezub's avatar
schultezub committed
203
                LGL_ERROR;
204

205 206
                data.addData(p_entryImageID.getValue(), entrypoints);
                data.addData(p_exitImageID.getValue(), exitpoints);
207 208 209 210 211 212
            }
            else {
                LERROR("Input image must have dimensionality of 3.");
            }
        }
        else {
213
            LDEBUG("No suitable input image or proxy geometry found.");
214 215 216
        }
    }

schultezub's avatar
schultezub committed
217
    std::string EEPGenerator::generateHeader() const {
218
        return getDecoratedHeader();
schultezub's avatar
schultezub committed
219 220
    }

221
    void EEPGenerator::updateProperties(DataContainer& dataContainer) {
222 223 224
        p_mirrorID.setVisible(p_enableMirror.getValue());
    }

225 226 227 228 229
    void EEPGenerator::updateShader() {
        _shader->setHeaders(generateHeader());
        _shader->rebuild();
    }

230
}