OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/97109615

目录

前言

OSG拾取动作概念:pick

鼠标拖动球体旋转的实现原理

光照亮度

代码

初始化模型代码

事件管理器代码

入坑

入坑一:场景中心结点随物体缩放变换了

入坑二:获取几何图形的半径不对

入坑三:屏幕坐标到世界坐标不正确

入坑四:鼠标拖动旋转错位

工程模板:对应版本号1.15.0


 

OSG三维开发专栏

OSG开发笔记(一):OSG介绍、编译

OSG开发笔记(二):OSG帮助文档编译

OSG开发笔记(三):OSG使用osgQt嵌入Qt应用程序

OSG开发笔记(四):OSG不使用osgQt重写类嵌入Qt应用程序》:

OSG开发笔记(五):OSG场景理解与基础类概述

OSG开发笔记(六):OSG内存管理

OSG开发笔记(七):OSG复现OpenGL入门示例和OSG坐标系

OSG开发笔记(八):OSG模型文件存储与读取

OSG开发笔记(九):OSG模型的基本操作之添加/删除、显示/隐藏、开关节点开/》:

OSG开发笔记(十):OSG模型的变换之平移、旋转和缩放

OSG开发笔记(十一):OSG渲染状态与2D纹理映射

OSG开发笔记(十二):OSG基本几何图形、内置几何类型

OSG开发笔记(十三):OSG三维纹理映射(体渲染)

OSG开发笔记(十四):OSG交互

OSG开发笔记(十五):OSG光照

OSG开发笔记(十六):OSG视口、相机和视点

OSG开发笔记(十七):OSG中的相机移动

OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源

OSG开发笔记(十九):OSG文字显示

OSG开发笔记(二十):OSG使用HUD显示文字

OSG开发笔记(二十一):OSG使用HUD绘制图形以及纹理混合模式

OSG开发笔记(二十二):OSG场景背景

OSG开发笔记(二十三):Qt使用QOpenGLWidget渲染OSG地球仪

OSG开发笔记(二十四):OSG漫游之平移、转向和低抬头

OSG开发笔记(二十五):OSG漫游之CS移动、碰撞检测与跳跃

OSG开发笔记(二十六):OSG漫游之上下楼梯

《OSG开发笔记(二十七):OSG路径漫游之录制播放固定路径动画

《OSG开发笔记(二十八):OSG模型固定路径动画

  持续补充中…

 

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源

 

前言

       地球的变换都实现了,还差一个鼠标点击地球拖动旋转,交互之前已经实现,但如何确定点击的是球体,然后拖动旋转球体,是本篇章的内容。

 

OSG拾取动作概念:pick

       Pick主要是通过鼠标的点击来拾取一些问题,或者判断鼠标所点的位置在哪里。在OSG中pick首先肯定需要相应鼠标单击时间,pick本身并不是一个OSG的库函数。Pick有两个重要的参数,即:点击时的屏幕位置,在pick中由这个屏幕上的点发射线到场景中的物体交互,可能与多个物体交互,然后逐一判断与那些物体相交。可以得到这些问题的节点,然后以区别他们。

       Pick拾取是重写交互的类osgGA::GUIEventHandler,然后在类的虚函数中是否与物体相交,然后拾取出相交的物体,可以理解为概念上Pick。

 

鼠标拖动球体旋转的实现原理

       原先想通过视口点与球心的距离,拖动自己得到屏幕视口上(视口界面)的坐标,入坑三解决后,发现笔者陷入误区,应该拾取球体上的点,拖动移动球体上的点,计算这两点间的角度,对球体进行旋转。

       具体方法是:获取物体变换矩阵,分别计算x,y,z三个方向的偏移角度,然后变换之后设置变换矩阵。

 

光照亮度

       光照对比目标软件,比较暗,优化增加了4个光源,提升亮度。

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第1张图片

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第2张图片

       增加光源后

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第3张图片

 

代码

初始化模型代码

