射线使用-碰撞检测

【cocos creator】2.x里,使用3D射线碰撞检测 3:响应射线的物体分组group要设置为3D,分组管理里需要勾选3D和3D的碰撞。2: 响应射线的物体要加3D碰撞盒 BoxCollider3D。 阅读详情

射线使用-碰撞检测

我们首先实现对鼠标右键的响应是他能够自由查看

然后实现摄像机不能穿越地面

最后单击左键增加实体,并能在单机状态下移动实体

 

首先,一如既往,提供程序运行的代码框架

#include <CEGUI/CEGUISystem.h>
#include <CEGUI/CEGUISchemeManager.h>
#include <OgreCEGUIRenderer.h>

#include "ExampleApplication.h"

class MouseQueryListener : public ExampleFrameListener, public OIS::MouseListener
{
public:

 MouseQueryListener(RenderWindow* win, Camera* cam, SceneManager *sceneManager, CEGUI::Renderer *renderer)
  : ExampleFrameListener(win, cam, false, true), mGUIRenderer(renderer)
 {
 } // MouseQueryListener

 ~MouseQueryListener()
 {


 }

 bool frameStarted(const FrameEvent &evt)
 {
  return ExampleFrameListener::frameStarted(evt);
 }

 
 bool mouseMoved(const OIS::MouseEvent &arg)
 {
  return true;
 }

 bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
 {
  return true;
 }

 bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
 {
  return true;
 }


protected:
 RaySceneQuery *mRaySceneQuery;     // The ray scene query pointer
 bool mLMouseDown, mRMouseDown;     // True if the mouse buttons are down
 int mCount;                        // The number of robots on the screen
 SceneManager *mSceneMgr;           // A pointer to the scene manager
 SceneNode *mCurrentObject;         // The newly created object
 CEGUI::Renderer *mGUIRenderer;     // CEGUI renderer
};

class MouseQueryApplication : public ExampleApplication
{
protected:
 CEGUI::OgreCEGUIRenderer *mGUIRenderer;
 CEGUI::System *mGUISystem;         // cegui system
public:
 MouseQueryApplication()
 {
 }

 ~MouseQueryApplication()
 {
 }
protected:
 void chooseSceneManager(void)
 {
  // Use the terrain scene manager.
  mSceneMgr = mRoot->createSceneManager(ST_EXTERIOR_CLOSE);
 }

 void createScene(void)
 {
 }

 void createFrameListener(void)
 {
  mFrameListener = new MouseQueryListener(mWindow, mCamera, mSceneMgr, mGUIRenderer);
  mFrameListener->showDebugOverlay(true);
  mRoot->addFrameListener(mFrameListener);
 }
};


#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
#else
int main(int argc, char **argv)
#endif
{
 // Create application object
 MouseQueryApplication app;

 try {
  app.go();
 } catch(Exception& e) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
  MessageBox(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
  fprintf(stderr, "An exception has occurred: %s/n",
   e.getFullDescription().c_str());
#endif
 }

 return 0;
}

运行结果应当是一片漆黑


一、创建场景(createScene()添加代码)

       // Set ambient light创建天空
       mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
       mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

       // World geometry创建地面
       mSceneMgr->setWorldGeometry("terrain.cfg");

       // Set camera look point设置摄像机要防止摄像机一开始就在地面之下
       mCamera->setPosition(40, 100, 580);
       mCamera->pitch(Degree(-30));
       mCamera->yaw(Degree(-45));

既然我们建立了基本的世界空间,那么就要打开光标。打开光标,要使用CEGUI函数调用。

创建一个OgreCEGUIRenderer,然后创建系统对象并将刚创建的Renderer传给它。

创建mGUIRenderer时必须以最后一个参数告诉CEGUI你要用那个场景管理器

       // CEGUI setup
       mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);
       mGUISystem = new CEGUI::System(mGUIRenderer);

      // Mouse显示光标
       CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");
       CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");

你可以运行一下你的程序,看到有天,有地,还有一个不会动的图形化光标

——————————————————————————————————————————————

