查看: 1147|回复: 1

相机跟随物体绑定后相机方向与物体运动方向垂直

[复制链接]

该用户从未签到

发表于 2015-12-17 21:21:11 | 显示全部楼层 |阅读模式
大家好!小弟编写了一个相机跟随船舶demo,按下运动键后物体运动方向与相机运动方向垂直,折腾了一天还是无法解决,恳请各位帮忙,谢谢!以下为源码:

class boatDeviceStateType//该类用于指示船舶运动状态
{
public:
        boatDeviceStateType():
        moveFwdOrBack(0),
        moveTurnLeftOrRight(0),
        m_fSpeed(0.50f),
        bStartFollowShip(false),
        m_fAngle(0.50f),
        _matBoat(osg::Matrixd::identity())
{
}
        ~boatDeviceStateType(void);

public:
        /**前进或后退标志:
        0: 停止
        1: 前进
        -1:后退
        */
        int moveFwdOrBack;

        /**左转弯或右转弯标志
        0: 未转弯状态
        1: 左转弯
        -1:右转弯
        */
        int moveTurnLeftOrRight;

        /**
        速度参数,相机运行及船舶运行需要用到
        初始速度设为2.0
        */
        float m_fSpeed;

        /**
        单位相机旋转角度,初始设置为2.0
        */
        float m_fAngle;

        /**
        是否开启相机绑定,默认关闭
        */
        bool bStartFollowShip;

        osg::Matrixd _matBoat;
};


class boatGUIEvent :
        public osgGA::GUIEventHandler
{
public:
        boatGUIEvent(boatDeviceStateType* tids)
        {
                boatInputDeviceState=tids;
        }

        ~boatGUIEvent(void);

        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
   switch(ea.getEventType())
        {
                case  osgGA::GUIEventAdapter::KEYDOWN:
                        {
                                if (ea.getKey()==0xFF52)//前行
                                {
                                        boatInputDeviceState->moveFwdOrBack=1;
                                        //std::cout<<"GUI:"<<std::endl;
                                }

                                else if (ea.getKey()==0xFF54)//后退
                                {
                                        boatInputDeviceState->moveFwdOrBack=-1;
                                }

                                if (ea.getKey()==0xFF53)//右转弯
                                {
                                        boatInputDeviceState->moveTurnLeftOrRight=-1;
                                }
                                else if(ea.getKey()==0xFF51)//左转弯
                                {
                                        boatInputDeviceState->moveTurnLeftOrRight=1;
                                }

                                if (ea.getKey()==0xFFAB)//按下加号键,对应于KEY_KP_Add
                                {
                                        boatInputDeviceState->m_fSpeed+=0.001;

                                }
                                else if(ea.getKey()==0xFFAD)//按下减号键,对应 KEY_UP_Subtract
                                {
                                        boatInputDeviceState->m_fSpeed-=0.001;
                                        if(boatInputDeviceState->m_fSpeed<=0.001)
                                                boatInputDeviceState->m_fSpeed=0.001;

                                }



                                return false;
                                break;
                        }

                case osgGA::GUIEventAdapter::KEYUP:
                        {
                                boatInputDeviceState->moveFwdOrBack=0;//停止前进及后退
                                boatInputDeviceState->moveTurnLeftOrRight=0;
                                return false;
                                break;
                        }

                default:

                        return false;
                        break;
}

protected:
        /**外设接收标志*/
        boatDeviceStateType* boatInputDeviceState;

};

//
struct updateAccumulatoredMatrix:public osg::NodeCallback
{
        virtual void operator()(osg::Node* node,osg::NodeVisitor* nv)
        {
                _matrix=osg::computeWorldToLocal(nv->getNodePath());
                traverse(node,nv);
        }
        osg::Matrix _matrix;
};

struct transformAccumulator
{
public:
        transformAccumulator()
        {
                _parent=NULL;
                node=new osg::Node;
                mpcb=new updateAccumulatoredMatrix;
                node->setUpdateCallback(mpcb);
        }

        bool attachToGroup(osg::Group* g)
        {
                bool _success=false;
                if (_parent!=NULL)
                {
                        int n=_parent->getNumChildren();
                        for (int i=0;i<n;i++)
                        {
                                if (node==_parent->getChild(i))
                                {
                                        _parent->removeChild(i,1);
                                        _success=true;
                                }
                        }

                        if (!_success)
                        {
                                return _success;
                        }
                }

                g->addChild(node);
                return true;
        }