osg::ref_ptr OsgWidget::getPick()
{
    osg::ref_ptr pGroup = new osg::Group();
    // 该结点是为了开关
    osg::ref_ptr pSwitch = new osg::Switch;
    // 该结点是为了变换
    osg::ref_ptr pTrans = new osg::MatrixTransform;
    // 该结点是为了灯光
    osg::ref_ptr pLightSource0 = new osg::LightSource;
    osg::ref_ptr pLightSource1 = new osg::LightSource;
    osg::ref_ptr pLightSource2 = new osg::LightSource;
    osg::ref_ptr pLightSource3 = new osg::LightSource;
    osg::ref_ptr pLightSource4 = new osg::LightSource;
#if 1
    {
        // 绘制球体
        // 步骤一:绘制几何类型(几何体)
        osg::ref_ptr pGeode = new osg::Geode;
        qreal radius = 1.0;
        pGeode->addDrawable(new osg::ShapeDrawable(
                                new osg::Sphere(osg::Vec3(0, 0, 0), 1.0f)));
        osg::ref_ptr pSphere = new osg::Sphere(osg::Vec3(0, 0, 0), radius);
        qDebug() << "几何结点中心点:" << pSphere->getRadius() 
                 << "设置的半径" << radius;
        // 打印几何体中心坐标与半径
        qDebug() << "变换结点中心点:" << pGeode->getBound().center().x()
                                    << pGeode->getBound().center().y()
                                    << pGeode->getBound().center().z();
        qDebug() << "变换结点半径:" << pGeode->getBound().radius()
                                  << pGeode->getBound().radius2();


        // 步骤二:加载图片添加纹理
        osg::ref_ptr pImage;
        pImage = osgDB::readImageFile("D:/qtProject/osgDemo/" \
                                      "osgDemo/modules/osgWidget/image/earth.bmp");
        osg::ref_ptr pTexture2D = new osg::Texture2D;
        pTexture2D->setImage(pImage.get());
        // 步骤三:渲染设置
        osg::ref_ptr pStateSet = pGeode->getOrCreateStateSet();
        pStateSet->setTextureAttribute(0, pTexture2D.get());
        pStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
        // 步骤四:手动设置属性,让法线随着模型大小变化而变化。
        // osg中光照只会对有法线的模型起作用,而模型经过缩放后法线是不会变得,
        pStateSet->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);
        pTrans->addChild(pGeode);

        // 步骤五:打开光照(开关节点得光照)
        pStateSet = pSwitch->getOrCreateStateSet();
        pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
        pStateSet->setMode(GL_LIGHT0, osg::StateAttribute::ON);
        pStateSet->setMode(GL_LIGHT1, osg::StateAttribute::ON);
        pStateSet->setMode(GL_LIGHT2, osg::StateAttribute::ON);
        pStateSet->setMode(GL_LIGHT3, osg::StateAttribute::ON);
        pStateSet->setMode(GL_LIGHT4, osg::StateAttribute::ON);
        // 步骤六:创建光照对象
        osg::ref_ptr pLight = new osg::Light();
        // 设置光照对应的光照点,对应GL_LIGHT0
        pLight->setLightNum(0);
        // 设置光照方向
        pLight->setDirection(osg::Vec3(0.0, 1.0, 0.0));
        // 设置光照位置,最后一个参数0-平行光,1-点光源
        pLight->setPosition(osg::Vec4(0.0, -5.0, 0.0, 1.0));
//        pLight->setPosition(osg::Vec4(0.0, -40.0, 0.0, 0.0));
        // 设置散射光颜色: 红光/白光
        pLight->setDiffuse(osg::Vec4(1.0, 1.0, 1.0, 1.0));
        // 设置常量衰减指数
        pLight->setConstantAttenuation(1.0);
        // 设置线性衰减指数
        pLight->setLinearAttenuation(0.0);
        // 设置二次衰减指数
        pLight->setQuadraticAttenuation(0.0);
        // 创建光源
        pLightSource0->setLight(pLight.get());

#if 1
        // 步骤七:增加上下左右4个光源
        pLight = new osg::Light(*pLight.get());
        pLight->setLightNum(1);
        pLight->setPosition(osg::Vec4(5.0, -5.0, 0.0, 1.0));
//        pLight->setDiffuse(osg::Vec4(1.0, 0.0, 0.0, 1.0));
        pLightSource1->setLight(pLight.get());

        pLight = new osg::Light(*pLight.get());
        pLight->setLightNum(2);
        pLight->setPosition(osg::Vec4(-5.0, -5.0, 0.0, 1.0));
//        pLight->setDiffuse(osg::Vec4(0.0, 1.0, 0.0, 1.0));
        pLightSource2->setLight(pLight.get());

        pLight = new osg::Light(*pLight.get());
        pLight->setLightNum(3);
        pLight->setPosition(osg::Vec4(0.0, -5.0, -5.0, 1.0));
//        pLight->setDiffuse(osg::Vec4(0.0, 0.0, 1.0, 1.0));
        pLightSource3->setLight(pLight.get());

        pLight = new osg::Light(*pLight.get());
        pLight->setLightNum(4);
        pLight->setPosition(osg::Vec4(0.0, -5.0, 5.0, 1.0));
//        pLight->setDiffuse(osg::Vec4(1.0, 0.0, 1.0, 1.0));
        pLightSource4->setLight(pLight.get());
#endif
        // 步骤八:添加事件管理器
//        _pViewer->addEventHandler(new MyUserEventHandler);
//        _pViewer->addEventHandler(new MyUserCameraEventHandler);
//        _pViewer->addEventHandler(new MyUserCameraScaleEventHandler);
        // 事件管理器中对WSAD控制摄像机平移、上下左右旋转地球仪、鼠标滚轮缩放、鼠标中间重置
        _pViewer->addEventHandler(new MyUserPickEventHandler);
#if 1
        {
            // 步骤九:设置相机参数
            osg::Vec3d eyeVect3D;
            osg::Vec3d centerVect3D;
            osg::Vec3d upVect3D;
            // 获取当前视口到图像中心的距离
            double radius = pSwitch->getBound().radius();
            // 将距离扩大5倍
            double viewDistance = radius * 5;
            // 参考点坐标,通常是物体中心
            centerVect3D = pSwitch->getBound().center();
            // 相机向上:尤其注意,相机向上的方向在世界坐标中的方向
            upVect3D = osg::Vec3d(0, 0, 1);
            // 视点及相机位置与物理位置分离
            eyeVect3D = centerVect3D + osg::Vec3d(0, 1, 0) * viewDistance;
            _pViewer->getCamera()->setViewMatrixAsLookAt(eyeVect3D,
                                                         centerVect3D,
                                                         upVect3D);
            // 这里不使用漫游器,需要自己手动关闭,因为OSG默认了会调用TrackballManipulator
            _pViewer->setCameraManipulator(0);
        }
#else
        _pViewer->setCameraManipulator(new osgGA::TrackballManipulator);
#endif
    }
