屏幕坐标转换场景坐标并进行物体检测

在 OpenSceneGraph 中,要将屏幕坐标转换为当前场景坐标,并过滤出屏幕显示范围内的节点,可以通过以下步骤实现:

  1. 获取屏幕坐标: 当用户点击或交互时,获取鼠标点击的屏幕坐标。

  2. 转换屏幕坐标为世界坐标: 使用视图矩阵和投影矩阵将屏幕坐标转换为世界坐标。

  3. 进行节点遍历和过滤: 遍历场景中的节点,根据节点的世界坐标和屏幕空间边界进行筛选,以确定哪些节点位于屏幕范围内。

以下是一个基本示例代码,展示了如何在 OpenSceneGraph 中实现屏幕坐标到当前场景坐标的转换,并过滤出屏幕显示范围内的节点:

#include 
#include 
#include 
#include 

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(&aa);
            if (view) {
                osg::ref_ptr 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 loadedModel = osgDB::readNodeFile("path/to/your/model.obj");

    osgViewer::Viewer viewer;
    viewer.setSceneData(loadedModel.get());

    viewer.addEventHandler(new PickHandler());

    return viewer.run();
}

isNodeInViewport 函数用于检查节点是否在当前视口范围内。它通过将世界坐标转换为屏幕坐标,并检查是否在视口内来判断节点是否在屏幕范围内。

这个有个容易犯错的问题,就是语言描述是计算机屏幕范围内,导致开发者想通过屏幕坐标去过滤,但是在空间没有物体进行碰撞检测的情况下,不好实现,所以逆过来求解:检查节点是否在当前视口范围内。

你可能感兴趣的:(osg学习记录,c++)