二、将鼠标右键绑定到“鼠标观察”模式

 首先进行变量介绍(这些变量框架代码已经提供了)

    RaySceneQuery *mRaySceneQuery;      // 射线场景查询指针,寻找地面上的坐标


    bool mLMouseDown, mRMouseDown;     // 如果按下鼠标按钮,返回True


    int mCount;                        // 屏幕上机器人的数量,实体数


    SceneManager *mSceneMgr;           // 指向场景管理器的指针


    SceneNode *mCurrentObject;    //指向最近创建的场景节点的指针(我们将用这个“拖拽”实体)。


    CEGUI::Renderer *mGUIRenderer;     // CEGUI渲染器


MouseQueryListener的构造函数中添加代码:

        // Setup default variables
        mCount = 0;
        mCurrentObject = NULL;
        mLMouseDown = false;
        mRMouseDown = false;
        mSceneMgr = sceneManager;

        // Reduce move speed
        mMoveSpeed = 50;
        mRotateSpeed /= 500;

//为了MouseQueryListener能收到鼠标事件,我们必须把它注册为一个鼠标监听器。

        // Register this so that we get mouse events.
        mMouse->setEventCallback(this);
//用场景管理器的一个调用创建一个RaySceneQuery对象

        // Create RaySceneQuery
        mRaySceneQuery = mSceneMgr->createRayQuery(Ray());

 

//创建一个RaySceneQuery,以后我们就必须销毁它。

~MouseQueryListener()析构函数增加代码:

        // We created the query, and we are also responsible for deleting it.
        mSceneMgr->destroyQuery(mRaySceneQuery);

mouseMoved中增加代码:

      // Update CEGUI with the mouse motion
       CEGUI::System::getSingleton().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);

 

 

      // If we are dragging the left mouse button.
       if (mLMouseDown)
       {
       } // if

       // If we are dragging the right mouse button.
       else if (mRMouseDown)
       {
           mCamera->yaw(Degree(-arg.state.X.rel * mRotateSpeed));
           mCamera->pitch(Degree(-arg.state.Y.rel * mRotateSpeed));
       } // else if


 

 

mousePressed中增加代码:
       //当鼠标右键按下时,隐藏光标,并设置变量mRMouseDown为true。

       // Left mouse button down
       if (id == OIS::MB_Left)
       {
           mLMouseDown = true;
       } // if

       // Right mouse button down
       else if (id == OIS::MB_Right)
       {
           CEGUI::MouseCursor::getSingleton().hide();
           mRMouseDown = true;
       } // else if

 

mouseReleased中增加代码:
        //右键抬起时,我们需要再次显示光标,并将mRMouseDown设置为false。

          // Left mouse button up
       if (id == OIS::MB_Left)
       {
           mLMouseDown = false;
       } // if

       // Right mouse button up
       else if (id == OIS::MB_Right)
       {
           CEGUI::MouseCursor::getSingleton().show();
           mRMouseDown = false;
       } // else if

试一下你的摄像机是否能受右键控制吧!

____________________________________________________________________________

三、地形碰撞检测

    在BaseFrameListener移动了摄像机后,我们要确保摄像机在地面以上10个单位处。如果它不在,我们要把它移到那儿。

frameStarted中增加代码(删除原来的return语句):

        // Process the base frame listener code.  Since we are going to be
        // manipulating the translate vector, we need this to happen first.
        if (!ExampleFrameListener::frameStarted(evt))
            return false;

//因为ExampleFrameListener的frameStarted成员函数移动摄像机,并且在此发生后我们需要在函数中安排

//我们的剩余行动。我们的目标及时找到摄像机的当前位置,并沿着它向地面发射一条射线。这被称为射线

//场景查询,它会告诉我们我们下面的地面的高度。得到了摄像机的当前位置后,我们需要创建一条射线。

//这条射线有一个起点(射线开始的地方),和一个方向(此处y轴负方向)。

 

       // Setup the scene query
       Vector3 camPos = mCamera->getPosition();
       Ray cameraRay(Vector3(camPos.x, 5000.0f, camPos.z), Vector3::NEGATIVE_UNIT_Y);

       //一旦我们创建了射线,我们就告诉RaySceneQuery对象使用它。 
       mRaySceneQuery->setRay(cameraRay);
       //使用了5000.0f高度代替了摄像机的实际位置。

 

       //现在我们需要执行查询,得到结果。查询结果是std::iterator类型的。

       // Perform the scene query
        RaySceneQueryResult &result = mRaySceneQuery->execute();
        RaySceneQueryResult::iterator itr = result.begin();

