Commit e20da19c authored by Jakob Weiss's avatar Jakob Weiss
Browse files

Added / fixed stereo module

Somehow I messed up the cherrypick/merge history.
Stereo module provides basic processors for a compositor and a camera
generator to generate stereo images.
parent f75772e3
Loading
Loading
Loading
Loading
+107 −0
Original line number Diff line number Diff line
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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.
// 
// ================================================================================================

in vec3 ex_TexCoord;
out vec4 out_Color;
#include "tools/texture2d.frag"

uniform sampler2D _colorTextureLeft;
uniform sampler2D _colorTextureRight;

void main() {
    out_Color = vec4(ex_TexCoord, 1.0);
    #ifdef MODE_INTERLACE_VERT
    //Vertical Interlaced
    if (mod(trunc(gl_FragCoord.x), 2.0) < 0.5)
        out_Color = texture2D(_colorTextureLeft, vec2(ex_TexCoord));
    else
        out_Color = texture2D(_colorTextureRight, vec2(ex_TexCoord));
    #endif

#ifdef MODE_INTERLACE_HORIZ
    //Vertical Interlaced
    if (mod(trunc(gl_FragCoord.y), 2.0) < 0.5)
        out_Color = texture2D(_colorTextureLeft, vec2(ex_TexCoord));
    else
        out_Color = texture2D(_colorTextureRight, vec2(ex_TexCoord));
    #endif

#ifdef MODE_SIDEBYSIDE_VERT
    // Vertical Side-by-Side (i.e. top/bottom)
    if(ex_TexCoord.y < 0.5)
        out_Color = texture2D(_colorTextureLeft, vec2(ex_TexCoord.x, ex_TexCoord.y * 2.0));
    else
        out_Color = texture2D(_colorTextureRight, vec2(ex_TexCoord.x, (ex_TexCoord.y - 0.5) * 2.0));
    #endif

#ifdef MODE_SIDEBYSIDE_HORIZ
    // Horizontal Side-by-Side (i.e. left/right)
    if(ex_TexCoord.x < 0.5)
        out_Color = texture2D(_colorTextureLeft, vec2(ex_TexCoord.x * 2.0, ex_TexCoord.y));
    else
        out_Color = texture2D(_colorTextureRight, vec2((ex_TexCoord.x - 0.5) * 2.0, ex_TexCoord.y));
    #endif

#ifdef MODE_ANAGLYPH_MCALLISTER
    // Anaglyph rendering based on https://research.csc.ncsu.edu/stereographics/LS.pdf

    // anaglyph color transform matrices for red/cyan
    mat3 P_L = mat3(
        0.4155, -0.0458, -0.0545, // first column
        0.4710, -0.0484, -0.0614, // second column
        0.1670, -0.0258, 0.0128 // third column
    );
    mat3 P_R = mat3(
        -0.0109, 0.3756, -0.0651, // first column
        -0.0365, 0.7333, -0.1286, // second column
        -0.0060, 0.0111, 1.2968 // third column
    );

    vec4 cLeft = texture2D(_colorTextureLeft, vec2(ex_TexCoord));
    vec4 cRight = texture2D(_colorTextureRight, vec2(ex_TexCoord));
    out_Color = clamp(vec4(P_L*cLeft.xyz + P_R * cRight.xyz, 1.0f), 0.0, 1.0);
#endif

// Code for half-color and optimized anaglyph from https://wiki.delphigl.com/index.php/shader_Stereoscopy
#ifdef MODE_ANAGLYPH_HALFCOLOR
  //Half-Color Anaglyph
  vec3 cleft = texture2D(_colorTextureLeft, vec2(ex_TexCoord)).xyz;
  vec3 cright = texture2D(_colorTextureRight, vec2(ex_TexCoord)).xyz;
  out_Color.r = 0.299*cleft.r + 0.587*cleft.g + 0.114*cleft.b;  //Half-Color
  out_Color.g = cright.g;
  out_Color.b = cright.b;
#endif

#ifdef MODE_ANAGLYPH_WIMMER
  //"Optimized Anaglyph" by Peteter Wimmer http://www.3dtv.at/knowhow/AnaglyphComparison_en.aspx
  vec3 cleft = texture2D(_colorTextureLeft, vec2(ex_TexCoord)).xyz;
  vec3 cright = texture2D(_colorTextureRight, vec2(ex_TexCoord)).xyz;
  //out_Color.r = 0.7*cleft.g + 0.3*cleft.b;            // no gamma correction
  out_Color.r = pow(0.7*cleft.g + 0.3*cleft.b, 1.5);  // with gamma correction
  out_Color.g = cright.g;
  out_Color.b = cright.b;
#endif

}
+105 −0
Original line number Diff line number Diff line
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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 STEREOPIPELINE_H__
#define STEREOPIPELINE_H__

