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 }