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

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