#include "core/pipeline/autoevaluationpipeline.h"

#include "modules/modulesapi.h"
#include "modules/base/processors/lightsourceprovider.h"
#include "modules/base/processors/trackballcameraprovider.h"
#include "modules/io/processors/vtkimagereader.h"
#include "modules/vis/processors/geometryrenderer.h"
#include "modules/vis/processors/rendertargetcompositor.h"
#include "modules/stereo/processors/stereocompositor.h"
#include "modules/stereo/processors/stereocameragenerator.h"

namespace campvis {
    template <class WrappedPipeline>
    class CAMPVIS_MODULES_API StereoPipeline: public WrappedPipeline {
    public:
        /**
         * [UNFINISHED / NOT IMPLEMENTED] Creates a StereoRenderDemo pipeline. Wraps an existing pipeline and modifies it for stereo rendering.
         * \param   dataContainer   Reference to the DataContainer containing local working set of data
         *                          for this pipeline, must be valid the whole lifetime of this pipeline.
         */
        explicit StereoPipeline(DataContainer& dc)
            : WrappedPipeline(dc)
            , _stereoCamGenerator()
            , _stereoComp(&_canvasSize)
        {
        };

        /**
         * Virtual Destructor
         **/
        virtual ~StereoPipeline()
        {
        }

        /// \see AutoEvaluationPipeline::init()
        virtual void init() override
        {
            addProcessor(&_stereoCamGenerator);
            WrappedPipeline::init();
            addProcessor(&_stereoComp);               
            _stereoComp.init(); // we must init this ourselves since this is normally called in the base class init()
            _stereoComp.p_outputImage.setValue("Stereo.Final");
            _renderTargetID.setValue("Stereo.Final");
            
        }

        /// \see AutoEvaluationPipeline::deinit()
        virtual void deinit() override {
            WrappedPipeline::deinit();
        }

        virtual void executePipeline() override {
            std::cout << "Executing Pipeline.." << std::endl;
            WrappedPipeline::executePipeline();
        }

        /// \see AbstractPipeline::getName()
        virtual std::string getName() const { return getId(); };
        static const std::string getId() { return std::string("Stereo<") + WrappedPipeline::getId() + ">"; };


    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) override {
            std::cout << "Processor " << processor->getInstanceName() << " validated." << std::endl;
        };

    protected:
        StereoCameraGenerator _stereoCamGenerator;
        StereoCompositor _stereoComp;
    };
}

#endif // STEREOPIPELINE_H__
+168 −0
Original line number Diff line number Diff line
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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 "stereorenderdemo.h"

#include "cgt/texturereadertga.h"

#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"

#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"

#include "core/datastructures/geometrydatafactory.h"

namespace campvis {

    StereoRenderDemo::StereoRenderDemo(DataContainer& dc)
        : AutoEvaluationPipeline(dc, getId())
        , _tcp(&_canvasSize)
        , _lsp()
        , _geometryReader()
        , _lvRendererL(&_canvasSize)
        , _teapotRendererL(&_canvasSize)
        , _compositorL(&_canvasSize)
        , _lvRendererR(&_canvasSize)
        , _teapotRendererR(&_canvasSize)
        , _compositorR(&_canvasSize)
        , _stereoComp(&_canvasSize)
    {
        addEventListenerToBack(&_tcp);

        addProcessor(&_tcp);
        addProcessor(&_stereoCamGenerator);
        addProcessor(&_lsp);
        addProcessor(&_geometryReader);
        addProcessor(&_teapotRendererL);
        addProcessor(&_lvRendererL);
        addProcessor(&_compositorL);
        addProcessor(&_teapotRendererR);
        addProcessor(&_lvRendererR);
        addProcessor(&_compositorR);
        addProcessor(&_stereoComp);
    }

    StereoRenderDemo::~StereoRenderDemo() {
        _geometryReader.s_validated.disconnect(this);
    }

