source: osgVisual/src/distortion/visual_distortion.cpp @ 147

Last change on this file since 147 was 147, checked in by Torben Dannhauer, 13 years ago
File size: 19.6 KB
Line 
1/* -*-c++-*- osgVisual - Copyright (C) 2009-2010 Torben Dannhauer
2 *
3 * This library is based on OpenSceneGraph, open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * osgVisual requires for some proprietary modules a license from the correspondig manufacturer.
9 * You have to aquire licenses for all used proprietary modules.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * OpenSceneGraph Public License for more details.
15*/
16
17#include <visual_distortion.h>
18
19using namespace osgVisual;
20
21visual_distortion::visual_distortion(osgViewer::Viewer* viewer_, osg::ArgumentParser& arguments_, std::string configFileName) : viewer(viewer_), arguments(arguments_)
22{
23        OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion instantiated." << std::endl;
24
25        initialized = false;
26        distortionEnabled = false;
27        parser = new CameraConfigParser();
28
29        distortedGraph = NULL;
30        cleanGraph = NULL;
31
32        distortMapTexture = NULL;
33        blendMapTexture = NULL;
34}
35
36visual_distortion::~visual_distortion(void)
37{
38        OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion destroyed." << std::endl;
39}
40
41bool visual_distortion::processCommandlineparameters()
42{
43        // Distortion files.
44        arguments.getApplicationUsage()->addCommandLineOption("-C <channelname>","Setup the channel name, this is the preset for blendmap, distortionmap and camera configuration file.");
45    arguments.getApplicationUsage()->addCommandLineOption("--distortionmap","Set a distortion map file name.");
46    arguments.getApplicationUsage()->addCommandLineOption("--blendmap","Set a blend map file name.");
47
48        // Render implementation.
49        arguments.getApplicationUsage()->addCommandLineOption("--shaderDistortion","Use OpenGL shader for distortion and blending.");
50        arguments.getApplicationUsage()->addCommandLineOption("--fbo","Use Frame Buffer Object for render to texture, where supported.");
51    arguments.getApplicationUsage()->addCommandLineOption("--fb","Use FrameBuffer for render to texture.");
52    arguments.getApplicationUsage()->addCommandLineOption("--pbuffer","Use Pixel Buffer for render to texture, where supported.");
53    arguments.getApplicationUsage()->addCommandLineOption("--window","Use a seperate Window for render to texture.");
54
55        // Texture
56    arguments.getApplicationUsage()->addCommandLineOption("--width","Set the width of the render to texture.");         // used for all render implementations
57    arguments.getApplicationUsage()->addCommandLineOption("--height","Set the height of the render to texture.");       // used for all render implementations
58
59        // Texture Rectangle?
60    arguments.getApplicationUsage()->addCommandLineOption("--texture-rectangle","Use osg::TextureRectangle for doing the render to texure to.");
61
62        // HDR?
63    arguments.getApplicationUsage()->addCommandLineOption("--hdr","Render distortion as HDR.");
64
65        // Read out Distortion CMDLine arguments
66        while (arguments.read("--width", tex_width)) {}
67    while (arguments.read("--height", tex_height)) {}
68
69        while (arguments.read("--fbo")) { renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; }
70    while (arguments.read("--pbuffer")) { renderImplementation = osg::Camera::PIXEL_BUFFER; }
71    while (arguments.read("--pbuffer-rtt")) { renderImplementation = osg::Camera::PIXEL_BUFFER_RTT; }
72    while (arguments.read("--fb")) { renderImplementation = osg::Camera::FRAME_BUFFER; }
73    while (arguments.read("--window")) { renderImplementation = osg::Camera::SEPERATE_WINDOW; }
74
75    while (arguments.read("--texture-rectangle")) { useTextureRectangle = true; }
76
77    while (arguments.read("--shaderDistortion")) { useShaderDistortion = true; }
78
79    while (arguments.read("--hdr")) { useHDR = true; }
80
81        while (arguments.read("--distortionmap", distortMapFileName)) { }
82    while (arguments.read("--blendmap", blendMapFileName)) { }
83
84        std::string pre_cfg("..\\resources\\distortion\\view_");
85        std::string pre_distortion("..\\resources\\distortion\\distort_");
86        std::string pre_blend("..\\resources\\distortion\\blend_");
87        std::string post_cfg(".cfg");
88        std::string post_distortion(".bmp");
89        std::string post_blend(".bmp");
90        std::string channelname;
91        while (arguments.read("-C",channelname))
92        {
93                OSG_NOTIFY(osg::INFO) << "channelname:" << channelname << std::endl;
94                // load channel config
95                parser->parseConfigFile((pre_cfg+channelname+post_cfg).data());
96                // load channel blendmap
97                blendMapFileName = (pre_blend+channelname+post_blend).data();
98                // load channel distortionmap
99                distortMapFileName = (pre_distortion+channelname+post_distortion).data(); 
100                // set channel frustum
101                if( parser->isConfigParsed())
102                        viewer->getCamera()->setProjectionMatrixAsFrustum((parser->getFrustumDataset())[0], (parser->getFrustumDataset())[1], (parser->getFrustumDataset())[2], (parser->getFrustumDataset())[3], (parser->getFrustumDataset())[4], (parser->getFrustumDataset())[5]);
103                else
104                        OSG_NOTIFY(osg::WARN) << "WARNING: Unable to parse Frustum values from '" << pre_cfg<<channelname<<post_cfg << "' -- continue without valid frustum values." << std::endl;
105        }
106
107         // report any errors if they have occurred when parsing the program arguments.
108    if (arguments.errors())
109    {
110        arguments.writeErrorMessages(std::cout);
111                exit(1);
112    }
113        return true;
114}
115
116osg::Group* visual_distortion::initialize(osg::Group* subgraph, const osg::Vec4& clearColor )
117{
118        OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion initialize..." << std::endl;
119
120        // Initialize variables:
121        tex_width = 2048;
122    tex_height = 2048;
123        renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT;
124        useTextureRectangle = false;
125        useShaderDistortion = false;
126        useHDR = false; 
127        distortMapFileName = "..\\resources\\distortion\\distort_distDisabled.bmp";
128        blendMapFileName = "..\\resources\\distortion\\blend_distDisabled.bmp";
129
130
131
132
133        // Process Commandline arguments:
134        processCommandlineparameters();
135
136        // Add this node to the scenegraph to get updated during update traversal.
137        subgraph->addChild( this );
138
139        // add the keyboard handler for toggle distortion
140        arguments.getApplicationUsage()->addKeyboardMouseBinding("d", "Toggle Distortion.");
141        kBEventHandler = new ToggleDistortionKBEventHandler( this );
142        viewer->addEventHandler( kBEventHandler );
143
144        cleanGraph = subgraph;
145        distortedGraph = createPreRenderSubGraph( subgraph, clearColor );
146
147        // Create and install updateCallback (to get called for copying the main cameras view matrixes to the PRE_RENDER camera)
148        // -- must be called _AFTER_ createPreRenderSubGraph() (necessary because sceneCamera is set by createPreRenderSubGraph())
149        updateCallback = new distortionUpdateCallback( viewer, sceneCamera );
150        this->setUpdateCallback( updateCallback );
151
152        // Note down state flags..
153        initialized = true;
154        distortionEnabled = true;
155
156        distortionEnabled = true;
157        viewer->setSceneData( distortedGraph );
158       
159        return distortedGraph;
160}
161
162void visual_distortion::shutdown()
163{
164        if(initialized)
165        {
166                // Remove this Node from scenegraph
167                cleanGraph->removeChild( this );
168
169                // Remove update callback
170                this->removeUpdateCallback( updateCallback );
171                updateCallback = NULL;
172
173                OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion shutdown complete." << std::endl;
174        }
175}
176
177void visual_distortion::distortionUpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
178{
179        // Copy Main Camera's matrixes to the PRE_RENDER Camera.
180        //std::cout << "distortion updatecallback" << std::endl;
181        sceneCamera->setViewMatrix( viewer->getCamera()->getViewMatrix() );
182        sceneCamera->setProjectionMatrix( viewer->getCamera()->getProjectionMatrix() );
183}
184
185void visual_distortion::toggleDistortion()
186{
187        // Toggle
188        //// If not Distorted: enabled distortion
189        if( !distortionEnabled )
190        {
191                distortionEnabled = true;
192                viewer->setSceneData( distortedGraph );
193        }
194        else    // .. otherwise disable distortion
195        {
196                distortionEnabled = false;
197                viewer->setSceneData( cleanGraph );
198        }
199}
200
201
202osg::Group* visual_distortion::createPreRenderSubGraph(osg::Group* subgraph, const osg::Vec4& clearColor )
203{
204    if (!subgraph) return 0;
205
206    // create a group to contain the flag and the pre rendering camera.
207    osg::Group* parent = new osg::Group;
208
209    // texture to render to and to use for rendering of flag.
210    osg::Texture* texture = 0;
211    if (useTextureRectangle)
212    {
213        osg::TextureRectangle* textureRect = new osg::TextureRectangle;
214        textureRect->setTextureSize(tex_width, tex_height);
215        textureRect->setInternalFormat(GL_RGBA);
216        textureRect->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
217        textureRect->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
218       
219        texture = textureRect;
220    }
221    else
222    {
223        osg::Texture2D* texture2D = new osg::Texture2D;
224        texture2D->setTextureSize(tex_width, tex_height);
225        texture2D->setInternalFormat(GL_RGBA);
226        texture2D->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
227        texture2D->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
228       
229        texture = texture2D;
230    } 
231
232    if (useHDR)
233    {
234        texture->setInternalFormat(GL_RGBA16F_ARB);
235        texture->setSourceFormat(GL_RGBA);
236        texture->setSourceType(GL_FLOAT);
237    }
238
239    // load a distortion map texture file
240        if ( osgDB::fileExists( distortMapFileName ) )
241                distortMapTexture = loadTexture(distortMapFileName);
242        else
243        {
244                OSG_NOTIFY(osg::FATAL) << "ERROR: Distortionmap file'" << distortMapFileName << "' not found! Please change the channelname, filename or copy the desired file to the applications root folder!" << std::endl;
245                exit(-1);
246        }
247
248    // load a blend map texture file
249        if ( osgDB::fileExists( blendMapFileName ) )
250                blendMapTexture = loadTexture(blendMapFileName);
251        else
252        {
253                OSG_NOTIFY(osg::FATAL) << "ERROR: Blendmap file'" << blendMapFileName << "' not found! Please change the channelname, filename or copy the desired file to the applications root folder!" << std::endl;
254                exit(-1);
255        }
256
257    // set up the plane to render the rendered view.
258    {
259        // create the quad to visualize.
260        osg::Geometry* polyGeom = new osg::Geometry();
261
262        polyGeom->setSupportsDisplayList(false);
263
264        osg::Vec3 origin(0.0f,0.0f,0.0f);
265        osg::Vec3 xAxis(1.0f,0.0f,0.0f);
266        osg::Vec3 yAxis(0.0f,1.0f,0.0f);
267        osg::Vec3 zAxis(0.0f,0.0f,1.0f);
268        float height = 1024.0f;
269        float width = 1280.0f;
270        int noSteps = 128;
271        if (useShaderDistortion)
272            noSteps = 2;
273
274        osg::Vec3Array* vertices = new osg::Vec3Array;
275        osg::Vec2Array* texcoords = new osg::Vec2Array;
276        osg::Vec2Array* texcoords2 = useShaderDistortion?NULL:(new osg::Vec2Array);
277        osg::Vec4Array* colors = new osg::Vec4Array;
278
279        osg::Vec3 bottom = origin;
280        osg::Vec3 dx = xAxis*(width/((float)(noSteps-1)));
281        osg::Vec3 dy = yAxis*(height/((float)(noSteps-1)));
282
283        osg::Vec2 bottom_texcoord(0.0f,0.0f);
284        osg::Vec2 dx_texcoord(1.0f/(float)(noSteps-1),0.0f);
285        osg::Vec2 dy_texcoord(0.0f,1.0f/(float)(noSteps-1));
286
287        osg::Vec3 cursor = bottom;
288        osg::Vec2 texcoord = bottom_texcoord;
289        int i,j;
290        for(i=0;i<noSteps;++i)
291        {
292            osg::Vec3 cursor = bottom+dy*(float)i;
293            osg::Vec2 texcoord = bottom_texcoord+dy_texcoord*(float)i;
294            for(j=0;j<noSteps;++j)
295            {
296                vertices->push_back(cursor);
297                if (distortMapTexture && !useShaderDistortion)
298                {
299                    osg::Vec2 imgcoord = osg::Vec2((distortMapTexture->getImage(0)->s()-1) * texcoord.x(),
300                                                   (distortMapTexture->getImage(0)->t()-1) * texcoord.y());
301                    unsigned char* pPixel = &distortMapTexture->getImage(0)->data()[(int)imgcoord.y()*distortMapTexture->getImage(0)->getRowSizeInBytes()+
302                                                                                    (int)imgcoord.x()*distortMapTexture->getImage(0)->getPixelSizeInBits()/8];
303                    texcoords->push_back(osg::Vec2(((float)pPixel[2] / 255.0f + (pPixel[0] % 16)) / 16.0f,
304                                                   1.0f - ((float)pPixel[1] / 255.0f + (pPixel[0] / 16)) / 16.0f));
305                    texcoords2->push_back(osg::Vec2(texcoord.x(), texcoord.y()));
306                }
307                else
308                    texcoords->push_back(osg::Vec2(texcoord.x(), texcoord.y()));
309                colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
310
311                cursor += dx;
312                texcoord += dx_texcoord;
313            }
314        }
315
316        // pass the created vertex array to the points geometry object.
317        polyGeom->setVertexArray(vertices);
318
319        polyGeom->setColorArray(colors);
320        polyGeom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
321        polyGeom->setTexCoordArray(0,texcoords);
322        if (!useShaderDistortion)
323            polyGeom->setTexCoordArray(2,texcoords2);
324
325        for(i=0;i<noSteps-1;++i)
326        {
327            osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);
328            for(j=0;j<noSteps;++j)
329            {
330                elements->push_back(j+(i+1)*noSteps);
331                elements->push_back(j+(i)*noSteps);
332            }
333            polyGeom->addPrimitiveSet(elements);
334        }
335
336        // new we need to add the texture to the Drawable, we do so by creating a
337        // StateSet to contain the Texture StateAttribute.
338        osg::StateSet* stateset = polyGeom->getOrCreateStateSet();
339        stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
340        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
341        stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
342
343        osg::Geode* geode = new osg::Geode();
344        geode->addDrawable(polyGeom);
345
346        if (useShaderDistortion)
347        {
348            // apply the distortion map texture
349            if (distortMapTexture)
350                geode->getOrCreateStateSet()->setTextureAttributeAndModes(1, distortMapTexture, osg::StateAttribute::ON);
351        }
352
353        // apply the blend map texture
354        if (blendMapTexture)
355            geode->getOrCreateStateSet()->setTextureAttributeAndModes(2, blendMapTexture, osg::StateAttribute::ON);
356
357        // set up the camera to render the textured quad
358        osg::Camera* camera = new osg::Camera;
359
360        // just inherit the main cameras view
361        camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
362        camera->setViewMatrix(osg::Matrix::identity());
363        //sceneCamera->setProjectionMatrixAsOrtho2D(0,viewer->getCamera()->getViewport()->width(),0,viewer->getCamera()->getViewport()->height());
364                camera->setProjectionMatrixAsOrtho2D(0,1280,0,1024);
365                /** \todo: use screen size dynamically */
366
367        // set the camera to render before the main camera.
368        camera->setRenderOrder(osg::Camera::POST_RENDER, 200);
369
370        // only clear the depth buffer
371        camera->setClearMask(0);
372
373        // add subgraph to render
374        camera->addChild(geode);
375
376        if (useShaderDistortion)
377        {
378            // create shaders for distortion
379            osg::StateSet* ss = geode->getOrCreateStateSet();
380
381            osg::Program* distortProgram = new osg::Program;
382            distortProgram->setName( "distortion" );
383            osg::Shader* distortVertObj = new osg::Shader( osg::Shader::VERTEX );
384            osg::Shader* distortFragObj = new osg::Shader( osg::Shader::FRAGMENT );
385
386            if (loadShaderSource( distortVertObj, "../resources/distortion/shader.vert" ) &&
387                loadShaderSource( distortFragObj, "../resources/distortion/shader.frag" ) &&
388                distortMapTexture)
389            {
390                distortProgram->addShader( distortFragObj );
391                distortProgram->addShader( distortVertObj );
392                ss->addUniform( new osg::Uniform("textureImage", 0) );
393                ss->addUniform( new osg::Uniform("textureDistort", 1) );
394                ss->addUniform( new osg::Uniform("textureBlend", 2) );
395                ss->setAttributeAndModes(distortProgram, osg::StateAttribute::ON);
396            }
397                        else
398                        {
399                                OSG_NOTIFY(osg::FATAL) << "##################################" << std::endl << "## Unable to activate ShaderDistortion!" << std::endl << "## ABORT" << std::endl << "##################################" << std::endl;
400                                exit(0);
401                        }
402        }
403
404        parent->addChild(camera);
405    }
406
407    // then create the camera node to do the render to texture
408    {   
409        osg::Camera* camera = new osg::Camera;
410
411        // set up the background color and clear mask.
412        camera->setClearColor(clearColor);
413        camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
414
415
416        // just inherit the main cameras view
417                /* ABSOLUTE_RF required to make intersections possible.
418                Disadvantage of ABOLUTE_RF : the maincameras view matrix and projection
419                matrix has to copied to the PRE_RENDER camera by our self.
420                Therefore an update callback is installed.
421                */
422                camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); 
423        camera->setProjectionMatrix(osg::Matrixd::identity());
424        camera->setViewMatrix(osg::Matrixd::identity());
425
426        // set viewport
427        camera->setViewport(0,0,tex_width,tex_height);
428
429        // set the camera to render before the main camera.
430        camera->setRenderOrder(osg::Camera::PRE_RENDER, 0);
431
432                sceneCamera = camera;
433
434        // tell the camera to use OpenGL frame buffer object where supported.
435        camera->setRenderTargetImplementation(renderImplementation);
436
437        // attach the texture and use it as the color buffer.
438        camera->attach(osg::Camera::COLOR_BUFFER, texture);     // No Multisampling/Antialiasing
439                //camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, 0, false, 4, 4); // 4x Multisampling/Antialiasing
440
441        // add subgraph to render
442        camera->addChild(subgraph);
443
444        parent->addChild(camera);
445    }   
446    return parent;
447}
448
449
450bool visual_distortion::loadShaderSource( osg::Shader* shader, const std::string& fileName )
451{
452    std::string foundFileName = osgDB::findDataFile(fileName);
453    if (foundFileName.length() != 0 )
454    {
455        return shader->loadShaderSourceFromFile( foundFileName.c_str() );
456    }
457
458    OSG_NOTIFY(osg::WARN) << "File \"" << fileName << "\" not found." << std::endl;
459
460    return false;
461}
462
463osg::Texture* visual_distortion::loadTexture( const std::string& fileName )
464{
465    std::string foundFileName = osgDB::findDataFile(fileName);
466    if (foundFileName.length() != 0 )
467    {
468        // load distortion map texture file
469        osg::Image* image = osgDB::readImageFile(foundFileName);
470        if (image)
471        {
472                        osg::Texture2D* texture = new osg::Texture2D;
473            texture->setImage(image);
474            texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
475            texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
476            texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE);
477            texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE);
478            return texture;
479        }
480    }
481
482    OSG_NOTIFY(osg::WARN) << "File \"" << fileName << "\" not found." << std::endl;
483
484    return NULL;
485}
Note: See TracBrowser for help on using the repository browser.