        osg::Matrix getMatrix()
        {
                return mpcb->_matrix;
        }

protected:
        osg::ref_ptr<osg::Group> _parent;
        osg::Node* node;
        updateAccumulatoredMatrix* mpcb;
};

class followNodeMatrixManipulator:
        public osgGA::CameraManipulator
{
public:
        followNodeMatrixManipulator(transformAccumulator* ta)
        {
                worldCoordinatesOfNode=ta;
                theMatrix=osg::Matrixd::identity();
        }
        //~followNodeMatrixManipulator();
        virtual void setByMatrix(const osg::Matrixd& matrix)
        {
                theMatrix=matrix;
        }

        virtual void setByInverseMatrix(const osg::Matrixd& matrix)
        {
                theMatrix=osg::Matrix::inverse(matrix);
        }

        virtual osg::Matrixd getMatrix() const
        {
                return theMatrix;
        }

        virtual osg::Matrixd getInverseMatrix() const
        {
                //将矩阵从Y轴向上旋转到Z轴向上
                osg::Matrixd _mat;
                _mat=theMatrix* osg::Matrixd::rotate(-osg:I_2,osg::Vec3(1.0,0,0));
                return _mat;
        }

        void updateTheMatrix()
        {
                theMatrix=worldCoordinatesOfNode->getMatrix();
        }

        bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
        {
                switch(ea.getEventType())
                {
                case (osgGA::GUIEventAdapter::FRAME):
                        {
                                updateTheMatrix();
                                return false;
                        }
                }
                return false;
        }

protected:
        transformAccumulator* worldCoordinatesOfNode;
        osg::Matrixd theMatrix;
};


/**
加载天空球纹理
*/
osg::ref_ptr<osg::TextureCubeMap> loadCubeMapTexture()
{
        osg::ref_ptr<osg::TextureCubeMap> cubeMap=new osg::TextureCubeMap;
        cubeMap->setInternalFormat(GL_RGBA);
        cubeMap->setFilter(osg::Texture::MIN_FILTER,osg::Texture:INEAR_MIPMAP_LINEAR);
        cubeMap->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
        cubeMap->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
        cubeMap->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);

        cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_X,
                osgDB::readImageFile("resources/textures/sky_fair_cloudy/west.png"));

        cubeMap->setImage(osg::TextureCubeMap::POSITIVE_X,
                osgDB::readImageFile("resources/textures/sky_fair_cloudy/east.png"));

        cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Y,
                osgDB::readImageFile("resources/textures/sky_fair_cloudy/up.png"));

        cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Y,
                osgDB::readImageFile("resources/textures/sky_fair_cloudy/down.png"));

        cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Z,
                osgDB::readImageFile("resources/textures/sky_fair_cloudy/south.png"));

        cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Z,
                osgDB::readImageFile("resources/textures/sky_fair_cloudy/north.png"));

        return cubeMap;
}

//船舶运动回调
class BoatPcsitionCallback:public osg::NodeCallback
{
public:
        BoatPcsitionCallback(osgOcean::OceanScene *oceanScene,boatDeviceStateType* boatDevState)
        {
                _oceanScene=oceanScene;
                boatInputDeviceSta=boatDevState;
                m_fMoveSpeed=0.8;
                m_Angle=2.0;
        }

