在 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
函數用于檢查節點是否在當前視口范圍內。它通過將世界坐標轉換為屏幕坐標,并檢查是否在視口內來判斷節點是否在屏幕范圍內。
這個有個容易犯錯的問題,就是語言描述是計算機屏幕范圍內,導致開發者想通過屏幕坐標去過濾,但是在空間沒有物體進行碰撞檢測的情況下,不好實現,所以逆過來求解:檢查節點是否在當前視口范圍內。