#endif
    pSwitch->addChild(pTrans.get());
    // 添加光源(光源与球体平级结点,球体变换,光源不变换)
    pGroup->addChild(pSwitch.get());

    pGroup->addChild(pLightSource0.get());
    pGroup->addChild(pLightSource1.get());
    pGroup->addChild(pLightSource2.get());
    pGroup->addChild(pLightSource3.get());
    pGroup->addChild(pLightSource4.get());

    return pGroup.get();
}

事件管理器代码

MyUserPickEventHandler.h

#ifndef MYUSERPICKEVENTHANDLER_H
#define MYUSERPICKEVENTHANDLER_H

#include 
#include 

#define     ZOOM_OUT_SCALE      (0.95)      // 缩小比例系数
#define     ZOOM_IN_SCALE       (1.05)      // 放大比例系数
#define     MIN_SCALE           (0.5)       // 相机距离变小最小比例,视觉为地球仪放大
#define     MAX_SCALE           (2.5)        // 相机距离变大最大比例,视觉为地球仪缩小
#define     STEP_DISTANCE       (0.005)      // 相机上下左右单步移动距离

class MyUserPickEventHandler : public osgGA::GUIEventHandler
{

public:
    MyUserPickEventHandler();

public:
    /** Deprecated, Handle events, return true if handled, false otherwise. */
    virtual bool handle(const osgGA::GUIEventAdapter& guiEventAdapter, osgGA::GUIActionAdapter& guiActionAdapter);

protected:
    bool pick(const double x, const double y, osgViewer::Viewer *pViewer, osg::Vec3dArray *pVec3dArrayOut);
    osg::Vec3d screen2Word(osg::Vec3d screenVec3d, osgViewer::Viewer *pViewer);

private:
    float _scale;   // 保存当前相对于原始比例的缩放系数
    bool _pickEarth;
    osg::Vec3d _originVec3d;
    osg::Vec3d _lastVec3d;
};
#endif // MYUSEREVENTHANDLER_H

