ScreenMouseTrack.h #pragma once #include "stdafx.h" #include "ogre.h" #include "TranslateCoord.h" using namespace Ogre; enum QueryStatus { QUERY_NOMAL = 0, //鼠标没有按下过 QUERY_LBUTTONDOWN ,//鼠标按下了 QUERY_MOUSEMOVE //鼠标按下了,并在移动 }; class CScreenMouseTrack { public: CScreenMouseTrack(SceneManager* mgr, Camera* CamAdd,Ogre::Entity* ent,CTranslateCoord* mTranslateCoord); ~CScreenMouseTrack(void); void onLButtonDown(Vector2 mPoint);//设定一些信息 mTheAxis mCurRayDirecton mCamPos void onMouseMove(Vector2 mpoint);//根据当前点和之前获取的信息 计算该移动的vector3 void RayQuery(Vector2 mpoint);//查询 设置相交轴 射线方向 void onLButtonUp();//鼠标左键抬起 或离开窗口 private: void EraseList();//清楚list保存的坐标轴 void deselectObjects(); void selectObject(MovableObject *obj); BOOL GetScreenCoordinates(const Vector3& vWorldPos, Vector2& _point);//3D点到屏幕的转换 int getAxisNum();//得到当前轴的序号012 Entity* mEntity;//当前操作的Entity SceneManager *mSceneMgr; std::list<MovableObject*> mSelected;//选择的轴 Camera* mCamera;//当前查询所用摄像机 RaySceneQuery* mRaySceneQuery;//射线查询 Vector3 mAxisDirection;//当前查询到的坐标轴朝向 //Vector3 mRayCurPiont;//上一帧查询到的点位置 Vector2 mScreenOtherPoin;//查询到的坐标轴上另一点的屏幕映射 Vector2 mSreenCoordPoint;//坐标轴原点到屏幕的映射 float moveSpeed;//坐标移动的速度 Vector2 mCurPiont2D;//屏幕上一帧的坐标 SceneNode* CoordsNode;//坐标轴节点 QueryStatus mQueryStatus;//记录当前查询状态 float coordLength;//坐标包围盒的对角线大小 Vector3 RayDirection;//射线方向 CTranslateCoord* mCoords;//3个坐标轴 // CPoint curPoint;//记录鼠标move上一帧的位置 // SceneNode* mCoordSceneNode;//坐标位置 // Vector2 mTheAxis;//所查询到的坐标轴映射到屏幕上的方向 // Vector3 mCurRayDirection;//上一帧射线的方向 // Vector3 mCamPos;//相机位置 }; ScreenMouseTrack.cpp #include "StdAfx.h" #include "ScreenMouseTrack.h" CScreenMouseTrack::CScreenMouseTrack(SceneManager* mgr, Camera* CamAdd,Entity* ent,CTranslateCoord* mTranslateCoord):mSceneMgr(mgr),mEntity(ent), mCamera(CamAdd),mQueryStatus(QUERY_NOMAL),mCoords(mTranslateCoord) { mRaySceneQuery = mSceneMgr->createRayQuery(Ray()); } CScreenMouseTrack::~CScreenMouseTrack(void) { mSceneMgr->destroyQuery(mRaySceneQuery); } void CScreenMouseTrack::deselectObjects() { std::list<MovableObject*>::iterator itr; for (itr = mSelected.begin(); itr != mSelected.end(); ++itr) { //(*itr)->getParentSceneNode()->showBoundingBox(false); mCoords->setClick(false); (*itr)->getParentSceneNode()->setScale(1/1.1,1/1.1,1/1.1); } } void CScreenMouseTrack::EraseList() { //清除所有坐标轴 mSelected.erase(mSelected.begin(),mSelected.end()); } void CScreenMouseTrack::selectObject(MovableObject *obj) { //obj->getParentSceneNode()->showBoundingBox(true); obj->getParentSceneNode()->setScale(1.1,1.1,1.1);// int axisNum = getAxisNum(); mCoords->setClick(true,axisNum); /*obj->getParentSceneNode()->*/ mSelected.push_back(obj); } int CScreenMouseTrack::getAxisNum() { if (1==(int)mAxisDirection.x) return 0; if(1==(int)mAxisDirection.y) return 1; if (1==(int)mAxisDirection.z) return 2; //错误 AfxMessageBox(_T("坐标轴射线方向错误"), MB_OK); return -1; } void CScreenMouseTrack::onLButtonDown(Vector2 mPoint) { mCurPiont2D = mPoint; mQueryStatus = QUERY_LBUTTONDOWN; RayQuery(mPoint); } void CScreenMouseTrack::onMouseMove(Vector2 mpoint) { //之前按下了左键 if (mQueryStatus == QUERY_LBUTTONDOWN || mQueryStatus == QUERY_MOUSEMOVE) { //根据坐标原点离相机的距离确定移动速度 moveSpeed = 4.0f*CoordsNode->getPosition().distance(mCamera->getPosition())/mCamera->getNearClipDistance(); //求出射线和查询到的坐标轴间的夹角sin,并取倒数与moveSpeed相乘 Radian RayAixsAngle = RayDirection.angleBetween(mAxisDirection); moveSpeed = moveSpeed/Ogre::Math::Sin(RayAixsAngle); //移动coords和Entity //邻近临屏幕点的向量 Vector2 ScreenAxis2D = mpoint-mCurPiont2D; //3D坐标轴映射到平面的向量 Vector2 ScreenAxis3D_2D = mScreenOtherPoin - mSreenCoordPoint; //ScreenAxis3D_2D到ScreenAxis2D投影 决定移动距离 float translateDistance = ScreenAxis2D.dotProduct(ScreenAxis3D_2D)/ScreenAxis3D_2D.length(); CoordsNode->translate(mAxisDirection*translateDistance*moveSpeed); //等同设置mEntity位置 //mEntity->getParentSceneNode()->setPosition(CoordsNode->getPosition() - mEntity->getBoundingBox().getCenter()); mEntity->getParentSceneNode()->translate(mAxisDirection*translateDistance*moveSpeed); mQueryStatus = QUERY_MOUSEMOVE; //更新当前查询点 mCurPiont2D = mpoint; //更新射线方向 RayQuery(mpoint); } } void CScreenMouseTrack::onLButtonUp() { mQueryStatus = QUERY_NOMAL; deselectObjects(); } void CScreenMouseTrack::RayQuery(Vector2 mpoint) { Ray mouseRay = mCamera->getCameraToViewportRay(mpoint.x,mpoint.y);//mfc poin 到ogre vector2 //保留射线方向 RayDirection = mouseRay.getDirection(); if (mQueryStatus == QUERY_MOUSEMOVE) { return; } //设置查询掩码 mRaySceneQuery->setRay(mouseRay); //mRaySceneQuery->setQueryTypeMask(SceneManager::ENTITY_TYPE_MASK); mRaySceneQuery->setSortByDistance(true); mRaySceneQuery->setQueryMask(COORD_MASK); //Execute query RaySceneQueryResult &result = mRaySceneQuery->execute(); deselectObjects(); RaySceneQueryResult::iterator itr; //找到第一个查询到的坐标系轴 for ( itr = result.begin(); itr != result.end(); itr++ ) { mAxisDirection = itr->movable->getParentSceneNode()->getOrientation() * Ogre::Vector3::UNIT_X; selectObject(itr->movable); coordLength = itr->movable->getBoundingBox().getMaximum().distance(itr->movable->getBoundingBox().getMinimum()); //坐标轴原点节点 CoordsNode = itr->movable->getParentSceneNode()->getParentSceneNode(); Vector3 mCoord3D = CoordsNode->getPosition(); GetScreenCoordinates(mCoord3D,mSreenCoordPoint); Vector3 point3D = mCoord3D + mAxisDirection*coordLength; GetScreenCoordinates(point3D,mScreenOtherPoin); //查询到第一个坐标轴就返回 return; } //按下左键时没有查到坐标轴,避免外面按下,在拖进boundingbox 而移动了物体 mQueryStatus = QUERY_NOMAL; } BOOL CScreenMouseTrack::GetScreenCoordinates(const Vector3& vWorldPos, Vector2& _point) { assert(mCamera); Vector3 hcsPosition = mCamera->getProjectionMatrix() * (mCamera->getViewMatrix() * vWorldPos); // if((hcsPosition.x < -1.0f) || (hcsPosition.x > 1.0f) || // (hcsPosition.y < -1.0f) || (hcsPosition.y > 1.0f)) // { // return FALSE; // } //应该将-1-1之间变为0-1之间吧 _point.x = hcsPosition.x/2.0f + 0.5; _point.y = 0.5f - hcsPosition.y/2.0f;//y值方向相反 // x = m_nWidth / 2 + (m_nWidth * hcsPosition.x / 2); // y = m_nHeight / 2 - (m_nHeight * hcsPosition.y / 2); return TRUE; }