osg--交互

本文介绍了如何在osg中实现自定义事件处理器,包括处理不同类型的事件,以及如何在视图中添加和移除事件处理器。此外,还详细讲解了物体相交的步骤,包括使用IntersectionVisitor进行相交检查和获取相交信息。最后,探讨了图形上下文的创建和使用。

自定义事件处理器

  • osgGA::GUIEventHandler 事件处理器/事件遍历器的回调
    • 重载
      • handle
        • 参数osgGA::GUIEventAdapter

          • getEventType

          在这里插入图片描述

          • getModKeyMask 返回MODKEY_CTRL/MODKEY_SHIFT/MODKEY_ALT
          • 注意:相应set方法不适合在handle中出现,用于osg底层显示系统向事件队列添加事件
        • 参数osgGA::GUIActionAdapter

          • osgViewer::Viewer* viewer = dynamic_castosgViewer::Viewer*(&aa);
  • 事件处理管理
    • addEventHandler
    • removeEventHandler
  • 步骤
    • 自定义事件处理器
    • viewer中加入自定义事件处理器
    • 取消viewer主相机控制器
      • viewer.getCamera()->setAllowEventFocus(false);
    • 设置viewer的ViewMatrix
      • viewer.getCamera()->setViewMatrixAsLookAt(osg::Vec3(0.0f,-100.0f,0.0f), osg::Vec3(), osg::Z_AXIS );

示例

#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventHandler>
#include <osgViewer/Viewer>

class ModelController : public osgGA::GUIEventHandler
{
public:
	ModelController(osg::MatrixTransform* node)
		: _model(node)
	{}
	virtual bool handle(const osgGA::GUIEventAdapter& ea,
		osgGA::GUIActionAdapter& aa);

protected:
	osg::ref_ptr<osg::MatrixTransform> _model;
};
bool ModelController::handle(const osgGA::GUIEventAdapter& ea,
	osgGA::GUIActionAdapter& aa)
{
	if (!_model) return false;
	osg::Matrix matrix = _model->getMatrix();

	switch (ea.getEventType())
	{
	case osgGA::GUIEventAdapter::KEYDOWN:
		switch (ea.getKey())
		{
		case 'a': case 'A':
			matrix *= osg::Matrix::rotate(-0.1f, osg::Z_AXIS);
			break;
		case 'd': case 'D':
			matrix *= osg::Matrix::rotate(0.1f, osg::Z_AXIS);
			break;
		case 'w': case 'W':
			matrix *= osg::Matrix::rotate(-0.1f, osg::X_AXIS);
			break;
		case 's': case 'S':
			matrix *= osg::Matrix::rotate(0.1f, osg::X_AXIS);
			break;
		default:break;
		}
		_model->setMatrix(matrix);
		break;
	default:
		break;
	}
	return false;
}
int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("cessna.osg");
	osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
	mt->addChild(model.get());
	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(mt.get());

	osg::ref_ptr<ModelController> ctrler =
		new ModelController(mt.get());
	osgViewer::Viewer viewer;
	viewer.addEventHandler(ctrler.get());
	viewer.getCamera()->setAllowEventFocus(false);
	viewer.getCamera()->setViewMatrixAsLookAt(
		osg::Vec3(0.0f, -100.0f, 0.0f), osg::Vec3(), osg::Z_AXIS);

	viewer.setSceneData(root.get());
	return viewer.run();
}

自定义事件

  • osgGA::EventQueue
    • addEvent
      • osgGA::GUIEventAdapter
        • setEventType
        • setButton
    • userEvent
      • 参数为osg::Referenced
  • 说明:每一个事件都将遍历事件处理器

示例

#include <osg/Switch>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventHandler>
#include <osgViewer/Viewer>
#include <iostream>

struct TimerInfo : public osg::Referenced
{
	TimerInfo(unsigned int c) : _count(c) {}
	unsigned int _count;
};
class TimerHandler : public osgGA::GUIEventHandler
{
public:
	TimerHandler(osg::Switch* sw) : _switch(sw), _count(0) {}
	virtual bool handle(const osgGA::GUIEventAdapter& ea,
		osgGA::GUIActionAdapter& aa);

protected:
	osg::ref_ptr<osg::Switch> _switch;
	unsigned int _count;
};
bool TimerHandler::handle(const osgGA::GUIEventAdapter& ea,
	osgGA::GUIActionAdapter& aa)
{
	switch (ea.getEventType())
	{
	case osgGA::GUIEventAdapter::FRAME:
		if (_count % 100 == 0)
		{
			osgViewer::Viewer* viewer =
				dynamic_cast<osgViewer::Viewer*>(&aa);
			if (viewer)
			{
				viewer->getEventQueue()->userEvent(
					new TimerInfo(_count));
			}
		}
		_count++;
		break;
	case osgGA::GUIEventAdapter::USER:
		if (_switch.valid())
		{
			const TimerInfo* ti =
				dynamic_cast<const TimerInfo*>(ea.getUserData()
					);
			std::cout << "Timer event at: " << ti->_count <<
				std::endl;

			_switch->setValue(0, !_switch->getValue(0));
			_switch->setValue(1, !_switch->getValue(1));
		}
		break;
	default:
		break;
	}
	return false;
}
int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile("cessna.osg");
	osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile("cessnafire.osg");
	osg::ref_ptr<osg::Switch> root = new osg::Switch;
	root->addChild(model1.get(), false);
	root->addChild(model2.get(), true);
	osgViewer::Viewer viewer;
	viewer.setSceneData(root.get());
	viewer.addEventHandler(new TimerHandler(root.get()));
	return viewer.run();
}

物体相交

  • osgUtil::IntersectionVisitor
    • 继承osg::NodeVisitor

    • 参数为osgUtil::Intersector

      在这里插入图片描述

步骤

  • 定义自定义事件处理器
    • 定义intersector
      • osg::ref_ptrosgUtil::LineSegmentIntersector intersector = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
    • 遍历
      • osgUtil::IntersectionVisitor iv( intersector.get() );
      • camera->accept( iv );
    • 检查相交
      • containsIntersections
    • 获取相交
      • getIntersections 由近到远
    • 获取相交点
      • getLocalIntersectPoint
      • getWorldIntersectPoint
    • 获取相交几何体及父节点
    • 获取相交三角组元索引

示例

#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/PolygonMode>
#include <osgDB/ReadFile>
#include <osgUtil/LineSegmentIntersector>
#include <osgViewer/Viewer>

class PickHandler : public osgGA::GUIEventHandler
{
public:
	osg::Node* getOrCreateSelectionBox();
	virtual bool handle(const osgGA::GUIEventAdapter& ea,
		osgGA::GUIActionAdapter& aa);

protected:
	osg::ref_ptr<osg::MatrixTransform> _selectionBox;
};
osg::Node* PickHandler::getOrCreateSelectionBox()
{
	if (!_selectionBox)
	{
		osg::ref_ptr<osg::Geode> geode = new osg::Geode;
		geode->addDrawable(
			new osg::ShapeDrawable(new osg::Box(osg::Vec3(),
				1.0f)));


		_selectionBox = new osg::MatrixTransform;
		_selectionBox->setNodeMask(0x1);
		_selectionBox->addChild(geode.get());


		osg::StateSet* ss = _selectionBox->getOrCreateStateSet();
		ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
		ss->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE));
	}
	return _selectionBox.get();
}
bool PickHandler::handle(const osgGA::GUIEventAdapter& ea,
	osgGA::GUIActionAdapter& aa)
{
	if (ea.getEventType() != osgGA::GUIEventAdapter::RELEASE || ea.getButton() != osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON
		||
		!(ea.getModKeyMask()&osgGA::GUIEventAdapter::MODKEY_CTRL)
		)
		return false;


	osgViewer::Viewer* viewer =
		dynamic_cast<osgViewer::Viewer*>(&aa);
	if (viewer)
	{
		osg::ref_ptr<osgUtil::LineSegmentIntersector>
			intersector =
			new osgUtil::LineSegmentIntersector(
				osgUtil::Intersector::WINDOW, ea.getX(), ea.getY()
			);
		osgUtil::IntersectionVisitor iv(intersector.get());
		iv.setTraversalMask(~0x1);
		viewer->getCamera()->accept(iv);

		if (intersector->containsIntersections())
		{
			osgUtil::LineSegmentIntersector::Intersection result = *(intersector->getIntersections().begin());
			osg::BoundingBox bb = result.drawable->getBoundingBox();
			osg::Vec3 worldCenter = bb.center() * osg::computeLocalToWorld(result.nodePath);
			_selectionBox->setMatrix(
				osg::Matrix::scale(bb.xMax() - bb.xMin(),
					bb.yMax() - bb.yMin(),
					bb.zMax() - bb.zMin()) *
				osg::Matrix::translate(worldCenter));
		}
	}
	return false;
}
int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile("cessna.osg");
	osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile("cow.osg");
	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(model1.get());
	root->addChild(model2.get());

	osg::ref_ptr<PickHandler> picker = new PickHandler;
	root->addChild(picker->getOrCreateSelectionBox());

	osgViewer::Viewer viewer;
	viewer.setSceneData(root.get());
	viewer.addEventHandler(picker.get());
	return viewer.run();
}

图形上下文

  • 形式
    • 相关的窗口API
    • 缓冲,比如opengl的像素缓冲
  • osg
    • osg::GraphicsContext
      • createGraphicsContext()

        • 参数为osg::GraphicsContext::Traits

        在这里插入图片描述

    • osgViewer::GraphicsWindow
      • getEventQueue() 处理GUI事件
  • 步骤
    • 创建traits
    • 创建graphics context
    • 附加到相机
    • 设置相机为主相机

示例

#include <osg/GraphicsContext>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>


int main(int argc, char** argv)
{
	osg::ref_ptr<osg::GraphicsContext::Traits> traits =
		new osg::GraphicsContext::Traits;
	traits->x = 50;
	traits->y = 50;
	traits->width = 800;
	traits->height = 600;
	traits->windowDecoration = true;
	traits->doubleBuffer = true;
	traits->samples = 4;

	osg::ref_ptr<osg::GraphicsContext> gc =
		osg::GraphicsContext::createGraphicsContext(traits.get());

	osg::ref_ptr<osg::Camera> camera = new osg::Camera;
	camera->setGraphicsContext(gc);
	camera->setViewport(
		new osg::Viewport(0, 0, traits->width, traits->height));
	camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	camera->setClearColor(osg::Vec4f(0.2f, 0.2f, 0.4f, 1.0f));
	camera->setProjectionMatrixAsPerspective(
		30.0f, (double)traits->width / (double)traits->height,
		1.0, 1000.0);

	osg::ref_ptr<osg::Node> root = osgDB::readNodeFile(
		"cessna.osg");

	osgViewer::Viewer viewer;
	viewer.setCamera(camera.get());
	viewer.setSceneData(root.get());
	return viewer.run();
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值