osg三維場景中拾取滑鼠在模型表面的點選點

西北逍遥發表於2024-11-19

osg三維場景中拾取滑鼠在模型表面的點選點

#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::LineSegmentIntersector* intersector = new osgUtil::LineSegmentIntersector(
        //    osgUtil::IntersectionVisitor::IntersectionType::FIRST, // 使用第一個相交點
        //    osg::Vec3(x, y, -1.0f), // 射線起點
        //    osg::Vec3(x, y, 1.0f)   // 射線終點
        //    );

        //osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::PROJECTION, x, y);

        // 執行相交檢測
        osgUtil::IntersectionVisitor iv;
        //bool computeIntersections(float x,float y, osgUtil::LineSegmentIntersector::Intersections& intersections,osg::Node::NodeMask traversalMask = 0xffffffff);

        // 儲存相交結果的容器
        osgUtil::LineSegmentIntersector::Intersections intersections;

        // 執行相交檢測
        if (view.computeIntersections(x, y, intersections)) {
            // 檢查是否有相交點
            if (!intersections.empty()) {
                // 獲取第一個相交點
                //const osgUtil::LineSegmentIntersector::Intersection& intersection = intersections[0];
                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; // 只處理第一個相交點
                }
                //const osg::Vec3& point = intersection.getWorldIntersectPoint();
                //std::cout << "Intersection point: " << point << std::endl;

            }
            else {
                std::cout << "No intersection found." << std::endl;
            }
        }
        else {
            std::cout << "No intersection found." << std::endl;
        }

        // 清理資源
        //delete intersector;
    }
};


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();
}

////////////////

#######################################

相關文章