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

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