    void StereoRenderDemo::init() {
        AutoEvaluationPipeline::init();

        // load textureData from file
        cgt::TextureReaderTga trt;
        cgt::Texture* campTexture = trt.loadTexture(ShdrMgr.completePath("/modules/vis/sampledata/camplogo.tga"), cgt::Texture::LINEAR);
        ImageData* textureData = new ImageData(2, campTexture->getDimensions(), campTexture->getNumChannels());
        ImageRepresentationGL::create(textureData, campTexture);
        getDataContainer().addData("CampTexture", textureData);

        // connect slots
        _geometryReader.s_validated.connect(this, &StereoRenderDemo::onProcessorValidated);

        // create Teapot
        auto teapot = GeometryDataFactory::createTeapot();
        teapot->applyTransformationToVertices(cgt::mat4::createScale(cgt::vec3(50.f)));
        getDataContainer().addData("teapot", teapot.release());

        // setup pipeline
        _geometryReader.p_url.setValue(ShdrMgr.completePath("/modules/vis/sampledata/left_ventricle_mesh.vtk"));
        _geometryReader.p_targetImageID.setValue("reader.output");

        _lvRendererL.p_geometryID.setValue("reader.output");
        _lvRendererL.p_renderTargetID.setValue("lv.render.left");
        _lvRendererL.p_renderMode.selectById("triangles");
        _lvRendererL.p_camera.setValue("camera.left");
        _lvRendererL.p_solidColor.setValue(cgt::vec4(0.8f, 0.f, 0.f, .9f));

        _lvRendererR.p_geometryID.setValue("reader.output");
        _lvRendererR.p_renderTargetID.setValue("lv.render.right");
        _lvRendererR.p_renderMode.selectById("triangles");
        _lvRendererR.p_camera.setValue("camera.right");
        _lvRendererR.p_solidColor.setValue(cgt::vec4(0.8f, 0.f, 0.f, .9f));

        _teapotRendererL.p_geometryID.setValue("teapot");
        _teapotRendererL.p_renderTargetID.setValue("teapot.render.left");
        _teapotRendererL.p_renderMode.selectById("trianglestrip");
        _teapotRendererL.p_showWireframe.setValue(false);
        _teapotRendererL.p_camera.setValue("camera.left");
        _teapotRendererL.p_solidColor.setValue(cgt::vec4(1.f, 0.5f, 0.f, 1.f));

        _teapotRendererR.p_geometryID.setValue("teapot");
        _teapotRendererR.p_renderTargetID.setValue("teapot.render.right");
        _teapotRendererR.p_renderMode.selectById("trianglestrip");
        _teapotRendererR.p_showWireframe.setValue(false);
        _teapotRendererR.p_camera.setValue("camera.right");
        _teapotRendererR.p_solidColor.setValue(cgt::vec4(1.f, 0.5f, 0.f, 1.f));

        _compositorL.p_firstImageId.setValue("lv.render.left");
        _compositorL.p_secondImageId.setValue("teapot.render.left");
        _compositorL.p_compositingMethod.selectById("depth");
        _compositorL.p_targetImageId.setValue("combine.left");
        _compositorL.p_enableBackground.setValue(false);

        _compositorR.p_firstImageId.setValue("lv.render.right");
        _compositorR.p_secondImageId.setValue("teapot.render.right");
        _compositorR.p_compositingMethod.selectById("depth");
        _compositorR.p_targetImageId.setValue("combine.right");
        _compositorR.p_enableBackground.setValue(false);

        _stereoComp.p_inputLeft.setValue("combine.left");
        _stereoComp.p_inputRight.setValue("combine.right");
        _stereoComp.p_outputImage.setValue("stereocombined");

        // setup the eye viewport size
        _lvRendererL.setViewportSizeProperty(&_stereoComp.p_preferredInputViewports);
        _teapotRendererL.setViewportSizeProperty(&_stereoComp.p_preferredInputViewports);
        _compositorL.setViewportSizeProperty(&_stereoComp.p_preferredInputViewports);
        _lvRendererR.setViewportSizeProperty(&_stereoComp.p_preferredInputViewports);
        _teapotRendererR.setViewportSizeProperty(&_stereoComp.p_preferredInputViewports);
        _compositorR.setViewportSizeProperty(&_stereoComp.p_preferredInputViewports);

        _renderTargetID.setValue("stereocombined");
    }

    void StereoRenderDemo::deinit() {
        _geometryReader.s_validated.disconnect(this);
        AutoEvaluationPipeline::deinit();
    }