MyUserPickEventHandler.cpp

#include "MyUserPickEventHandler.h"
#include "define.h"
#include "osg/MatrixTransform"
#include 
#include "MyMath.h"

MyUserPickEventHandler::MyUserPickEventHandler()
    : osgGA::GUIEventHandler(),
      _scale(1.0),
      _pickEarth(false)
{
}

bool MyUserPickEventHandler::handle(const osgGA::GUIEventAdapter
                                &guiEventAdapter, osgGA::GUIActionAdapter &guiActionAdapter)
{
    bool flag = false;
    // 获取viwerer
    osg::ref_ptr pViewer
            = dynamic_cast(&guiActionAdapter);
    if(!pViewer)
    {
        return false;
    }
    osg::ref_ptr pGroup = pViewer->getSceneData()->asGroup();
    if(!pGroup)
    {
        return false;
    }
    osg::ref_ptr pSwitch;
    // 遍历结点,获取开关结点,两个结点:开关结点和灯光结点
    for(int index = 0; index < pGroup->getNumChildren(); index++)
    {
        pSwitch = pGroup->getChild(index)->asSwitch();
        if(pSwitch)
        {
            break;
        }
        if(index == pGroup->getNumChildren() - 1)
        {
            return false;
        }
    }
    osg::ref_ptr pTransform = pSwitch->getChild(0)->asTransform();
    if(!pTransform)
    {
        return false;
    }
    osg::ref_ptr pTrans = pTransform->asMatrixTransform();
    if(!pTrans)
    {
        return false;
    }
    osg::ref_ptr pGeode = pTrans->getChild(0)->asGeode();
    if(!pGeode)
    {
        return false;
    }
    osg::Vec3d eyeVect3D;
    osg::Vec3d centerVect3D;
    osg::Vec3d upVect3D;
    qreal radius = qSqrt(pSwitch->getBound().radius2() / 3);
    osg::Matrix matrix = pTrans->getMatrix();
    osg::Vec3d vec3d;
    osg::ref_ptr pVec3dArray = new osg::Vec3dArray();
    qreal offsetAngle;
    switch (guiEventAdapter.getEventType())
    {
    case osgGA::GUIEventAdapter::EventType::KEYDOWN:
        switch (guiEventAdapter.getKey())               // 左右上下 ADWS
        {
            case osgGA::GUIEventAdapter::KEY_Left:      // 左方向键-向左旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(-1.0), 0, 0, 1);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::KEY_Right:     // 右方向键-向右旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(1.0), 0, 0, 1);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::KEY_Up:        // 上方向键-向上旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(-1.0), 1, 0, 0);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::KEY_Down:      // 下方向键-向下旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(1.0), 1, 0, 0);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::KEY_A:         // A键-向右移动1个位置
                pViewer->getCamera()->getViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                eyeVect3D += osg::Vec3d(-STEP_DISTANCE, 0, 0);
                pViewer->getCamera()->setViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                break;
            case osgGA::GUIEventAdapter::KEY_D:         // D键-向右移动1个位置
                pViewer->getCamera()->getViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                eyeVect3D += osg::Vec3d(STEP_DISTANCE, 0, 0);
                pViewer->getCamera()->setViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                break;
            case osgGA::GUIEventAdapter::KEY_W:         // W键-向上移动1个位置
                pViewer->getCamera()->getViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                eyeVect3D += osg::Vec3d(0, 0, STEP_DISTANCE);
                pViewer->getCamera()->setViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                break;
            case osgGA::GUIEventAdapter::KEY_S:         // S键-向下移动1个位置
                pViewer->getCamera()->getViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                eyeVect3D += osg::Vec3d(0, 0, -STEP_DISTANCE);
                pViewer->getCamera()->setViewMatrixAsLookAt(eyeVect3D,
                                                            centerVect3D,
                                                            upVect3D);
                break;
            case osgGA::GUIEventAdapter::KEY_Space:     // 空格-开关结点
                pSwitch->setNodeMask(pSwitch->getNodeMask() == 0? 1:0);
                break;
            default:
                break;
        }
        break;
    case osgGA::GUIEventAdapter::EventType::SCROLL:
        switch (guiEventAdapter.getScrollingMotion())
        {
            case osgGA::GUIEventAdapter::SCROLL_UP:     // 鼠标滚轮向上放大
                _scale *= ZOOM_IN_SCALE;
                if(_scale > MAX_SCALE)
                {
                    _scale = MAX_SCALE;
                }
                matrix = matrix * matrix.scale(_scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x());
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::SCROLL_DOWN:   // 鼠标滚轮向下缩小
                _scale *= ZOOM_OUT_SCALE;
                if(_scale < MIN_SCALE)
                {
                    _scale = MIN_SCALE;
                }
                matrix = matrix * matrix.scale(_scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x());
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            default:
                break;
        }
        break;
    case osgGA::GUIEventAdapter::EventType::PUSH:
        switch (guiEventAdapter.getButton())
        {
        case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
            if(pick(guiEventAdapter.getX(), guiEventAdapter.getY(), pViewer, pVec3dArray.get()))
            {
                // 拾取到物体
                _pickEarth = true;
                _lastVec3d = pVec3dArray->at(0);
            }
            break;
        case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:   // 鼠标中间:重置
            // 显示
            pSwitch->setNodeMask(1);
            // 恢复默认大小
            _scale = 1.0;
            matrix = matrix * matrix.scale(_scale/matrix.getScale().x(),
                                           _scale/matrix.getScale().x(),
                                           _scale/matrix.getScale().x());
            matrix = matrix.rotate(osg::DegreesToRadians(0.0), 1, 1, 1);
            pTrans->setMatrix(matrix);
            // 恢复默认相机位置
            pViewer->getCamera()->getViewMatrixAsLookAt(eyeVect3D,
                                                        centerVect3D,
                                                        upVect3D);
            eyeVect3D = osg::Vec3d(0, -5, 0);
            pViewer->getCamera()->setViewMatrixAsLookAt(eyeVect3D,
                                                        centerVect3D,
                                                        upVect3D);
            break;
        default:
            break;
        }
        break;
    case osgGA::GUIEventAdapter::EventType::DRAG:
        if(_pickEarth)
        {
#if 0
            qDebug() << "===================================================";
            qDebug() << "变换结点中心:" << pTrans->getBound().center().x()
                                        << pTrans->getBound().center().y()
                                        << pTrans->getBound().center().z();
            qDebug() << "变换结点半径:" << qSqrt(pTrans->getBound().radius2() / 3);

            // 此时获取到的坐标为鼠标在屏幕上的坐标
            vec3d = osg::Vec3d(guiEventAdapter.getX(), guiEventAdapter.getY(), 0);
//            vec3d = osg::Vec3d(0, 0, 0);
            qDebug() << "传入屏幕坐标" << vec3d.x() <<  vec3d.y() << vec3d.z();
            vec3d = screen2Word(vec3d, pViewer);
            qDebug() << "输出世界坐标" << vec3d.x() <<  vec3d.y() << vec3d.z();
            // 修成世界坐标
            vec3d.set(vec3d.x(), -5, vec3d.y());
            qDebug() << "修改世界坐标" << vec3d.x() <<  vec3d.y() << vec3d.z();
#endif
            if(pick(guiEventAdapter.getX(), guiEventAdapter.getY(), pViewer, pVec3dArray.get()))
            {
                // 相交点
                vec3d = pVec3dArray->at(0);
                // 计算x轴方向角度
                offsetAngle = MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(vec3d.y(), vec3d.z()))
                              -MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(_lastVec3d.y(), _lastVec3d.z()));
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(-offsetAngle), 1, 0, 0);
                // 计算y轴方向角度
//                offsetAngle = MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(vec3d.x(), vec3d.z()))
//                              -MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(_lastVec3d.x(), _lastVec3d.z()));
//                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(offsetAngle), 0, 1, 0);
                // 计算z轴方向角度
                offsetAngle = MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(vec3d.y(), vec3d.x()))
                              -MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(_lastVec3d.y(), _lastVec3d.x()));
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(offsetAngle), 0, 0, 1);
                pTrans->setMatrix(matrix);
                _lastVec3d = vec3d;
            }
        }
        break;
    case osgGA::GUIEventAdapter::EventType::RELEASE:
        _pickEarth = false;
        break;

    default:
        break;
    }
    // 返回false会继续向下个事件处理类传递
