OSGWidget.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // Include own headers
  2. #include "OSGWidget.hpp"
  3. // Include modules
  4. #include "PickHandler.hpp"
  5. #include "TrackPointRenderer.hpp"
  6. #include "HudCallback.hpp"
  7. // Include dependencies
  8. #include <osgViewer/Viewer>
  9. #include <osg/ShapeDrawable>
  10. #include <osg/Geode>
  11. #include <osgDB/ReadFile>
  12. #include <osg/Group>
  13. #include <osg/Switch>
  14. #include <osg/MatrixTransform>
  15. #include <osg/Matrix>
  16. #include <osgGA/TrackballManipulator>
  17. #include <osgUtil/LineSegmentIntersector>
  18. #include <osgUtil/IntersectionVisitor>
  19. #include <osgUtil/MeshOptimizers>
  20. #include <osg/PolygonMode>
  21. #include <osgDB/WriteFile>
  22. #include <osg/Material>
  23. #include <osg/StateSet>
  24. #include <cassert>
  25. #include <stdexcept>
  26. #include <vector>
  27. #include <QDebug>
  28. #include <QKeyEvent>
  29. #include <QPainter>
  30. #include <QWheelEvent>
  31. namespace osgWidget {
  32. void Viewer::setupThreading() {
  33. if (_threadingModel == SingleThreaded) {
  34. if (_threadsRunning) {
  35. stopThreading();
  36. }
  37. } else {
  38. if (!_threadsRunning) {
  39. startThreading();
  40. }
  41. }
  42. }
  43. }
  44. void OSGWidget::fixMaterialState(osg::ref_ptr<osg::Node> node) {
  45. osg::StateSet* stateSet = node->getOrCreateStateSet();
  46. osg::Material* material = new osg::Material;
  47. material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
  48. stateSet->setAttributeAndModes(material, osg::StateAttribute::ON);
  49. stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
  50. }
  51. OSGWidget::OSGWidget(QWidget* parent): QOpenGLWidget(parent),
  52. graphicsWindow_(new osgViewer::GraphicsWindowEmbedded(this->x(), this->y(), this->width(), this->height())),
  53. _viewer(new osgWidget::Viewer),
  54. selectionActive_(false),
  55. selectionFinished_(true)
  56. {
  57. this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  58. // Root node of the scene
  59. _root = new osg::Group;
  60. // Create the camera
  61. float aspectRatio = static_cast<float>(this->width()) / static_cast<float>(this->height());
  62. auto pixelRatio = this->devicePixelRatio();
  63. osg::Camera* camera = new osg::Camera;
  64. camera->setViewport(0, 0, this->width() * pixelRatio, this->height() * pixelRatio);
  65. camera->setClearColor(osg::Vec4(0.2f, 0.1875f, 0.375f, 1.0f));
  66. camera->setProjectionMatrixAsPerspective(30.0f, aspectRatio, 1.0f, 1000.0f);
  67. camera->setGraphicsContext(graphicsWindow_);
  68. // Create the viewer
  69. _view = new osgViewer::View;
  70. _view->setCamera(camera);
  71. _view->setSceneData(_root);
  72. // Create coordinate axes
  73. _coordinateAxes = new osg::Group;
  74. osg::Vec4 axesColor = osg::Vec4(0.7f, 0.7f, 0.7f, 1.0f);
  75. osg::ref_ptr<osg::MatrixTransform> xRotation = new osg::MatrixTransform;
  76. xRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(1.0f, 0.0f, 0.0f)));
  77. osg::ref_ptr<osg::Geode> xAxis = new osg::Geode;
  78. osg::ref_ptr<osg::ShapeDrawable> xAxisShape = new osg::ShapeDrawable();
  79. xAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 0.05f, 100.0f));
  80. xAxisShape->setColor(axesColor);
  81. xAxis->addDrawable(xAxisShape.get());
  82. osg::ref_ptr<osg::ShapeDrawable> xConeShape = new osg::ShapeDrawable();
  83. xConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 50.0f), 0.2f, 1.0f));
  84. xConeShape->setColor(axesColor);
  85. xAxis->addDrawable(xConeShape.get());
  86. xRotation->addChild(xAxis.get());
  87. osg::ref_ptr<osg::MatrixTransform> yRotation = new osg::MatrixTransform;
  88. yRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(0.0f, 1.0f, 0.0f)));
  89. osg::ref_ptr<osg::Geode> yAxis = new osg::Geode;
  90. osg::ref_ptr<osg::ShapeDrawable> yAxisShape = new osg::ShapeDrawable();
  91. yAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 0.05f, 100.0f));
  92. yAxisShape->setColor(axesColor);
  93. yAxis->addDrawable(yAxisShape.get());
  94. osg::ref_ptr<osg::ShapeDrawable> yConeShape = new osg::ShapeDrawable();
  95. yConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 50.0f), 0.2f, 1.0f));
  96. yConeShape->setColor(axesColor);
  97. yAxis->addDrawable(yConeShape.get());
  98. yRotation->addChild(yAxis.get());
  99. osg::ref_ptr<osg::Geode> zAxis = new osg::Geode;
  100. osg::ref_ptr<osg::ShapeDrawable> zAxisShape = new osg::ShapeDrawable();
  101. zAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 0.05f, 100.0f));
  102. zAxisShape->setColor(axesColor);
  103. osg::ref_ptr<osg::ShapeDrawable> zConeShape = new osg::ShapeDrawable();
  104. zConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 50.0f), 0.2f, 1.0f));
  105. zConeShape->setColor(axesColor);
  106. zAxis->addDrawable(zConeShape.get());
  107. zAxis->addDrawable(zAxisShape.get());
  108. _coordinateAxes->addChild(xRotation.get());
  109. _coordinateAxes->addChild(yRotation.get());
  110. _coordinateAxes->addChild(zAxis.get());
  111. OSGWidget::fixMaterialState(_coordinateAxes);
  112. _root->addChild(_coordinateAxes);
  113. _mesh = new osg::Geode;
  114. // Add axes preview
  115. osg::ref_ptr<osg::Camera> hudCamera = new osg::Camera;
  116. int width = 1024;
  117. int height = 1024;
  118. hudCamera->setProjectionMatrixAsOrtho(0, width, 0, height, 1, 100);
  119. hudCamera->setRenderOrder(osg::Camera::POST_RENDER);
  120. hudCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
  121. hudCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
  122. osg::ref_ptr<osg::Group> axesPreview = createAxesPreview();
  123. osg::MatrixTransform* pTM = new osg::MatrixTransform;
  124. pTM->addChild(axesPreview.get());
  125. axesPreview->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
  126. pTM->setMatrix(osg::Matrix::scale(osg::Vec3(width/12, width/12, width/12)) * osg::Matrix::translate(osg::Vec3(width/20, width/20, 1)));
  127. pTM->setUpdateCallback(new HudCallback(camera));
  128. hudCamera->addChild(pTM);
  129. hudCamera->setViewMatrixAsLookAt(osg::Vec3(0, 0, 1), osg::Vec3(0, 0, 0), osg::Vec3(0, 1, 0)); // opengl default camera position
  130. _root->addChild(hudCamera.release());
  131. // Attach a manipulator (it's usually done for us when we use viewer.run())
  132. osg::ref_ptr<osgGA::TrackballManipulator> tm = new osgGA::TrackballManipulator;
  133. tm->setAllowThrow(false);
  134. _view->setCameraManipulator(tm);
  135. _viewer->addView(_view);
  136. _viewer->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
  137. _viewer->realize();
  138. _picker = new PickHandler(this, _root);
  139. _root->addChild(_picker->getPickerRoot());
  140. _view->addEventHandler(_picker);
  141. // This ensures that the widget will receive keyboard events. This focus
  142. // policy is not set by default. The default, Qt::NoFocus, will result in
  143. // keyboard events that are ignored.
  144. this->setFocusPolicy(Qt::StrongFocus);
  145. this->setMinimumSize(100, 100);
  146. // Ensures that the widget receives mouse move events even though no
  147. // mouse button has been pressed. We require this in order to let the
  148. // graphics window switch viewports properly.
  149. this->setMouseTracking(true);
  150. _pointRoot = new osg::Group;
  151. _root->addChild(_pointRoot.get());
  152. _pointRenderer = new TrackPointRenderer(this, _pointRoot);
  153. }
  154. OSGWidget::~OSGWidget() {
  155. }
  156. void OSGWidget::renderBaseMesh(const osg::ref_ptr<osg::Vec3Array> vertices, const osg::ref_ptr<osg::Vec3Array> normals) {
  157. _root->removeChild(_mesh);
  158. osg::ref_ptr<osg::Geometry> meshGeometry = new osg::Geometry;
  159. meshGeometry->setVertexArray(vertices.get());
  160. meshGeometry->setNormalArray(normals.get(), osg::Array::BIND_PER_VERTEX);
  161. meshGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertices->getNumElements()));
  162. osgUtil::optimizeMesh(meshGeometry.get());
  163. _mesh->addDrawable(meshGeometry.get());
  164. OSGWidget::fixMaterialState(_mesh);
  165. _root->addChild(_mesh);
  166. _picker->updateRenderer();
  167. }
  168. osg::ref_ptr<osg::Geode> OSGWidget::getMesh() {
  169. return _mesh;
  170. }
  171. PickHandler* OSGWidget::getPicker() {
  172. return _picker;
  173. }
  174. TrackPointRenderer* OSGWidget::getPointRenderer() {
  175. return _pointRenderer;
  176. }
  177. void OSGWidget::paintEvent(QPaintEvent*) {
  178. this->makeCurrent();
  179. QPainter painter(this);
  180. painter.setRenderHint(QPainter::Antialiasing);
  181. this->paintGL();
  182. painter.end();
  183. this->doneCurrent();
  184. }
  185. void OSGWidget::paintGL() {
  186. _viewer->frame();
  187. }
  188. void OSGWidget::resizeGL(int width, int height) {
  189. auto pixelRatio = this->devicePixelRatio();
  190. this->getEventQueue()->windowResize(this->x(), this->y(), width * pixelRatio, height * pixelRatio);
  191. graphicsWindow_->resized(this->x(), this->y(), width * pixelRatio, height * pixelRatio);
  192. this->onResize(width, height);
  193. }
  194. void OSGWidget::keyPressEvent(QKeyEvent* event) {
  195. QString keyString = event->text();
  196. const char* keyData = keyString.toLocal8Bit().data();
  197. if (event->key() == Qt::Key_H) {
  198. this->onHome();
  199. return;
  200. }
  201. this->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KeySymbol(*keyData));
  202. }
  203. void OSGWidget::keyReleaseEvent(QKeyEvent* event) {
  204. QString keyString = event->text();
  205. const char* keyData = keyString.toLocal8Bit().data();
  206. this->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KeySymbol(*keyData));
  207. }
  208. void OSGWidget::mouseMoveEvent(QMouseEvent* event) {
  209. auto pixelRatio = this->devicePixelRatio();
  210. this->getEventQueue()->mouseMotion(static_cast<float>(event->position().x() * pixelRatio), static_cast<float>(event->position().y() * pixelRatio));
  211. }
  212. void OSGWidget::mousePressEvent(QMouseEvent* event) {
  213. unsigned int button = 0;
  214. switch(event->button()) {
  215. case Qt::LeftButton:
  216. button = 1;
  217. break;
  218. case Qt::MiddleButton:
  219. button = 2;
  220. break;
  221. case Qt::RightButton:
  222. button = 3;
  223. break;
  224. default:
  225. break;
  226. }
  227. auto pixelRatio = this->devicePixelRatio();
  228. this->getEventQueue()->mouseButtonPress(static_cast<float>(event->position().x() * pixelRatio), static_cast<float>(event->position().y() * pixelRatio), button);
  229. }
  230. void OSGWidget::mouseReleaseEvent(QMouseEvent* event) {
  231. unsigned int button = 0;
  232. switch(event->button()) {
  233. case Qt::LeftButton:
  234. button = 1;
  235. break;
  236. case Qt::MiddleButton:
  237. button = 2;
  238. break;
  239. case Qt::RightButton:
  240. button = 3;
  241. break;
  242. default:
  243. break;
  244. }
  245. auto pixelRatio = this->devicePixelRatio();
  246. this->getEventQueue()->mouseButtonRelease(static_cast<float>(event->position().x() * pixelRatio), static_cast<float>(event->position().y() * pixelRatio), button);
  247. }
  248. void OSGWidget::wheelEvent(QWheelEvent* event) {
  249. event->accept();
  250. int delta = event->angleDelta().y();
  251. osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN;
  252. this->getEventQueue()->mouseScroll(motion);
  253. }
  254. bool OSGWidget::event(QEvent* event) {
  255. bool handled = QOpenGLWidget::event(event);
  256. // This ensures that the OSG widget is always going to be repainted after the
  257. // user performed some interaction. Doing this in the event handler ensures
  258. // that we don't forget about some event and prevents duplicate code.
  259. switch(event->type()) {
  260. case QEvent::KeyPress:
  261. case QEvent::KeyRelease:
  262. case QEvent::MouseButtonDblClick:
  263. case QEvent::MouseButtonPress:
  264. case QEvent::MouseButtonRelease:
  265. case QEvent::MouseMove:
  266. case QEvent::Wheel:
  267. this->update();
  268. break;
  269. case QEvent::Resize:
  270. this->onResize(this->width(), this->height());
  271. break;
  272. default:
  273. break;
  274. }
  275. return handled;
  276. }
  277. void OSGWidget::onHome() {
  278. osgViewer::ViewerBase::Views views;
  279. _viewer->getViews( views );
  280. for(std::size_t i = 0; i < views.size(); i++) {
  281. osgViewer::View* view = views.at(i);
  282. view->home();
  283. }
  284. }
  285. void OSGWidget::onResize(int width, int height) {
  286. std::vector<osg::Camera*> cameras;
  287. _viewer->getCameras(cameras);
  288. assert(cameras.size() == 1);
  289. auto pixelRatio = this->devicePixelRatio();
  290. cameras[0]->setViewport(0, 0, width * pixelRatio, height * pixelRatio);
  291. }
  292. osgGA::EventQueue* OSGWidget::getEventQueue() const {
  293. osgGA::EventQueue* eventQueue = graphicsWindow_->getEventQueue();
  294. if (eventQueue) {
  295. return eventQueue;
  296. } else {
  297. throw std::runtime_error("Unable to obtain valid event queue");
  298. }
  299. }
  300. osg::ref_ptr<osg::Group> OSGWidget::createAxesPreview() {
  301. osg::ref_ptr<osg::Group> axesPreview = new osg::Group;
  302. osg::Vec4 red = osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
  303. osg::Vec4 green = osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
  304. osg::Vec4 blue = osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
  305. osg::ref_ptr<osg::MatrixTransform> xRotation = new osg::MatrixTransform;
  306. xRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(1.0f, 0.0f, 0.0f)));
  307. osg::ref_ptr<osg::Geode> xAxis = new osg::Geode;
  308. osg::ref_ptr<osg::ShapeDrawable> xAxisShape = new osg::ShapeDrawable();
  309. xAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.5f), 0.01f, 1.0f));
  310. xAxisShape->setColor(red);
  311. xAxis->addDrawable(xAxisShape.get());
  312. osg::ref_ptr<osg::ShapeDrawable> xConeShape = new osg::ShapeDrawable();
  313. xConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 1.0f), 0.05f, 0.2f));
  314. xConeShape->setColor(red);
  315. xAxis->addDrawable(xConeShape.get());
  316. xRotation->addChild(xAxis.get());
  317. osg::ref_ptr<osg::MatrixTransform> yRotation = new osg::MatrixTransform;
  318. yRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(0.0f, 1.0f, 0.0f)));
  319. osg::ref_ptr<osg::Geode> yAxis = new osg::Geode;
  320. osg::ref_ptr<osg::ShapeDrawable> yAxisShape = new osg::ShapeDrawable();
  321. yAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.5f), 0.01f, 1.0f));
  322. yAxisShape->setColor(green);
  323. yAxis->addDrawable(yAxisShape.get());
  324. osg::ref_ptr<osg::ShapeDrawable> yConeShape = new osg::ShapeDrawable();
  325. yConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 1.0f), 0.05f, 0.2f));
  326. yConeShape->setColor(green);
  327. yAxis->addDrawable(yConeShape.get());
  328. yRotation->addChild(yAxis.get());
  329. osg::ref_ptr<osg::Geode> zAxis = new osg::Geode;
  330. osg::ref_ptr<osg::ShapeDrawable> zAxisShape = new osg::ShapeDrawable();
  331. zAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.5f), 0.01f, 1.0f));
  332. zAxisShape->setColor(blue);
  333. osg::ref_ptr<osg::ShapeDrawable> zConeShape = new osg::ShapeDrawable();
  334. zConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 1.0f), 0.05f, 0.2f));
  335. zConeShape->setColor(blue);
  336. zAxis->addDrawable(zConeShape.get());
  337. zAxis->addDrawable(zAxisShape.get());
  338. axesPreview->addChild(xRotation.get());
  339. axesPreview->addChild(yRotation.get());
  340. axesPreview->addChild(zAxis.get());
  341. OSGWidget::fixMaterialState(axesPreview);
  342. return axesPreview;
  343. }