root/OpenSceneGraph/trunk/examples/osgmanipulator/osgmanipulator.cpp @ 12088

Revision 12088, 15.0 kB (checked in by robert, 4 years ago)

From Wang Rui, "I'd like to submit a small new feature to the osgmanipulator example
which could fix the dragger size in screen, so that no matter how we
zoom in/out the camera, the dragger will never be scaled.

This is what 3D graphics software like 3dsmax and maya behave, which
helps users select and manipulate draggers more easily.

You may turn on the feature with the new --fixedDraggerSize argument:

# osgmanipulator.exe --fixedDraggerSize --dragger TranslateAxisDragger?
cessna.osg
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgmanipulator.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osgDB/ReadFile>
20#include <osgUtil/Optimizer>
21#include <osgViewer/Viewer>
22#include <osg/CoordinateSystemNode>
23#include <osgText/Text>
24
25#include <osgManipulator/TabBoxDragger>
26#include <osgManipulator/TabBoxTrackballDragger>
27#include <osgManipulator/TabPlaneDragger>
28#include <osgManipulator/TabPlaneTrackballDragger>
29#include <osgManipulator/TrackballDragger>
30#include <osgManipulator/Translate1DDragger>
31#include <osgManipulator/Translate2DDragger>
32#include <osgManipulator/TranslateAxisDragger>
33
34#include <osg/ShapeDrawable>
35#include <osg/MatrixTransform>
36#include <osg/Geometry>
37#include <osg/Material>
38
39#include <iostream>
40
41osgManipulator::Dragger* createDragger(const std::string& name)
42{
43    osgManipulator::Dragger* dragger = 0;
44    if ("TabPlaneDragger" == name)
45    {
46        osgManipulator::TabPlaneDragger* d = new osgManipulator::TabPlaneDragger();
47        d->setupDefaultGeometry();
48        dragger = d;
49    }
50    else if ("TabPlaneTrackballDragger" == name)
51    {
52        osgManipulator::TabPlaneTrackballDragger* d = new osgManipulator::TabPlaneTrackballDragger();
53        d->setupDefaultGeometry();
54        dragger = d;
55    }
56    else if ("TabBoxTrackballDragger" == name)
57    {
58        osgManipulator::TabBoxTrackballDragger* d = new osgManipulator::TabBoxTrackballDragger();
59        d->setupDefaultGeometry();
60        dragger = d;
61    }
62    else if ("TrackballDragger" == name)
63    {
64        osgManipulator::TrackballDragger* d = new osgManipulator::TrackballDragger();
65        d->setupDefaultGeometry();
66        dragger = d;
67    }
68    else if ("Translate1DDragger" == name)
69    {
70        osgManipulator::Translate1DDragger* d = new osgManipulator::Translate1DDragger();
71        d->setupDefaultGeometry();
72        dragger = d;
73    }
74    else if ("Translate2DDragger" == name)
75    {
76        osgManipulator::Translate2DDragger* d = new osgManipulator::Translate2DDragger();
77        d->setupDefaultGeometry();
78        dragger = d;
79    }
80    else if ("TranslateAxisDragger" == name)
81    {
82        osgManipulator::TranslateAxisDragger* d = new osgManipulator::TranslateAxisDragger();
83        d->setupDefaultGeometry();
84        dragger = d;
85    }
86    else
87    {
88        osgManipulator::TabBoxDragger* d = new osgManipulator::TabBoxDragger();
89        d->setupDefaultGeometry();
90        dragger = d;
91    }
92
93   
94 
95    return dragger;
96}
97
98// The DraggerContainer node is used to fix the dragger's size on the screen
99class DraggerContainer : public osg::Group
100{
101public:
102    DraggerContainer() : _draggerSize(240.0f), _active(true) {}
103   
104    DraggerContainer( const DraggerContainer& copy, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY )
105    :   osg::Group(copy, copyop),
106        _dragger(copy._dragger), _draggerSize(copy._draggerSize), _active(copy._active)
107    {}
108   
109    META_Node( osgManipulator, DraggerContainer );
110   
111    void setDragger( osgManipulator::Dragger* dragger )
112    {
113        _dragger = dragger;
114        if ( !containsNode(dragger) ) addChild( dragger );
115    }
116   
117    osgManipulator::Dragger* getDragger() { return _dragger.get(); }
118    const osgManipulator::Dragger* getDragger() const { return _dragger.get(); }
119   
120    void setDraggerSize( float size ) { _draggerSize = size; }
121    float getDraggerSize() const { return _draggerSize; }
122   
123    void setActive( bool b ) { _active = b; }
124    bool getActive() const { return _active; }
125   
126    void traverse( osg::NodeVisitor& nv )
127    {
128        if ( _dragger.valid() )
129        {
130            if ( _active && nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR )
131            {
132                osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
133               
134                float pixelSize = cv->pixelSize(_dragger->getBound().center(), 0.48f);
135                if ( pixelSize!=_draggerSize )
136                {
137                    float pixelScale = pixelSize>0.0f ? _draggerSize/pixelSize : 1.0f;
138                    osg::Vec3d scaleFactor(pixelScale, pixelScale, pixelScale);
139                   
140                    osg::Vec3 trans = _dragger->getMatrix().getTrans();
141                    _dragger->setMatrix( osg::Matrix::scale(scaleFactor) * osg::Matrix::translate(trans) );
142                }
143            }
144        }
145        osg::Group::traverse(nv);
146    }
147   
148protected:
149    osg::ref_ptr<osgManipulator::Dragger> _dragger;
150    float _draggerSize;
151    bool _active;
152};
153
154osg::Node* addDraggerToScene(osg::Node* scene, const std::string& name, bool fixedSizeInScreen)
155{
156    scene->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
157
158    osg::MatrixTransform* selection = new osg::MatrixTransform;
159    selection->addChild(scene);
160
161    osgManipulator::Dragger* dragger = createDragger(name);
162
163    osg::Group* root = new osg::Group;
164    root->addChild(selection);
165
166    if ( fixedSizeInScreen )
167    {
168        DraggerContainer* draggerContainer = new DraggerContainer;
169        draggerContainer->setDragger( dragger );
170        root->addChild(draggerContainer);
171    }
172    else
173        root->addChild(dragger);
174
175    float scale = scene->getBound().radius() * 1.6;
176    dragger->setMatrix(osg::Matrix::scale(scale, scale, scale) *
177                       osg::Matrix::translate(scene->getBound().center()));
178
179    dragger->addTransformUpdating(selection);
180
181    // we want the dragger to handle it's own events automatically
182    dragger->setHandleEvents(true);
183
184    // if we don't set an activation key or mod mask then any mouse click on
185    // the dragger will activate it, however if do define either of ActivationModKeyMask or
186    // and ActivationKeyEvent then you'll have to press either than mod key or the specified key to
187    // be able to activate the dragger when you mouse click on it.  Please note the follow allows
188    // activation if either the ctrl key or the 'a' key is pressed and held down.
189    dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_CTRL);
190    dragger->setActivationKeyEvent('a');
191
192    return root;
193}
194
195osg::Node* createDemoScene(bool fixedSizeInScreen) {
196 
197    osg::Group* root = new osg::Group;
198
199    osg::ref_ptr<osg::Geode> geode_1 = new osg::Geode;
200    osg::ref_ptr<osg::MatrixTransform> transform_1 = new osg::MatrixTransform;
201
202    osg::ref_ptr<osg::Geode> geode_2 = new osg::Geode;
203    osg::ref_ptr<osg::MatrixTransform> transform_2 = new osg::MatrixTransform;
204
205    osg::ref_ptr<osg::Geode> geode_3 = new osg::Geode;
206    osg::ref_ptr<osg::MatrixTransform> transform_3 = new osg::MatrixTransform;
207
208    osg::ref_ptr<osg::Geode> geode_4 = new osg::Geode;
209    osg::ref_ptr<osg::MatrixTransform> transform_4 = new osg::MatrixTransform;
210
211    osg::ref_ptr<osg::Geode> geode_5 = new osg::Geode;
212    osg::ref_ptr<osg::MatrixTransform> transform_5 = new osg::MatrixTransform;
213
214    osg::ref_ptr<osg::Geode> geode_6 = new osg::Geode;
215    osg::ref_ptr<osg::MatrixTransform> transform_6 = new osg::MatrixTransform;
216
217    osg::ref_ptr<osg::Geode> geode_7 = new osg::Geode;
218    osg::ref_ptr<osg::MatrixTransform> transform_7 = new osg::MatrixTransform;
219
220 
221
222
223
224    const float radius = 0.8f;
225    const float height = 1.0f;
226    osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints;
227    hints->setDetailRatio(2.0f);
228    osg::ref_ptr<osg::ShapeDrawable> shape;
229
230    shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, -2.0f), 10, 10.0f, 0.1f), hints.get());
231    shape->setColor(osg::Vec4(0.5f, 0.5f, 0.7f, 1.0f));
232    geode_1->addDrawable(shape.get());
233
234    shape = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), radius * 2,radius), hints.get());
235    shape->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f));
236    geode_2->addDrawable(shape.get());
237
238    shape = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(-3.0f, 0.0f, 0.0f), radius,radius), hints.get());
239    shape->setColor(osg::Vec4(0.6f, 0.8f, 0.8f, 1.0f));
240    geode_3->addDrawable(shape.get());
241
242    shape = new osg::ShapeDrawable(new osg::Cone(osg::Vec3(3.0f, 0.0f, 0.0f), 2 * radius,radius), hints.get());
243    shape->setColor(osg::Vec4(0.4f, 0.9f, 0.3f, 1.0f));
244    geode_4->addDrawable(shape.get());
245
246    shape = new osg::ShapeDrawable(new osg::Cone(osg::Vec3(0.0f, -3.0f, 0.0f), radius, height), hints.get());
247    shape->setColor(osg::Vec4(0.2f, 0.5f, 0.7f, 1.0f));
248    geode_5->addDrawable(shape.get());
249
250    shape = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0.0f, 3.0f, 0.0f), radius, height), hints.get());
251    shape->setColor(osg::Vec4(1.0f, 0.3f, 0.3f, 1.0f));
252    geode_6->addDrawable(shape.get());
253
254    shape = new osg::ShapeDrawable(new osg::Cone(osg::Vec3(0.0f, 0.0f, 3.0f), 2.0f, 2.0f), hints.get());
255    shape->setColor(osg::Vec4(0.8f, 0.8f, 0.4f, 1.0f));
256    geode_7->addDrawable(shape.get());
257
258
259
260
261
262
263    // material
264    osg::ref_ptr<osg::Material> matirial = new osg::Material;
265    matirial->setColorMode(osg::Material::DIFFUSE);
266    matirial->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
267    matirial->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(1, 1, 1, 1));
268    matirial->setShininess(osg::Material::FRONT_AND_BACK, 64.0f);
269    root->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), osg::StateAttribute::ON);
270
271      transform_1.get()->addChild(addDraggerToScene(geode_1.get(),"TabBoxDragger",fixedSizeInScreen));
272    transform_2.get()->addChild(addDraggerToScene(geode_2.get(),"TabPlaneDragger",fixedSizeInScreen));
273    transform_3.get()->addChild(addDraggerToScene(geode_3.get(),"TabBoxTrackballDragger",fixedSizeInScreen));
274    transform_4.get()->addChild(addDraggerToScene(geode_4.get(),"TrackballDragger",fixedSizeInScreen));
275    transform_5.get()->addChild(addDraggerToScene(geode_5.get(),"Translate1DDragger",fixedSizeInScreen));
276    transform_6.get()->addChild(addDraggerToScene(geode_6.get(),"Translate2DDragger",fixedSizeInScreen));
277    transform_7.get()->addChild(addDraggerToScene(geode_7.get(),"TranslateAxisDragger",fixedSizeInScreen));
278
279    root->addChild(transform_1.get());
280    root->addChild(transform_2.get());
281    root->addChild(transform_3.get());
282    root->addChild(transform_4.get());
283    root->addChild(transform_5.get());
284    root->addChild(transform_6.get());
285    root->addChild(transform_7.get());
286
287 
288 
289    return root;
290}
291//
292int main( int argc, char **argv )
293{
294
295    // use an ArgumentParser object to manage the program arguments.
296    osg::ArgumentParser arguments(&argc,argv);
297   
298    // set up the usage document, in case we need to print out how to use this program.
299    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
300    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
301    arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad");
302    arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField");
303    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display command line parameters");
304    arguments.getApplicationUsage()->addCommandLineOption("--help-env","Display environmental variables available");
305    arguments.getApplicationUsage()->addCommandLineOption("--help-keys","Display keyboard & mouse bindings available");
306    arguments.getApplicationUsage()->addCommandLineOption("--help-all","Display all command line, env vars and keyboard & mouse bindings.");
307
308    arguments.getApplicationUsage()->addCommandLineOption("--dragger <draggername>","Use the specified dragger for manipulation [TabPlaneDragger,TabPlaneTrackballDragger,TrackballDragger,Translate1DDragger,Translate2DDragger,TranslateAxisDragger,TabBoxDragger]");
309    arguments.getApplicationUsage()->addCommandLineOption("--fixedDraggerSize","Fix the size of the dragger geometry in the screen space");
310   
311    bool fixedSizeInScreen = false;
312    while (arguments.read("--fixedDraggerSize")) { fixedSizeInScreen = true; }
313
314    // construct the viewer.
315    osgViewer::Viewer viewer;
316
317    // get details on keyboard and mouse bindings used by the viewer.
318    viewer.getUsage(*arguments.getApplicationUsage());
319
320    // if user request help write it out to cout.
321    bool helpAll = arguments.read("--help-all");
322    unsigned int helpType = ((helpAll || arguments.read("-h") || arguments.read("--help"))? osg::ApplicationUsage::COMMAND_LINE_OPTION : 0 ) |
323                            ((helpAll ||  arguments.read("--help-env"))? osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE : 0 ) |
324                            ((helpAll ||  arguments.read("--help-keys"))? osg::ApplicationUsage::KEYBOARD_MOUSE_BINDING : 0 );
325    if (helpType)
326    {
327        arguments.getApplicationUsage()->write(std::cout, helpType);
328        return 1;
329    }
330
331    // report any errors if they have occurred when parsing the program arguments.
332    if (arguments.errors())
333    {
334        arguments.writeErrorMessages(std::cout);
335        return 1;
336    }
337
338    std::string dragger_name = "TabBoxDragger";
339    arguments.read("--dragger", dragger_name);
340
341    osg::Timer_t start_tick = osg::Timer::instance()->tick();
342
343    // read the scene from the list of file specified command line args.
344    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
345
346    // if no model has been successfully loaded report failure.
347    bool tragger2Scene(true);
348    if (!loadedModel)
349    {
350        //std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
351        //return 1;
352        loadedModel = createDemoScene(fixedSizeInScreen);
353        tragger2Scene=false;
354    }
355
356    // any option left unread are converted into errors to write out later.
357    arguments.reportRemainingOptionsAsUnrecognized();
358
359    // report any errors if they have occurred when parsing the program arguments.
360    if (arguments.errors())
361    {
362        arguments.writeErrorMessages(std::cout);
363    }
364
365    osg::Timer_t end_tick = osg::Timer::instance()->tick();
366
367    std::cout << "Time to load = "<<osg::Timer::instance()->delta_s(start_tick,end_tick)<<std::endl;
368
369
370    // optimize the scene graph, remove redundant nodes and state etc.
371    osgUtil::Optimizer optimizer;
372    optimizer.optimize(loadedModel.get());
373
374   
375    // pass the loaded scene graph to the viewer.
376    if ( tragger2Scene ) {
377        viewer.setSceneData(addDraggerToScene(loadedModel.get(), dragger_name, fixedSizeInScreen));
378    } else {
379        viewer.setSceneData(loadedModel.get());
380    }
381
382
383    return viewer.run();
384}
Note: See TracBrowser for help on using the browser.