1 /* OpenSceneGraph example, osgpick.*/
2
3 /* osgpick sample
4 * demonstrate use of osgUtil/PickVisitor for picking in a HUD or
5 * in a 3d scene,
6 */
7
8 #include <osgUtil/Optimizer>
9 #include <osgDB/ReadFile>
10 #include <osgViewer/Viewer>
11 #include <osgViewer/CompositeViewer>
12
13 #include <osgGA/TerrainManipulator>
14 #include <osgGA/StateSetManipulator>
15 #include <osgGA/AnimationPathManipulator>
16 #include <osgGA/TrackballManipulator>
17 #include <osgGA/FlightManipulator>
18 #include <osgGA/DriveManipulator>
19 #include <osgGA/KeySwitchMatrixManipulator>
20 #include <osgGA/StateSetManipulator>
21 #include <osgGA/AnimationPathManipulator>
22 #include <osgGA/TerrainManipulator>
23
24 #include <osg/Material>
25 #include <osg/Geode>
26 #include <osg/BlendFunc>
27 #include <osg/Depth>
28 #include <osg/Projection>
29 #include <osg/MatrixTransform>
30 #include <osg/Camera>
31 #include <osg/io_utils>
32 #include <osg/ShapeDrawable>
33
34 #include <osgText/Text>
35
36 #include <sstream>
37
38 // 处理拾取事件的类,继承自osgGA::GUIEventhandler 界面事件处理
39 class PickHandler : public osgGA::GUIEventHandler {
40 public:
41 //构造函数
42 PickHandler(osgText::Text* updateText):
43 _updateText(updateText) {}
44 //析构函数
45 ~PickHandler() {}
46 //处理(事件接口、动作接口)
47 bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa);
48 //拾取(视图、事件接口)
49 virtual void pick(osgViewer::View* view, const osgGA::GUIEventAdapter& ea);
50 //设置显示内容
51 void setLabel(const std::string& name)
52 {
53 if (_updateText.get())
54 _updateText->setText(name);
55 }
56
57 protected:
58 //传递一个文字对象
59 osg::ref_ptr<osgText::Text> _updateText;
60 };
61 //事件处理(事件接口、动作接口)
62 bool PickHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
63 {
64 switch(ea.getEventType())
65 {
66 case(osgGA::GUIEventAdapter::PUSH):
67 {
68 //dynamic_cast运算符的作用是将&aa转换成osgViewer::View*类型的对象
69 osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
70 if (view) pick(view,ea);
71 return false;
72 }
73 case(osgGA::GUIEventAdapter::KEYDOWN):
74 {
75 if (ea.getKey()=='c')
76 {
77 osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
78 //event也是一个指针,类型是osgGA::GUIEventAdapter
79 osg::ref_ptr<osgGA::GUIEventAdapter> event = new osgGA::GUIEventAdapter(ea);
80 event->setX((ea.getXmin()+ea.getXmax())*0.5);
81 event->setY((ea.getYmin()+ea.getYmax())*0.5);
82 if (view) pick(view,*event);
83 }
84 return false;
85 }
86 default:
87 return false;
88 }
89 }
90
91 //拾取(视图、事件接口)通过view计算交点 ,从事件接口ea中获得 x和y
92 void PickHandler::pick(osgViewer::View* view, const osgGA::GUIEventAdapter& ea)
93 {
94 //创建一个线段交集检测对象
95 osgUtil::LineSegmentIntersector::Intersections intersections;
96
97 std::string gdlist="";
98 //得到鼠标的位置 x和y
99 float x = ea.getX();
100 float y = ea.getY();
101
102 //如果发生交集运算 (即鼠标点中了物体)
103 if (view->computeIntersections(x,y,intersections))
104 {
105 //得到相交交集的交点, hitr是一个迭代器
106 for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();
107 hitr != intersections.end();
108 ++hitr)
109 {
110 std::ostringstream os;//申请一个流
111 if (!hitr->nodePath.empty() && !(hitr->nodePath.back()->getName().empty()))
112 {
113 // the geodes are identified by name.
114 os<<"Object \""<<hitr->nodePath.back()->getName()<<"\""<<std::endl;
115 }
116 else if (hitr->drawable.valid())
117 {
118 os<<"Object \""<<hitr->drawable->className()<<"\""<<std::endl;
119 }
120 //将局部坐标顶点和法线输入到os这个流里面。
121 os<<" local coords vertex("<< hitr->getLocalIntersectPoint()<<")"<<" normal("<<hitr->getLocalIntersectNormal()<<")"<<std::endl;
122 os<<" world coords vertex("<< hitr->getWorldIntersectPoint()<<")"<<" normal("<<hitr->getWorldIntersectNormal()<<")"<<std::endl;
123 //交点索引列表vil,交点存在hitr里面
124 const osgUtil::LineSegmentIntersector::Intersection::IndexList& vil = hitr->indexList;
125 for(unsigned int i=0;i<vil.size();++i)
126 {
127 os<<" vertex indices ["<<i<<"] = "<<vil[i]<<std::endl;
128 }
129 //gdlist是一个字符串,用来存os中要显示的文字
130 gdlist += os.str();
131 }
132 }
133 //设置显示内容
134 setLabel(gdlist);
135 }
136 //创建HUD 参数是osgText。HUD也是作为场景中的一个节点存在
137 osg::Node* createHUD(osgText::Text* updateText)
138 {
139
140 // create the hud. derived from osgHud.cpp (derived:来源于)
141 // adds a set of quads, each in a separate Geode - which can be picked individually
142 // eg to be used as a menuing/help system!
143 // Can pick texts too!
144
145 osg::Camera* hudCamera = new osg::Camera;//创建一个相机
146 hudCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);//设置绝对帧引用
147 hudCamera->setProjectionMatrixAsOrtho2D(0,1280,0,1024);//设置正投影矩阵
148 hudCamera->setViewMatrix(osg::Matrix::identity());//设置视图矩阵
149 hudCamera->setRenderOrder(osg::Camera::POST_RENDER);//设置渲染顺序为POST
150 hudCamera->setClearMask(GL_DEPTH_BUFFER_BIT);//清除深度缓存
151
152 //设置字体,声明一个timesFont,初始化为times.ttf
153 std::string timesFont("fonts/times.ttf");
154
155 //关掉字体的光照、禁用深度缓存 来保证字体一直在最上面
156
157 osg::Vec3 position(150.0f,800.0f,0.0f);//设置位置
158 osg::Vec3 delta(0.0f,-60.0f,0.0f);
159
160 {
161 osg::Geode* geode = new osg::Geode();//也可以写成osg::ref_ptr<osg::Geode> geode = new osg::Geode();-------geode就是一个指针
162 osg::StateSet* stateset = geode->getOrCreateStateSet();//状态设置
163 stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);//关闭光照
164 stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);//关闭深度缓存
165 geode->setName("simple");//设置这个geode的名字,geode是场景中的叶子节点
166 hudCamera->addChild(geode);
167
168 osgText::Text* text = new osgText::Text;
169 geode->addDrawable( text );//geode是osg场景中的叶子节点,然后就是让所有drawable的东西成组
170
171 text->setFont(timesFont);//设置字体
172 text->setText("Picking in Head Up Displays is simple!\nHow to do it?\nAm I on the first quard?");//设置内容
173 text->setPosition(position);//设置字体位置,用到上面申明的position
174
175 position += delta;
176 }
177
178
179 for (int i=0; i<6; i++) {
180 osg::Vec3 dy(0.0f,-30.0f,0.0f);
181 osg::Vec3 dx(120.0f,0.0f,0.0f);
182 osg::Geode* geode = new osg::Geode();
183 osg::StateSet* stateset = geode->getOrCreateStateSet();
184 const char *opts[]={"One", "Two", "Three", "January", "Feb", "2003"};
185 osg::Geometry *quad=new osg::Geometry;//申明一个指向几何体的指针
186 stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
187 stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
188 std::string name="subOption";
189 name += " ";
190 name += std::string(opts[i]);
191 geode->setName(name);//设置节点的名字
192 osg::Vec3Array* vertices = new osg::Vec3Array(4); // 1 quad,弄个3元数组指针,数组有4个元素,分别保存矩形的4个顶点
193 osg::Vec4Array* colors = new osg::Vec4Array;//4元数组指针 ,保存颜色
194 colors = new osg::Vec4Array;
195 colors->push_back(osg::Vec4(0.8-0.1*i, 0.1*i, 0.2*i, 1.0));//通过i的变化来实现块的渐变颜色
196 quad->setColorArray(colors);
197 quad->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE);//绑定颜色到方块上
198 (*vertices)[0]=position;
199 (*vertices)[1]=position+dx;
200 (*vertices)[2]=position+dx+dy;
201 (*vertices)[3]=position+dy;
202 quad->setVertexArray(vertices);//设置顶点数组
203 quad->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
204 geode->addDrawable(quad);
205 hudCamera->addChild(geode);
206
207 position += delta;
208 }
209
210
211
212 {
213 //这里显示什么被选中
214 osg::Geode* geode = new osg::Geode();
215 osg::StateSet* stateset = geode->getOrCreateStateSet();
216 stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
217 stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
218 geode->setName("The text label");
219 geode->addDrawable( updateText );//这里的updateText是createHUD函数的传入参数
220 hudCamera->addChild(geode);
221
222 updateText->setCharacterSize(20.0f);
223 updateText->setFont(timesFont);
224 updateText->setColor(osg::Vec4(1.0f,1.0f,0.0f,1.0f));
225 updateText->setText("");
226 updateText->setPosition(position);
227 updateText->setDataVariance(osg::Object::DYNAMIC);
228
229 position += delta;
230 }
231
232 return hudCamera;
233
234 }
235
236
237 //主函数
238 int main( int argc, char **argv )
239 {
240 //使用一个参数解析器对象来管理程序的参数
241 osg::ArgumentParser arguments(&argc,argv);
242
243 //从命令行参数指定的文件列表中读取场景
244 osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles(arguments);
245 //如果场景没有创建成功
246 if (!scene && arguments.read("--relative-camera-scene"))
247 {
248 //创建一个带有相关引用帧的相机的测试场景
249 osg::Group* group = new osg::Group();
250
251 osg::Geode* sphere = new osg::Geode();//创建一个球
252 sphere->setName("Sphere");
253 sphere->addDrawable(new osg::ShapeDrawable(new osg::Sphere()));
254
255 osg::Geode* cube = new osg::Geode();//创建一个盒子
256 cube->setName("Cube");
257 cube->addDrawable(new osg::ShapeDrawable(new osg::Box()));
258
259 osg::Camera* camera = new osg::Camera();//创建一个相机
260 camera->setRenderOrder(osg::Camera::POST_RENDER);//设置渲染顺序为POST
261 camera->setClearMask(GL_DEPTH_BUFFER_BIT);//清除深度缓存
262 camera->setReferenceFrame(osg::Transform::RELATIVE_RF);//设置相对帧引用
263 camera->setViewMatrix(osg::Matrix::translate(-2, 0, 0));//设置视图矩阵
264
265 osg::MatrixTransform* xform = new osg::MatrixTransform(osg::Matrix::translate(1, 1, 1));
266 xform->addChild(camera);
267
268 group->addChild(sphere);
269 group->addChild(xform);
270 camera->addChild(cube);
271
272 scene = group;
273 }
274
275 //如果没有载入假设的场景,没有参数传进来。试着使用默认的模型代替。
276 if (!scene) scene = osgDB::readNodeFile("fountain.osgt");
277
278 osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(scene.get());
279 if (!group)
280 {
281 group = new osg::Group;
282 group->addChild(scene.get());
283 }
284
285 osg::ref_ptr<osgText::Text> updateText = new osgText::Text;
286
287 // add the HUD subgraph.
288 group->addChild(createHUD(updateText.get()));
289
290 if (arguments.read("--CompositeViewer"))
291 {
292 osg::ref_ptr<osgViewer::View> view = new osgViewer::View;
293 // 添加处理拾取事件的handler到视图中
294 view->addEventHandler(new PickHandler(updateText.get()));
295
296 // set the scene to render,设置场景到渲染中
297 view->setSceneData(group.get());
298
299 view->setUpViewAcrossAllScreens();
300
301 osgViewer::CompositeViewer viewer;
302 viewer.addView(view.get());
303
304 return viewer.run();
305
306 }
307 else
308 {
309 osgViewer::Viewer viewer;
310
311
312 // add all the camera manipulators
313 {
314 osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
315
316 keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
317 keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
318 keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
319
320 unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
321 keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
322
323 std::string pathfile;
324 char keyForAnimationPath = '5';
325 while (arguments.read("-p",pathfile))
326 {
327 osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
328 if (apm || !apm->valid())
329 {
330 num = keyswitchManipulator->getNumMatrixManipulators();
331 keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
332 ++keyForAnimationPath;
333 }
334 }
335
336 keyswitchManipulator->selectMatrixManipulator(num);
337
338 viewer.setCameraManipulator( keyswitchManipulator.get() );
339 }
340
341 // add the handler for doing the picking
342 viewer.addEventHandler(new PickHandler(updateText.get()));
343
344 // set the scene to render
345 viewer.setSceneData(group.get());
346
347 return viewer.run();
348 }
349
350 }