//begin方法获得迭代器的第一个元素。如果result.begin() == result.end(),那么无返回结果

 

//保证至少返回一个查询结果(itr != result.end()),那个结果是地面(itr->worldFragment)。

// Get the results, set the camera height
        if (itr != result.end() && itr->worldFragment)
        {
//worldFragment结构包含有在变量singleIntersection(一个Vector3)中射线击中地面的位置。
//我们要得到地面的高度,依靠将这个向量的Y值赋值给一个本地变量。
//一旦我们有了高度,我们就要检查摄像机是否低于这一高度,如果低于这一高度,
//那么我们要将摄像机向上移动至地面高度。
//注意,我们实际将摄像机多移动了10个单位。这样保证我们不能由于太靠近地面而看穿地面。

            Real terrainHeight = itr->worldFragment->singleIntersection.y;
            if ((terrainHeight + 10.0f) > camPos.y)
                mCamera->setPosition( camPos.x, terrainHeight + 10.0f, camPos.z );
        }

        return true;

运行一下,看你还能否“入地”!

 

_______________________________________________________________________________________

 

 


 

 四、添加对象并实现拖拽

    每次点击鼠标左键,我们将向屏幕上创建和添加对象。每次你点击、按住鼠标左键,就会创建一个对象并跟随你的光标。你可以移动对象,直到你松开鼠标左键,同时对象也锁定在那一点上。要做到这些,我们需要改变mousePressed函数。

在mousePressed()中的if语句添加代码:

       // Left mouse button down
       if (id == OIS::MB_Left)
       {
         // Setup the ray scene query, use CEGUI's mouse position
               CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
               Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(arg.state.width), mousePos.d_y/float(arg.state.height));
// Camera::getCameraToViewpointRay;一个将屏幕上的点击(X和Y坐标)转换成一条可供RaySceneQuery对象使用的射线的好用函数
               mRaySceneQuery->setRay(mouseRay);
               // Execute query执行查询
               RaySceneQueryResult &result = mRaySceneQuery->execute();
               RaySceneQueryResult::iterator itr = result.begin( );

               // Get results, create a node/entity on the position
               if (itr != result.end() && itr->worldFragment)
               {
       //有了worldFragment(也就是点击的位置),就可以创建对象并把它放到位。
       //解决唯一命名问题
                 char name[16];
                 sprintf( name, "Robot%d", mCount++ );
                 //用itr->worldFragment->singleIntersection作为我们的机器人的默认位置

                  Entity *ent = mSceneMgr->createEntity(name, "robot.mesh");
                   mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(String(name) + "Node", itr->worldFragment->singleIntersection);
                   mCurrentObject->attachObject(ent);
                   mCurrentObject->setScale(0.1f, 0.1f, 0.1f);//地图挺小的放小一点
               } // if

               mLMouseDown = true;
           } // if

在mousemoved()的if(mLMouseDown){}中添加代码:

if (mLMouseDown)
       {
           CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
           Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(arg.state.width),mousePos.d_y/float(arg.state.height));
           mRaySceneQuery->setRay(mouseRay);

           RaySceneQueryResult &result = mRaySceneQuery->execute();
           RaySceneQueryResult::iterator itr = result.begin();

           if (itr != result.end() && itr->worldFragment)
               mCurrentObject->setPosition(itr->worldFragment->singleIntersection);
       } // if

【 Git学习记录(三)】推荐四款主流的Git代码托管平台 —— GitHub、GitLab、Gitee、Coding 了解过Git之后,作为一个程序猿最基本的,你还需要了解目前主流的在线代码托管平台,并至少选择其中一款在平时开发中使用。这里特别介绍以下四款: 国外平台 GitHub —— 全球最流行的代码托管平台 GitLab —— 基于git的仓库管理程序 国内平台 Gitee —— 开源中国旗下的代码托管平台 Coding —— 支持社交元素的代码托管平台 一. GitHub 链接地址:https://github.com/ GitHub目前是全球最流行的代码托管平台(别称:全球最大的同性交友. 阅读详情

相关推荐

激光雷达接收芯片选型指南:APD、SiPM、SPAD阵列的优缺点对比