        virtual void operator()(osg::Node* node,osg::NodeVisitor * nv)
        {
                if (nv->getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
                {
                        osg::MatrixTransform* mt=dynamic_cast<osg::MatrixTransform*>(node);
                        if (!mt ||! _oceanScene)  return;
                        osg::Matrix mat=osg::computeLocalToWorld(nv->getNodePath());

                        osg::Vec3d pos=mat.getTrans();
                        osg::Vec3f normal;
                        float height=_oceanScene->getOceanSurfaceHeightAt(pos.x(),pos.y(),&normal);
                        float m_x=0.0;
                        float m_y=0.0;
                        static float m_Turn=0.0000;
                       
                        if (boatInputDeviceSta->moveFwdOrBack==1)//前进
                        {
                                m_x=fabs(boatInputDeviceSta->m_fSpeed)*cosf(m_Turn);
                                m_y=fabs(boatInputDeviceSta->m_fSpeed)*sinf(m_Turn);
                        }
                        else if (boatInputDeviceSta->moveFwdOrBack==-1)//后退
                        {
                                m_x=-fabs(boatInputDeviceSta->m_fSpeed)*cosf(m_Turn);
                                m_y=-fabs(boatInputDeviceSta->m_fSpeed)*sinf(m_Turn);
                        }
                        else if (boatInputDeviceSta->moveFwdOrBack==0)//停止前进
                        {
                                m_x=0.0;
                                m_y=0.0;
                        }

                        if (boatInputDeviceSta->moveTurnLeftOrRight==1)//左转弯
                        {
                                m_Turn+=osg:egreesToRadians(m_Angle);
                        }
                        else if (boatInputDeviceSta->moveTurnLeftOrRight==-1)//右转弯
                        {
                                m_Turn-=osg::DegreesToRadians(m_Angle);
                        }
                        else if(boatInputDeviceSta->moveTurnLeftOrRight==0)//停止转弯
                        {
                        }

                       
                        //mat.makeTranslate(osg::Vec3f(pos.x()+m_x,pos.y()+m_y,height-0.20));
                        mat.makeTranslate(osg::Vec3f(pos.x()+m_x,pos.y()+m_y,height+10));
                        osg::Matrix rot;
                        rot.makeIdentity();
                        rot.makeRotate(normal.x()/5,osg::Vec3f(1.0f,0.0f,0.0f),normal.y()/5,osg::Vec3f(0.0f,1.0f,0.0f),
                                m_Turn,osg::Vec3f(0.0f,0.0f,1.0f));
                        //a+=0.005;
                        mat=rot*mat;
                        mat=mat;
                        boatInputDeviceSta->_matBoat=mat;
                        mt->setMatrix(mat);

                }
                traverse(node, nv);
        }

private:
        osgOcean::OceanScene *_oceanScene;
        boatDeviceStateType* boatInputDeviceSta;
       
};

int main()
{
        osg::ref_ptr<osgViewer::Viewer> viewer=new osgViewer::Viewer;
        viewer->setUpViewInWindow(150,150,1024,768,0);

        //添加海洋
        osg::ref_ptr<osgOcean::FFTOceanSurface> oceanSurface=new osgOcean::FFTOceanSurface(64,
                256,100,osg::Vec2f(1.1f,1.1f),12.0f,1000.0f,0.8,1e-9,true,2.5,10.0f,256);//1e-8为浪高参数

        osg::ref_ptr<osgOcean::OceanScene> oceanScene=new osgOcean::OceanScene(oceanSurface.get());

        //添加海面数据
        viewer->addEventHandler(oceanSurface->getEventHandler());
        viewer->addEventHandler(oceanScene->getEventHandler());

        //添加天空盒
        osg::ref_ptr<osg::TextureCubeMap> cubemap=loadCubeMapTexture();
        osg::ref_ptr<SkyDome> skyDome=new SkyDome(10000.0f,16,16,cubemap.get());//new SkyDome(1900.0f,16,16,cubemap.get());
        skyDome->setNodeMask(oceanScene->getReflectedSceneMask() |oceanScene->getNormalSceneMask());
        osg::MatrixTransform * transform=new osg::MatrixTransform;
        transform->setDataVariance(osg::Object::DYNAMIC);
        transform->setMatrix(osg::Matrix::translate(osg::Vec3(0.0,0.0,0.0)));
        transform->setCullCallback(new SkyCameraTrackCallback);
        transform->addChild(skyDome);
        oceanScene->addChild(transform);
        //设置雾效与反射
        oceanScene->setAboveWaterFog(0.0012,osg::Vec4f(0.67,0.87,0.93,1.0));
        oceanScene->enableReflections(true);
        oceanSurface->setEnvironmentMap(cubemap);

        //水花
        oceanSurface->setFoamBottomHeight(2.20);
        oceanSurface->setFoamTopHeight(3.0);
        oceanSurface->enableCrestFoam(true);

        //
        boatDeviceStateType* bDeviceState=new boatDeviceStateType;
        boatGUIEvent* myBoatGUIEvent=new boatGUIEvent(bDeviceState);
        viewer->addEventHandler(myBoatGUIEvent);
        //

        //添加小船
        osg::ref_ptr<osg::Node> galley=osgDB::readNodeFile("resources/boat/boat.osgb");
        galley->setNodeMask(oceanScene->getReflectedSceneMask() |oceanScene->getNormalSceneMask()
                |oceanScene->getRefractedSceneMask());
        osg::ref_ptr<osg::MatrixTransform>galleyMat=new osg::MatrixTransform;
        /*osg::Matrix rot1;
        rot1.makeIdentity();
        rot1.makeRotate(0.0,osg::Vec3f(1.0f,0.0f,0.0f),0.0,osg::Vec3f(0.0f,1.0f,0.0f),
                osg::DegreesToRadians(90.0),osg::Vec3f(0.0f,0.0f,1.0f));*/
        galleyMat->setMatrix(/*rot1**/osg::Matrix::translate(osg::Vec3f(50.0f,0.0f,0.0f)));
        galleyMat->setUpdateCallback(new BoatPcsitionCallback(oceanScene,bDeviceState));

        galleyMat->addChild(galley);
        oceanScene->addChild(galleyMat);
        osg::ref_ptr<osg::Group> group=new osg::Group;

       //
        transformAccumulator* BoatTrackl=new transformAccumulator();//
        BoatTrackl->attachToGroup(galleyMat);//绑定跟随船
        followNodeMatrixManipulator* tb=new followNodeMatrixManipulator(BoatTrackl);//添加船舶跟随操作器

        viewer->setCameraManipulator(tb);

        group->addChild(oceanScene);
        osgUtil::Optimizer optimizer;
        optimizer.optimize(oceanScene.get());  
        optimizer.optimize(oceanSurface.get());  
        optimizer.optimize(galleyMat.get());  
        optimizer.reset();  
        //osgGA::TrackballManipulator *tb=new osgGA::TrackballManipulator;//添加操作器
        ////tb->setHomePosition(osg::Vec3f(0.0,0.0,20.0f),osg::Vec3f(0.0,20.0f,0.0),osg::Vec3f(0.0,0.0,1.0f));
        //tb->setHomePosition(osg::Vec3f(0.0,0.0,20.0f),osg::Vec3f(20.0,0.0f,0.0),osg::Vec3f(0.0,0.0,1.0f));

        //viewer->setCameraManipulator(tb);
       
        osg::DisplaySettings* ds=osg::DisplaySettings::instance();
        ds->setNumMultiSamples(16);
        viewer->setDisplaySettings(ds);
        viewer->setSceneData(group.get());

        viewer->run();

        return 0;
}

在此表示感谢!

该用户从未签到

