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

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