本文深入对比了激光雷达接收芯片APD、SiPM和SPAD阵列的核心技术原理与性能差异。APD作为线性模式工作的稳健选择,动态范围大;SiPM具备单光子探测和高增益优势;而SPAD阵列凭借像素级数字读出和集成TDC,在时间分辨率与系统集成度上领先。文章从灵敏度、时间精度、动态范围及系统成本等多维度剖析,为不同应用场景(如车载雷达、Flash LiDAR、消费电子)的芯片选型提供实战指南。

ik6789012的博客 655

UE<C++>三步在C++中制作射击类游戏(射线检测、接口调用)

C++中制作射击类游戏

weixin_44090328的博客 2078

IMU自动校准论文与代码实现A Robust and Easy to Implement Method for IMU Calibration without External Equipments

PART1 摘要 低成本的惯性测量单元会受到系统误差的影响,系统误差由标度因子和轴偏差造成,这会降低位置和姿态估计的精度。 本文提出了一种无需任何外部设备的,鲁棒性强,易于实现的IMU校准方法。 该程序基于多放置方案,再估计传感器偏差的同时,为加速度和陀螺仪三轴的尺度和偏差系数。我们的方法只需要用手移动传感器,并将其放置在一组不同的静态位置(姿态)。 论文描述了一个鲁棒的快速校准协议,...

qq_29313679的博客 5308

OGRE 地形碰撞检测

我们现在要实现它,以便当我们向着地面移动时,能够不穿过地面。因为BaseFrameListener已经处理了摄像机移动,所以我们就不用碰那些代码了。替代地,在BaseFrameListener移动了摄像机后,我们要确保摄像机在地面以上10个单位处。如果它不在,我们要把它移到那儿。请跟紧这段代码。我们将在本教程结束前使用RaySceneQuery做几件别的事,而且在这段结束后,我不会再做如此详细的介

痞子龙3D编程 3028

游戏数据训练世界模型:AI物理规律学习与仿真应用实践

世界模型作为理解现实世界动态的AI工具,通过多模态数据学习物理和空间属性来预测未来状态。其核心原理在于从环境交互中提取物理规律,技术价值体现在能够安全、低成本地训练AI系统应对复杂场景。在应用层面,游戏数据因其结构化环境和内置物理引擎,成为世界模型训练的优质素材。游戏世界中的物体交互、运动轨迹等数据天然包含现实物理规律,特别适合训练物理AI。本文以General Intuition公司获得3.2亿美元融资为切入点,深入探讨游戏数据在世界模型训练中的技术实现路径,涵盖数据提取管道构建、多模态数据融合方法,以及

weixin_29056865的博客 367

嵌入式开发实战:如何用cJSON库在STM32上实现轻量级JSON通信(附完整代码)

本文详细介绍了如何在STM32嵌入式系统中使用cJSON库实现高效的JSON通信方案。针对嵌入式环境的内存限制,提供了内存优化策略、cJSON库的深度定制方法以及完整的通信流程实现代码,帮助开发者解决JSON解析效率低下和跨平台兼容性等核心挑战。

star5的专栏 471

OGRE 选中物体

选中物体这次对于所有的鼠标事件,我创建了封闭函数来处理它们。当用户按下鼠标左键,"onLeftPressed"函数被调用,当按下右键时"onRightReleased"函数被调用,等等。一如既往,首先给出框架代码:   #include    #include    #include      #include "ExampleApplication.h"     class Mo

痞子龙3D编程 2564

【软考高项论文】论信息系统项目管理的干系人绩效域

例如,在处理与电信运营商合作铺设光纤网络的问题时,考虑到其在通信设施建设和运维方面的专业性和重要性,我们将之定位为高权力高利益的干系人,给予了高度关注和优先沟通。项目全程,我们对干系人绩效域的执行效果进行了定期检查和评估,通过定量与定性的数据收集,确认了项目在干系人管理上的成效,具体表现为:建立了稳固的工作关系网络,使干系人普遍认可项目目标;鉴于本项目牵涉到政府各级部门、企事业单位、市民团体、技术研发伙伴等多种类型的干系人,且干系人的诉求和影响力各异,因此,有序且持续的干系人参与管理显得尤为关键。

Programming Talk 1681

OGRE最简单的射线拾取详解

<br />射线拾取原理是从摄像机发射一条经过鼠标位置的射线,计算射线和哪些三角形相交,然后计算这些三角形所属的场景对象(可以是Entity,Light,平面等等)<br />OGRE已经帮我们实现了基本的功能。<br />在这里实现的是最简单的鼠标射线拾取。<br />view plaincopy to clipboardprint?<br />bool GuiFrameListener::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButton

痞子龙3D编程 2992

数仓建模—数据语义层

如今,企业产生大量数据,需要以正确的方式进行分析才能做出重要决策。数据可能来自多个来源并采用不同的格式,这使得清楚地了解其含义和重要性成为一项挑战。这就是语义层的用武之地。语义层存在于数据仓库和最终用户使用的应用程序之间。它为用户提供了简化且一致的数据视图,无论其基础数据源的复杂性如何。该逻辑层有助于映射物理数据结构以创建概念数据模型。它定义了数据元素之间的所有规则和关系,并以业务术语提供了数据的通用词汇表。然后,用户可以轻松地与数据进行交互,而无需了解其数据源的技术知识。

7万+

unity射线碰撞检测+LayerMask的使用

unity射线碰撞检测+LayerMask的使用 http://www.unitymanual.com/thread-21402-1-1.html (出处: -游戏开发者社区【游戏蛮牛】unity3d官网)

anmofeng的专栏 2294

从零开始跑通3DGS教程:(三)坐标系与尺度编辑(CloudCompare)

本文所属《从零开始跑通3DGS教程》系列文章; sfm重建的点云已经丢掉了尺度信息,并且坐标系跟图像数据有关(SFM初始化选择的图像),所以如果想恢复物理真实尺度,以及在想要的视角下渲染,那么需要对尺度和坐标系进行编辑修正,下文介绍如何使用CloudCompare修改坐标系和尺度

诺有缸的高飞鸟的博客 2870

[Unity3D]射线碰撞检测+LayerMask的使用

更多教程请访问: http://dingxiaowei.cn/ 射线:射线是3D世界中一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射。 用途:在unity中射线应用范围比较广,多用于碰撞检测(如:子弹飞行是否击中目标)、角色移动 等。 相关API: 1、RayCamera.main.Sc...

学无止境的专栏 2万+

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

射线碰撞检测+LayerMask的使用

射线:射线是3D世界中一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射 。 用途:在unity中射线应用范围比较广, 多用于碰撞检测(如:子弹飞行是否击中目标)、角色移动 等。 相关API: 1、Ray Camera.main.ScreenPointToRay(Vector3 pos)   返回一条射线Ray从摄像机到屏幕指定一个点

yaokang522的专栏 582

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

U3D 射线碰撞检测+LayerMask的使用

射线:射线是3D世界中一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射 。 用途:在unity中射线应用范围比较广, 多用于碰撞检测(如:子弹飞行是否击中目标)、角色移动 等。 相关API: 1、Ray Camera.main.ScreenPointToRay(Vector3 pos)   返回一条射线Ray从摄像机到屏幕指定一个点

Acettest's Blogs 989

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Unity 使用物理射线(Physics.Raycast),实现扇形区域碰撞检测三种方法

Unity 使用物理射线(Physics.Raycast),实现扇形(Fan-Shaped)区域碰撞检测。 参考之前的制作简单UI: Unity 有限状态机(Finite State Machine)的理解 与 实现简单的可插拔(Pluggable)AI脚本对象。 Github项目:GentleTank   网上已经很多实现扇形检测的方法。大部分都是用MeshCollider实现的。而据说

l773575310的博客 3万+

Unity射线碰撞检测的LayerMask的使用

Unity射线碰撞检测接口: Raycast (ray : Ray, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) layerMask参数设计如下: 1 &lt;&lt; 10 打开第10的层。 ~(1 &lt;&lt; 10)...

iDaDi的博客 721

Ogre中精确到三角面的碰撞检测(使用射线查询)

201404-04Ogre中精确到三角面的碰撞检测(使用射线查询) Jianchihu 编程之美 围观1238次 留下评论 编辑日期:2015-11-13 字体:大 中 小Ogre中的射线查询一般只能侦测到边界盒(AABB),就像你在下面图片看到的,使用下面的代码就能避免这些。初始化射线查询:12345678// create the ray scene query object    m_pra...

yangchuangbao的博客 728
上一篇: OGRE - 场景管理器
下一篇: OGRE+OIS 帧监听FrameListener、非缓冲输入和缓冲输入
性感花脸
博客等级 码龄20年 26粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值