 楼主| 发表于 2015-12-21 22:43:20 | 显示全部楼层
第一种解决方案:使用建模规范,规定模型朝向Y轴,同时修改模型运动类的函数,如下:
class VGDEVICE_API BoatPositionEvent :
                public osg::NodeCallback
        {
        public:

                BoatPositionEvent(osgOcean::OceanScene *oceanScene,vgLibrary::boatDeviceState* tids,osg::Node* _m_node):
                    _oceanScene(oceanScene),
                        boatRecDeviceState(tids),
                        m_node(_m_node)
                {
                }

                ~BoatPositionEvent(void)
                {
                }

                        virtual void operator()(osg::Node* node,osg::NodeVisitor * nv)
        {
                if (nv->getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
                {
                        osg::MatrixTransform* mt=dynamic_cast<osg::MatrixTransform*>(node);
                        if (!mt ||! _oceanScene)  return;
                        osg::Matrix mat=osg::computeLocalToWorld(nv->getNodePath());

                        osg::Vec3d pos=mat.getTrans();
                        osg::Vec3f normal;
                        float height=_oceanScene->getOceanSurfaceHeightAt(pos.x(),pos.y(),&normal);
                       
                        float m_x=0.0;
                        float m_y=0.0;
                        static float m_Turn=0.0;
                        if (boatRecDeviceState->moveFwdOrBack==1)//前进
                        {
                                m_x=-fabs(boatRecDeviceState->m_fSpeed)*sinf(m_Turn/*+osg:I_2*/);
                                m_y=fabs(boatRecDeviceState->m_fSpeed)*cosf(m_Turn/*+osg::PI_2*/);
                        }
                        else if (boatRecDeviceState->moveFwdOrBack==-1)//后退
                        {
                                m_x=fabs(boatRecDeviceState->m_fSpeed)*sinf(m_Turn/*+osg::PI_2*/);
                                m_y=-fabs(boatRecDeviceState->m_fSpeed)*cosf(m_Turn/*+osg::PI_2*/);
                        }
                       
                        if (boatRecDeviceState->m_LeftOrRight==1)//按下4
                        {
                                m_x=fabs(boatRecDeviceState->m_fSpeed)*cosf(m_Turn);
                                m_y=fabs(boatRecDeviceState->m_fSpeed)*sinf(m_Turn);
                        }
                        else if (boatRecDeviceState->m_LeftOrRight==-1)//按下5
                        {
                                m_x=-fabs(boatRecDeviceState->m_fSpeed)*cosf(m_Turn);
                                m_y=-fabs(boatRecDeviceState->m_fSpeed)*sinf(m_Turn);
                               
                        }

                        if (boatRecDeviceState->moveTurnLeftOrRight==1)//左转弯
                        {
                                m_Turn+=osg:egreesToRadians(boatRecDeviceState->m_fAngle);
                        }
                        else if (boatRecDeviceState->moveTurnLeftOrRight==-1)//右转弯
                        {
                                m_Turn-=osg::DegreesToRadians(boatRecDeviceState->m_fAngle);
                        }
                        else if(boatRecDeviceState->moveTurnLeftOrRight==0)//停止转弯
                        {
                       
                        }
                       
                        ////加入碰撞检测
                        //osg::Node* m_node=new osg::Node;
                        //m_node=osgDB::readNodeFile("dixing.osgb");
                        if (m_node)
                        {
                                osg::Vec3d newPos=osg::Vec3f(pos.x()+m_x+10,pos.y()+m_y+10,height);//移动后的点

                                osgUtil::IntersectVisitor iv;
                                osg::ref_ptr<osg:ineSegment> m_line=new osg::LineSegment(newPos,pos);
                                iv.addLineSegment(m_line.get());
                                m_node->accept(iv);
                                if (iv.hits())
                                {
                                        std::cout<<"发生碰撞!"<<std::endl;
                                }
                                else
                                {
                                        mat.makeTranslate(osg::Vec3f(pos.x()+m_x,pos.y()+m_y,height+2.0));
                                }
                        }
                        //
                        ////

                        //std::cout<<"m_Turn="<<m_Turn<<std::endl;
                        //mat.makeTranslate(osg::Vec3f(pos.x()+cosf(a),pos.y()+sinf(a),height+5.0));
                        //mat.makeTranslate(osg::Vec3f(pos.x()+m_x,pos.y()+m_y,height+1.0));
                        osg::Matrix rot;
                        rot.makeIdentity();
                        rot.makeRotate(normal.x(),osg::Vec3f(1.0f,0.0f,0.0f),
                                           normal.y(),osg::Vec3f(0.0f,1.0f,0.0f),
                                           m_Turn,osg::Vec3f(0.0f,0.0f,1.0f));
                        mat=rot*mat;
                        mat=mat;
                        mt->setMatrix(mat);
                       
                        /*osg::Vec3f _eye1,_center1,_up1;
                        mat.getLookAt(_eye1,_center1,_up1);

                        std::cout<<"物体"<<std::endl;
                        std::cout<<" _Eye1 "<<_eye1.x()<<" "<<_eye1.y()<<" "<<_eye1.z()<<std::endl;
                        std::cout<<" _center1 "<<_center1.x()<<" "<<_center1.y()<<" "<<_center1.z()<<std::endl;
                        std::cout<<" _up1 "<<_up1.x()<<" "<<_up1.y()<<" "<<_up1.z()<<std::endl;*/
                }

                traverse(node, nv);
        }

        private:
                osgOcean::OceanScene *_oceanScene;
                vgLibrary::boatDeviceState* boatRecDeviceState;

                osg::Node* m_node;
        };
绑定船舶后即可实现相机朝向船头方向,按下前进后退键即可实现模型前后运动
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表