    void StereoRenderDemo::onProcessorValidated(AbstractProcessor* processor) {
        if (processor == &_geometryReader) {
            // update camera
            ScopedTypedData<IHasWorldBounds> lv(*_dataContainer, _geometryReader.p_targetImageID.getValue());
            ScopedTypedData<IHasWorldBounds> teapot(*_dataContainer, "teapot");

            if (lv != 0 && teapot != 0) {
                cgt::Bounds unionBounds;
                //unionBounds.addVolume(lv->getWorldBounds());
                unionBounds.addVolume(teapot->getWorldBounds());

                _tcp.reinitializeCamera(unionBounds);
            }
        }
    }


}
+91 −0
Original line number Diff line number Diff line
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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 STEREORENDERDEMO_H__
#define STEREORENDERDEMO_H__

#include "core/pipeline/autoevaluationpipeline.h"

#include "modules/modulesapi.h"
#include "modules/base/processors/lightsourceprovider.h"
#include "modules/base/processors/trackballcameraprovider.h"
#include "modules/io/processors/vtkimagereader.h"
#include "modules/vis/processors/geometryrenderer.h"
#include "modules/vis/processors/rendertargetcompositor.h"
#include "modules/stereo/processors/stereocompositor.h"
#include "modules/stereo/processors/stereocameragenerator.h"

namespace campvis {
    class CAMPVIS_MODULES_API StereoRenderDemo : public AutoEvaluationPipeline {
    public:
        /**
         * Creates a StereoRenderDemo pipeline.
         * \param   dataContainer   Reference to the DataContainer containing local working set of data
         *                          for this pipeline, must be valid the whole lifetime of this pipeline.
         */
        explicit StereoRenderDemo(DataContainer& dc);

        /**
         * Virtual Destructor
         **/
        virtual ~StereoRenderDemo();

        /// \see AutoEvaluationPipeline::init()
        virtual void init();

        /// \see AutoEvaluationPipeline::deinit()
        virtual void deinit();

        /// \see AbstractPipeline::getName()
        virtual std::string getName() const { return getId(); };
        static const std::string getId() { return "StereoRenderDemo"; };


    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);

        TrackballCameraProvider _tcp;

        StereoCameraGenerator _stereoCamGenerator;

        LightSourceProvider _lsp;
        VtkImageReader _geometryReader;
        GeometryRenderer _lvRendererL;
        GeometryRenderer _teapotRendererL;
        RenderTargetCompositor _compositorL;

        GeometryRenderer _lvRendererR;
        GeometryRenderer _teapotRendererR;
        RenderTargetCompositor _compositorR;

        StereoCompositor _stereoComp;
    };
}

#endif // STEREORENDERDEMO_H__
+69 −0
Original line number Diff line number Diff line
#ifndef STEREOPAIRGENERATOR_H__
#define STEREOPAIRGENERATOR_H__

#include "core/pipeline/abstractprocessor.h"

#include "core/properties/datanameproperty.h"
#include "core/properties/floatingpointproperty.h"

#include "modules/modulesapi.h"

namespace campvis {

    /**
    * TODO
    */
    class CAMPVIS_MODULES_API StereoCameraGenerator : public AbstractProcessor {
    public:
        /**
        * Constructs a new StereoPairGenerator Processor
        **/
        StereoCameraGenerator();

        /**
        * Destructor
        **/
        virtual ~StereoCameraGenerator();

        /// \see AbstractProcessor::init()
        virtual void init();
        /// \see AbstractProcessor::deinit()
        virtual void deinit();

        /// To be used in ProcessorFactory static methods
        static const std::string getId() { return "StereoCameraGenerator"; };
        /// \see AbstractProcessor::getName()
        virtual const std::string getName() const { return getId(); };
        /// \see AbstractProcessor::getDescription()
        virtual const std::string getDescription() const { return "StereoCameraGenerator"; };
        /// \see AbstractProcessor::getAuthor()
        virtual const std::string getAuthor() const { return "Jakob Weiss <jakob.weiss@in.tum.de>"; };
        /// \see AbstractProcessor::getProcessorState()
        virtual ProcessorState getProcessorState() const { return AbstractProcessor::EXPERIMENTAL; };



        /**
        *
        * \param   dataContainer    DataContainer to work on
        */
        virtual void updateResult(DataContainer& dataContainer);

        /// \see AbstractProcessor::updateProperties
        virtual void updateProperties(DataContainer& dataContainer);


        DataNameProperty p_sourceCameraID;

        FloatProperty p_baseline;

    protected:

    private:
        static std::string loggerCat_;

    };

}

#endif // STEREOPAIRGENERATOR_H__
 No newline at end of file
Loading