Created
December 13, 2016 15:34
-
-
Save vicrucann/95ed58a08a46791fbc379dd363a4c1e2 to your computer and use it in GitHub Desktop.
OpeneSceneGraph: using ray casting to perform drawing on 3D virtual plane
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Canvas.h" | |
entity::Canvas::Canvas() | |
: osg::Group() | |
, m_transform(new osg::MatrixTransform) | |
, m_switch(new osg::Switch) | |
, m_frameGeode(new osg::Geode) | |
, m_frameGeometry(new osg::Geometry) | |
, m_dataGeode(new osg::Geode) | |
, m_center(osg::Vec3(0,0,0)) | |
, m_normal(osg::Vec3(0,-1,0)) | |
{ | |
osg::Vec3Array* vertices = new osg::Vec3Array; | |
vertices->push_back( osg::Vec3(1.0f, 0.0f, 1.0f) ); | |
vertices->push_back( osg::Vec3(-1.0f, 0.0f, 1.0f) ); | |
vertices->push_back( osg::Vec3(-1.0f, 0.0f, -1.f) ); | |
vertices->push_back( osg::Vec3(1.0f, 0.0f, -1.0f) ); | |
osg::Vec4Array* colors = new osg::Vec4Array; | |
colors->push_back( osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); | |
colors->push_back( osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); | |
colors->push_back( osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); | |
colors->push_back( osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); | |
this->addChild(m_transform.get()); | |
m_transform->addChild(m_switch.get()); | |
m_switch->addChild(m_frameGeode.get(), true); | |
m_frameGeode->addDrawable(m_frameGeometry.get()); | |
m_switch->addChild(m_dataGeode.get()); | |
m_frameGeometry->setVertexArray(vertices); | |
m_frameGeometry->setColorArray(colors); | |
m_frameGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); | |
m_frameGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,4)); | |
m_frameGeometry->dirtyDisplayList(); | |
m_frameGeometry->dirtyBound(); | |
} | |
void entity::Canvas::addStroke(Stroke *stroke) | |
{ | |
m_dataGeode->addChild(stroke); | |
} | |
const entity::Stroke *entity::Canvas::getStroke(unsigned int i) const | |
{ | |
return dynamic_cast<Stroke*>(m_dataGeode->getChild(i)); | |
} | |
void entity::Canvas::doStroke(float u, float v, int mouse) | |
{ | |
if (mouse == 0){ | |
m_stroke = new entity::Stroke; | |
m_stroke->setBegin(u,v); | |
m_dataGeode->addDrawable(m_stroke); | |
} | |
m_stroke->setEnd(u, v); | |
if (mouse == 2) | |
m_stroke = 0; | |
} | |
const osg::Vec3 &entity::Canvas::getCenter() const | |
{ | |
return m_center; | |
} | |
osg::Plane entity::Canvas::getPlane() const | |
{ | |
osg::Plane plane(m_normal, m_center); | |
return plane; | |
} | |
osg::MatrixTransform *entity::Canvas::getTransform() const | |
{ | |
return m_transform.get(); | |
} | |
entity::Canvas::~Canvas() | |
{ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CANVAS_H | |
#define CANVAS_H | |
#include <osg/ref_ptr> | |
#include <osg/Group> | |
#include <osg/Switch> | |
#include <osg/Geode> | |
#include <osg/Geometry> | |
#include <osg/MatrixTransform> | |
#include "Stroke.h" | |
namespace entity | |
{ | |
class Canvas : public osg::Group | |
{ | |
public: | |
Canvas(); | |
void addStroke(Stroke* stroke); | |
const Stroke* getStroke(unsigned int i) const; | |
void doStroke(float u, float v, int mouse); | |
const osg::Vec3& getCenter() const; | |
osg::Plane getPlane() const; | |
osg::MatrixTransform* getTransform() const; | |
protected: | |
~Canvas(); | |
private: | |
osg::ref_ptr<osg::MatrixTransform> m_transform; | |
osg::ref_ptr<osg::Switch> m_switch; | |
osg::ref_ptr<osg::Geode> m_frameGeode; | |
osg::ref_ptr<osg::Geometry> m_frameGeometry; | |
osg::ref_ptr<osg::Geode> m_dataGeode; | |
osg::ref_ptr<entity::Stroke> m_stroke; | |
osg::Vec3 m_center; | |
osg::Vec3 m_normal; | |
}; | |
} | |
#endif // CANVAS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 2.8.11) | |
project(osg-raycast) | |
set(CMAKE_INCLUDE_CURRENT_DIR ON) | |
find_package(OpenSceneGraph REQUIRED COMPONENTS osgDB osgGA osgUtil osgViewer) | |
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) | |
set(SOURCES | |
osg-raycast.cpp | |
Canvas.h | |
Canvas.cpp | |
Stroke.h | |
Stroke.cpp | |
EventHandler.h | |
EventHandler.cpp | |
) | |
add_executable(${PROJECT_NAME} ${SOURCES}) | |
target_link_libraries(${PROJECT_NAME} | |
${OPENSCENEGRAPH_LIBRARIES} | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "EventHandler.h" | |
#include <iostream> | |
#include "vector" | |
#include <osgViewer/View> | |
#include <osg/Plane> | |
EventHandler::EventHandler(entity::Canvas *canvas) | |
: osgGA::GUIEventHandler() | |
, m_canvas(canvas) | |
{ | |
} | |
bool EventHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) | |
{ | |
if (!( (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButtonMask()== osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) | |
|| (ea.getEventType() == osgGA::GUIEventAdapter::DRAG && ea.getButtonMask()== osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) | |
|| (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton()==osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) | |
)) | |
return false; | |
double u=0, v=0; | |
switch (ea.getEventType()){ | |
case osgGA::GUIEventAdapter::PUSH: | |
if (this->getRaytraceCanvasIntersection(ea,aa,u,v)) | |
this->doStroke(u, v, 0); | |
break; | |
case osgGA::GUIEventAdapter::RELEASE: | |
if (this->getRaytraceCanvasIntersection(ea,aa,u,v)) | |
this->doStroke(u, v, 2); | |
break; | |
case osgGA::GUIEventAdapter::DRAG: | |
if (this->getRaytraceCanvasIntersection(ea,aa,u,v)) | |
this->doStroke(u, v, 1); | |
break; | |
default: | |
break; | |
} | |
return true; | |
} | |
void EventHandler::doStroke(double u, double v, int mouse) | |
{ | |
m_canvas->doStroke(u, v, mouse); | |
} | |
bool EventHandler::getRaytraceCanvasIntersection(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, double &u, double &v) | |
{ | |
double x = ea.getX(); | |
double y = ea.getY(); | |
osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa); | |
if (!viewer){ | |
std::cerr << "getRaytraceCanvasIntersection(): could not read viewer" << std::endl; | |
return false; | |
} | |
osg::Camera* camera = viewer->getCamera(); | |
if (!camera){ | |
std::cout << "getRaytraceCanvasIntersection(): could not read camera" << std::endl; | |
return false; | |
} | |
if (!camera->getViewport()){ | |
std::cerr << "getRaytraceIntersection(): could not read viewport" << std::endl; | |
return false; | |
} | |
osg::Matrix VPW = camera->getViewMatrix() | |
* camera->getProjectionMatrix() | |
* camera->getViewport()->computeWindowMatrix(); | |
osg::Matrix invVPW; | |
if (!invVPW.invert(VPW)){ | |
std::cerr << "getRaytraceIntersection(): could not invert View-projection-world matrix for ray casting" << std::endl; | |
return false; | |
} | |
/* Algorithm: | |
* Calcualte near and far point in global 3D. | |
* Intersect that segment with plane of canvas - 3D intersection point. | |
* Extract local 3D coords so that to create a stroke. | |
*/ | |
osg::Vec3f nearPoint = osg::Vec3f(x, y, 0.f) * invVPW; | |
osg::Vec3f farPoint = osg::Vec3f(x, y, 1.f) * invVPW; | |
const osg::Plane plane = m_canvas->getPlane(); | |
const osg::Vec3f center = m_canvas->getCenter(); | |
std::vector<osg::Vec3f> ray(2); | |
ray[0] = nearPoint; | |
ray[1] = farPoint; | |
if (plane.intersect(ray)){ // 1 or -1: no intersection | |
std::cerr << "getRaytraceIntersection(): no intersection with the ray." << std::endl; | |
return false; | |
} | |
osg::Vec3f dir = farPoint-nearPoint; | |
if (! plane.dotProductNormal(dir)){ // denominator | |
std::cerr << "getRaytraceIntersection(): projected line is parallel to the canvas plane" << std::endl; | |
return false; | |
} | |
if (! plane.dotProductNormal(center-nearPoint)){ | |
std::cerr << "getRaytraceIntersection(): plane contains the line, so no single intersection can be defined" << std::endl; | |
return false; | |
} | |
double len = plane.dotProductNormal(center-nearPoint) / plane.dotProductNormal(dir); | |
osg::Vec3f P = dir * len + nearPoint; // global 3D intersection | |
osg::Matrix M = m_canvas->getTransform()->getMatrix(); | |
osg::Matrix invM; | |
if (!invM.invert(M)){ | |
std::cerr << "getRaytraceIntersection(): could not invert model matrix" << std::endl; | |
return false; | |
} | |
osg::Vec3f p = P * invM; // local intersection | |
u=p.x(); | |
v=p.z(); | |
return true; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef EVENTHANDLER_H | |
#define EVENTHANDLER_H | |
#include <osg/observer_ptr> | |
#include <osgGA/GUIEventHandler> | |
#include <osgGA/GUIActionAdapter> | |
#include <osgGA/GUIEventAdapter> | |
#include "Canvas.h" | |
class EventHandler : public osgGA::GUIEventHandler | |
{ | |
public: | |
EventHandler(entity::Canvas* canvas); | |
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa); | |
virtual void doStroke(double u, double v, int mouse); | |
protected: | |
bool getRaytraceCanvasIntersection(const osgGA::GUIEventAdapter& ea, | |
osgGA::GUIActionAdapter& aa, | |
double& u, double& v); | |
private: | |
osg::observer_ptr<entity::Canvas> m_canvas; | |
}; | |
#endif // EVENTHANDLER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ===================================================================================== | |
* | |
* Filename: osg-raycast.cpp | |
* | |
* Description: | |
* | |
* Version: 1.0 | |
* Created: 01/12/2016 07:50:06 PM | |
* Revision: none | |
* Compiler: gcc | |
* | |
* Author: Victoria Rudakova, [email protected] | |
* Organization: vicrucann.github.io | |
* | |
* ===================================================================================== | |
*/ | |
#include <iostream> | |
#include <windows.h> | |
#include <osg/ref_ptr> | |
#include <osgViewer/Viewer> | |
#include "Canvas.h" | |
#include "Stroke.h" | |
#include "EventHandler.h" | |
int main(int, char**){ | |
::SetProcessDPIAware(); | |
osg::ref_ptr<entity::Canvas> canvas = new entity::Canvas; | |
osg::ref_ptr<EventHandler> EH = new EventHandler(canvas.get()); | |
osgViewer::Viewer viewer; | |
viewer.setSceneData(canvas.get()); | |
viewer.addEventHandler(EH.get()); | |
viewer.setUpViewInWindow(100,100,300,300); | |
osg::Camera* cam = viewer.getCamera(); | |
cam->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 0.f)); | |
cam->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
osg::StateSet* stateset = canvas->getOrCreateStateSet(); | |
stateset->setMode(GL_LINE_SMOOTH, osg::StateAttribute::ON); | |
stateset->setMode(GL_BLEND, osg::StateAttribute::ON); | |
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); | |
return viewer.run(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Stroke.h" | |
entity::Stroke::Stroke() | |
: osg::Geometry() | |
{ | |
osg::Vec3Array* vertices = new osg::Vec3Array; | |
vertices->push_back(osg::Vec3(0,0,0)); | |
vertices->push_back(osg::Vec3(0.5,0,0.5)); | |
osg::Vec4 color = osg::Vec4(1,0,0,1); | |
osg::Vec4Array* colors = new osg::Vec4Array; | |
colors->push_back(color); | |
colors->push_back(color); | |
this->setVertexArray(vertices); | |
this->setColorArray(colors); | |
this->setColorBinding(osg::Geometry::BIND_OVERALL); | |
this->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, 2)); | |
this->setDataVariance(osg::Object::DYNAMIC); | |
this->setUseDisplayList(false); | |
this->setUseVertexBufferObjects(true); | |
} | |
void entity::Stroke::setColor(const osg::Vec4 &c) | |
{ | |
osg::Vec4Array* colors = static_cast<osg::Vec4Array*>(this->getColorArray()); | |
colors->front() = c; | |
colors->dirty(); | |
} | |
void entity::Stroke::setBegin(float a, float b) | |
{ | |
osg::Vec3Array* verts = static_cast<osg::Vec3Array*>(this->getVertexArray()); | |
(*verts)[0] = osg::Vec3(a,0,b); | |
verts->dirty(); | |
} | |
void entity::Stroke::setEnd(float c, float d) | |
{ | |
osg::Vec3Array* verts = static_cast<osg::Vec3Array*>(this->getVertexArray()); | |
(*verts)[1] = osg::Vec3(c,0,d); | |
verts->dirty(); | |
} | |
void entity::Stroke::setBeginEnd(float a, float b, float c, float d) | |
{ | |
osg::Vec3Array* verts = static_cast<osg::Vec3Array*>(this->getVertexArray()); | |
if (verts->size() == 0) { | |
verts->push_back(osg::Vec3(a,0,b)); | |
verts->push_back(osg::Vec3(c,0,d)); | |
} | |
else { | |
(*verts)[0] = osg::Vec3(a,0,b); | |
(*verts)[1] = osg::Vec3(c,0,d); | |
} | |
verts->dirty(); | |
} | |
entity::Stroke::~Stroke() | |
{ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef STROKE_H | |
#define STROKE_H | |
#include <osg/Geometry> | |
namespace entity{ | |
class Stroke : public osg::Geometry | |
{ | |
public: | |
Stroke(); | |
void setColor(const osg::Vec4& c); | |
void setBegin(float a, float b); | |
void setEnd(float c, float d); | |
void setBeginEnd(float a, float b, float c, float d); | |
protected: | |
~Stroke(); | |
}; // class | |
} // namespace | |
#endif // STROKE_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment