OSG三维场景中拾取鼠标在模型表面的点击点
创作时间:
作者:
@小白创作中心
OSG三维场景中拾取鼠标在模型表面的点击点
引用
1
来源
1.
https://www.cnblogs.com/herd/p/18555625
在三维图形编程中,鼠标拾取(Picking)是一个常见的需求,它允许用户通过鼠标点击来选择场景中的对象或位置。本文将详细介绍如何在OpenSceneGraph(OSG)中实现这一功能,具体来说,就是如何获取鼠标点击在模型表面的具体位置,并在该位置显示一个红色球体作为标记。
在OSG中实现鼠标拾取功能主要涉及以下几个关键步骤:
- 创建一个继承自
osgGA::GUIEventHandler的类,用于处理鼠标事件 - 在事件处理函数中获取鼠标点击位置
- 使用
osgUtil::LineSegmentIntersector进行射线相交检测 - 处理相交结果并在场景中显示标记
下面是完整的代码实现:
#include <osg/Group>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler>
#include <osgGA/TrackballManipulator>
#include <osg/Material>
#include <osg/StateSet>
#include <osgUtil/LineSegmentIntersector>
#include <osgUtil/IntersectVisitor>
#include <iostream>
class PickHandler : public osgGA::GUIEventHandler {
public:
PickHandler() {}
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
if (!view) return false;
// 检查是否为鼠标左键点击事件
if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) {
performPick(ea, *view);
return true;
}
return false;
}
osg::ref_ptr<osg::Geode> createRedSphere(const osg::Vec3f& position, float radius) {
// 创建一个球体形状
osg::ref_ptr<osg::Sphere> sphere = new osg::Sphere(position, radius);
// 创建一个形状绘制对象,并设置其颜色为红色
osg::ref_ptr<osg::ShapeDrawable> sphereDrawable = new osg::ShapeDrawable(sphere);
sphereDrawable->setColor(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); // 红色(RGBA)
// 创建一个地理节点(Geode),并将形状绘制对象添加到其中
osg::ref_ptr<osg::Geode> sphereGeode = new osg::Geode();
sphereGeode->addDrawable(sphereDrawable);
return sphereGeode;
}
private:
void performPick(const osgGA::GUIEventAdapter& ea, osgViewer::View& view) {
// 将鼠标位置转换为窗口坐标
int x = ea.getX();
int y = ea.getY();
// 执行相交检测
osgUtil::IntersectionVisitor iv;
osgUtil::LineSegmentIntersector::Intersections intersections;
// 执行相交检测
if (view.computeIntersections(x, y, intersections)) {
// 检查是否有相交点
if (!intersections.empty()) {
for (const auto& intersection : intersections) {
const osg::Vec3& point = intersection.getWorldIntersectPoint();
std::cout << "Intersection point: " << point.x() << " " << point.y() << " " << point.z() << std::endl;
osg::ref_ptr<osg::Geode> redSphere = createRedSphere(point, 10.1f); // 半径为1的红色球体
view.getSceneData()->asGroup()->addChild(redSphere);
break; // 只处理第一个相交点
}
}
else {
std::cout << "No intersection found." << std::endl;
}
}
else {
std::cout << "No intersection found." << std::endl;
}
}
};
int main(int argc, char** argv) {
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
// 加载场景 cow.osg excavator.OSGB library.OSGB
osg::Node* root = osgDB::readNodeFile("library.OSGB");
if (!root) {
std::cerr << "Error loading model" << std::endl;
return 1;
}
viewer->setSceneData(root);
// 添加鼠标拾取事件处理器
viewer->addEventHandler(new PickHandler());
// 开始运行
return viewer->run();
}
通过以上代码,你可以在OSG场景中实现基本的鼠标拾取功能。当用户在模型表面点击时,程序会计算出点击位置对应的三维坐标,并在该位置显示一个红色球体作为标记。这在许多三维应用中都是非常实用的功能,例如游戏开发、虚拟现实应用等。
热门推荐
解决洗衣机启动程序不灵的方法(如何处理洗衣机启动程序无法运行的问题)
中国足球后备力量培育与发展路径探索及未来前景分析
在怀孕前需要做哪些体检和咨询?
库车天山神秘大峡谷:新疆的自然奇观与人文瑰宝
碧水共治:党建引领排水治理新行动
“一身多病”的老年人,小心老年综合征找上门
上海世外系学校汇总及重点学校介绍
嬴政的49年:被迫做质子,13岁登基风光无限,晚年暴政成污点
清代奇书《姑妄言》及其作者曹去晶
隔夜冰箱啤酒还能喝吗?
认型传销模式:解析以公司为对象的传销行为及其法律责任
肝郁找上你全因压力大?4大汤水及花茶推介+穴位按摩,解决失眠抗压宁神
葛根粉饮酒前后食用效果大不同,医生建议这样做
近一半德国公司希望扩张到海外
如何制定股市投资策略?这些策略有哪些成功案例和失败教训?
打造完美睡眠,从调整生理时钟开始!
内容转发率怎么提升?什么样的内容,用户才会愿意帮你转发?
飞鸡:从小训练飞行的鸡能飞行吗?为什么野鸡能飞吗?是同一品种吗?今天自由思考
古代神话故事中的后羿射日:图像与形象的演变
生蛋比不过鸡,长肉比不过鸭,人类为啥还要驯服大鹅?
数据中心:驱动创新和我们的数字世界
道家哲学“三一”学说是什么?详解三清尊神的哲学意义
行政酒廊 哪些高端酒店是标配?
变更注册资本什么意思?变更注册资本会带来哪些影响?
用古诗词润泽学生心灵
吃太多酸性食物会导致骨质疏松?营养师教你正确补钙3要点
中医燥邪的辩证论治
如何缓解久坐引起的颈椎疼痛和头晕
2024年中国养老保险行业分析:制度模式与参保人数现状
注意力能训练吗?原来注意力分5种类!附4个方法提升注意力