在 OpenSceneGraph 中,要将屏幕坐标转换为当前场景坐标,并过滤出屏幕显示范围内的节点,可以通过以下步骤实现:
-
获取屏幕坐标: 当用户点击或交互时,获取鼠标点击的屏幕坐标。
-
转换屏幕坐标为世界坐标: 使用视图矩阵和投影矩阵将屏幕坐标转换为世界坐标。
-
进行节点遍历和过滤: 遍历场景中的节点,根据节点的世界坐标和屏幕空间边界进行筛选,以确定哪些节点位于屏幕范围内。
以下是一个基本示例代码,展示了如何在 OpenSceneGraph 中实现屏幕坐标到当前场景坐标的转换,并过滤出屏幕显示范围内的节点:
#include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler>
#include <osgUtil/LineSegmentIntersector>
#include <iostream>class PickHandler : public osgGA::GUIEventHandler {
public:virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH) {float x = ea.getX();float y = ea.getY();osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);if (view) {osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y);osgUtil::IntersectionVisitor iv(intersector.get());view->getCamera()->accept(iv);if (intersector->containsIntersections()) {for (auto& intersection : intersector->getIntersections()) {osg::NodePath& nodePath = intersection.nodePath;osg::Node* node = (nodePath.size() >= 1) ? nodePath.back() : nullptr;if (node && isNodeInViewport(view, node, intersection.getWorldIntersectPoint())) {std::cout << "Selected Node: " << node->getName() << std::endl;}}}}}return false;}bool isNodeInViewport(osgViewer::View* view, osg::Node* node, const osg::Vec3& worldPos) {osg::Vec3 screenPos;if (view->computeIntersections(worldPos, osg::Vec3(0, 0, -1), screenPos)) {osg::Viewport* viewport = view->getCamera()->getViewport();if (viewport) {return (screenPos.x() >= 0 && screenPos.x() <= viewport->width()) &&(screenPos.y() >= 0 && screenPos.y() <= viewport->height());}}return false;}
};int main() {osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("path/to/your/model.obj");osgViewer::Viewer viewer;viewer.setSceneData(loadedModel.get());viewer.addEventHandler(new PickHandler());return viewer.run();
}
isNodeInViewport
函数用于检查节点是否在当前视口范围内。它通过将世界坐标转换为屏幕坐标,并检查是否在视口内来判断节点是否在屏幕范围内。
这个有个容易犯错的问题,就是语言描述是计算机屏幕范围内,导致开发者想通过屏幕坐标去过滤,但是在空间没有物体进行碰撞检测的情况下,不好实现,所以逆过来求解:检查节点是否在当前视口范围内。