//    return flag;
    // 返回true则消息被截取,不会向下个事件处理类传递
    return true;
}

bool MyUserPickEventHandler::pick(const double x, const double y, osgViewer::Viewer *pViewer, osg::Vec3dArray *pVec3dArrayOut)
{
    bool ret = false;
    // 判断场景
    if(!pViewer->getSceneData())
    {
        return false;
    }
    // 判断是否拾取到物体
    osgUtil::LineSegmentIntersector::Intersections intersections;
    if(pViewer->computeIntersections(x, y, intersections))
    {
        for(auto iter = intersections.begin();
            iter != intersections.end();
            iter++)
        {
            pVec3dArrayOut->push_back(iter->getWorldIntersectPoint());
            ret = true;
        }
    }
    return ret;
}

osg::Vec3d MyUserPickEventHandler::screen2Word(osg::Vec3d screenVec3d, osgViewer::Viewer *pViewer)
{
    osg::ref_ptr pCamera = pViewer->getCamera();
    osg::Matrix matrix = pCamera->getViewMatrix() *
                         pCamera->getProjectionMatrix() *
                         pCamera->getViewport()->computeWindowMatrix();
    osg::Matrix intertMatrix = osg::Matrix::inverse(matrix);
    osg::Vec3d worldVec3d = screenVec3d * intertMatrix;
    return worldVec3d;
}

 

