OSGWidget.cpp 17 KB

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