入坑

入坑一:场景中心结点随物体缩放变换了

       预期应该是不变换的。

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第4张图片

解决方法:

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第5张图片      

        由此判断,开关结点与变换结点中心距离不一样,变换结点时相同的,应该时开关结点是否还有其他结点,经检查时添加了光照结点,如下图:

        

入坑二:获取几何图形的半径不对

        设置半径为1,获取上层结点半径为1.73205

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第6张图片

导致原因:

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第7张图片

解决方法:

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第8张图片

入坑三:屏幕坐标到世界坐标不正确

       不论缩放与移动,屏幕的世界坐标y轴应该一直是-5,初始化相机的时候设置了。

实测结果:

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第9张图片       

解决方法:

       可能存在理解错误,屏幕上的点,x和z转出来的应该是对的(依据移动点判断。

y轴值是-1.08,球体的位置为0,0,0,半径为1,若是相交最近的y值就是Y轴上,也就是(0,-1,0)是最近y值,所以屏幕上的中心点(200,200,0)应该对应坐标是(0,-5,0),实际x和z轴转出是对的,y轴是不对的,暂时先强制将y轴的深度设为-5,得出的姑且暂时认为是正确的吧。

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第10张图片

入坑四:鼠标拖动旋转错位

       原因:主要是X轴和Z轴的变换,笔者加入了Y轴

解决方法:

       去掉Y轴旋转

        OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源_第11张图片

 

工程模板:对应版本号1.15.0

        对应版本号1.15.0

 

欢迎技术交流和帮助,提供IT相关服务,索要源码请联系博主QQ: 21497936,若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/97109615

你可能感兴趣的:(Qt开发专栏,OSG,OSG三维开发专栏)