让物体绕固定点做圆周运动 让物体到达目的点

2023-11-09 11:10

本文主要是介绍让物体绕固定点做圆周运动 让物体到达目的点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

考虑了很多思路,但是大部分实际实现与预想的有很大差异,终其原因,是因为每帧的所消耗的时间是不定的,且轨迹离散,所以每帧都可能需要做轨迹的稍微修正(这种修正帧率越低速度越快会导致越明显)。下面的思路是比较简洁和高效的一种方式。
对于3d中的物体运动到目标点或者运动到目标轨迹,都需要先考虑如何让物体到达目标点或者轨迹。这里只讲述如何到达目标轨迹。对于有需要考虑精确的加速度的运动,需要考虑路径积分等复杂的运算。这里只考虑匀速的方式到达轨迹。如下:


r1 为目标轨迹,r2为物体当前位置的向心运动轨迹。O为物体当前位置及运动朝向。绿色的线为当前轨迹与目标轨迹的切线,黄色的为目标物体从当前位置运动到目标轨迹将要走的预期轨迹。
假设物体速度是恒定的,为了让物体朝向运动轨迹,首先需要让物体方向转到朝向目标轨迹,考虑的第一个就是用向心力(运动轨迹计算中必不可少的一个量)来达到转向目的,假设有一个外力Fx(向心力) = Fl(离心力) ,向心力的加速度为ao = Fx/m,Fl = ma = m*v^2/r   =>   a = v^2/r 。r = Fx/(m*v^2) = Fx/m/(v^2) = ao/(v^2)。实际中,向心力是有最大值的且可以控制成恒定量和可收放,向心力有最大值就表示半径r有最小值,根据 r和向心运动的轨迹圆和当前位置 求出的圆心 就很方便计算轨迹了。实际运算中,因为每帧间隔计算是离散的,所以在进入预设轨迹之后实际轨迹应该是一直处于相交状态,这样就需要一直保持位移修正修正和角度修正。帧率越高,越能贴合实际预期的轨迹。

注意从一个圆轨迹硬切到另外一个圆轨迹,是有力的突变的!!!!要想平滑快速切入,会比较麻烦。

扩展:根据这个方式,也可以很快的判断出前方的目标点在当前速度下是否不绕圈的情况下可达(在向心圆内或圆外),甚至计算出如何最快入轨(比如降低速度,复杂运算就需要考虑积分问题)等等操作。(到达目的点如果容许绕圈的情况,可以用我这种方式,虽然可能不是最快速度或最短路径,但是比较简洁容易理解。)


下面简单粗暴的使用最小r值示例。 
整体思路:

    /*做圆周运动,每帧的angle应该是不为0的,因为每帧都会有转角。也就是每帧都需要进行方向的修正。但是这个方式的思路是(即上面图中的黄色线路图的描述):

1、让计算物体每帧的角度修正。
2、在物体转动到目标切线方向的时候(forward==targetdir),如果圆心位置偏移比较大,将角度修正屏蔽掉(设置为0),让只做向着目标轨迹切点方向的平移,可以想象这个直接适用于上面的三种情况。
*/

int AppWorldLogic::init() //循环体外,初始化
{
    App::get()->setUpdate(1);
    Visualizer::get()->setEnabled(1);
    m_nodeO = Editor::get()->getNodeByName("material_ball");
    m_node = m_nodeO->clone(); //当前控制运动的物体
    m_node->setWorldTransform(translate(Vec3(m_x, 0, 0))); //设置当前控制运动的物体的初始位置
    m_target = m_nodeO->getNodeWorldPosition();//目标轨迹圆心
    vec3 left = m_node->getWorldLeft();
    vec3 targetDir = getTvec3(vec3((m_target - m_node->getNodeWorldPosition())));//当前控制物体的与目标轨迹圆心的方向。等价于预期的切入到目标轨迹的切入点的切线方向。
    m_isleft = dot(targetDir, left) > -0.00001;//根据偏向左边还是右边来判定向左还是向右。当然可以设置只向左或向右
    return 1;
}

int AppWorldLogic::update() //循环体内,60fps
{//只考虑二维平面的圆周运动 ,对于三维空间的运动,要复杂一些,但是可以通过降维加修正来达到预期。
    //本方法直接设定物体的离心力固定,只绕特定半径来做圆周运动。步骤为先转动方向,再移动到轨道上,再在轨道上运行。
    float ifps = Game::get()->getIFps();//上一帧所消耗的时间
    Vec3 pos = m_node->getNodeWorldPosition();
    vec3 forward = m_node->getWorldForward(); //当前物体的前方
    vec3 left = m_node->getWorldLeft();
    vec3 right = m_node->getWorldRight();
    double currentAcce = m_speed*m_speed / m_radius; //获取向心力加速度,m_radius表示事先设定的半径
    vec3 up = vec3(0, 0, 1);//考虑在xy平面上做圆周运动
    float angle = 0;
    Vec3 centerDir = m_isleft? Vec3(left):Vec3(right);
    vec3 v = forward*m_speed;
    v += vec3(centerDir)*currentAcce*ifps;//当前运动方向为forward+向心力的加速度乘ifps。
    v.z = 0;
    v = v.normalize()*m_speed;//计算出当前物体在当前帧的运动方向,注意这是个离散值。
    angle = getAngle(forward, v, up);  //计算出这帧应该偏移的角度,angle between forward and new direction// / 2.0f    Mat4 mat = m_node->getWorldTransform();
    Vec3 centerPos = pos;
    if (m_isleft)
    {
        centerPos = (mat*translate(Vec3(1, 0, 0)*m_radius)).getTranslate();//当前运动轨迹的圆心
    }
    else
    {
        centerPos = (mat*translate(Vec3(-1, 0, 0)*m_radius)).getTranslate();
    }
    if((centerPos-m_target).length()>m_speed*ifps)//圆心偏移是几乎不可能为0的,在一个可接受的误差范围内就足够了。
    {
        vec3 targetDir = vec3(m_target - centerPos).normalize();//m_target表示目标圆心,此处获取到从当前的圆心到目标点的向量。这个正好是该修正的偏移值。
        targetDir = targetDir.normalize();
        forward = forward.normalize();
        Log::message("%f\n", dot(targetDir, forward));//dot算出两向量夹角的弧度
        if (dot(targetDir, forward) > 0.99)//目标方向和当前方向不可能是绝对的没有误差。所以此处判断如果两个方向夹角的余弦值为0.99即两个方向夹角接近0度了,则不用去修正角度了。将角度设置为0。(可以绘制一张图,目标方向与目标元切线方向一致。)
        {
            angle = 0;//方向正确了,接下来就只进行偏移的修正,将方向修正暂停。
        }
    }

    mat = mat*Mat4(quat(up, angle))*translate(Vec3(0, -1, 0)*m_speed*ifps);//将这帧之前的变换矩阵乘以这帧的变化矩阵(注意矩阵的组装和摆放的顺序,可参考我之前的关于矩阵的博客),求出这帧之后的变换矩阵。
    m_node->setWorldTransform(mat);
    return 1;
}
 

这篇关于让物体绕固定点做圆周运动 让物体到达目的点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/375736

相关文章

2024 年高教社杯全国大学生数学建模竞赛题目——2024 年高教社杯全国大学生数学建模竞赛题目的求解

2024 年高教社杯全国大学生数学建模竞赛题目 (请先阅读“ 全国大学生数学建模竞赛论文格式规范 ”) 2024 年高教社杯全国大学生数学建模竞赛题目 随着城市化进程的加快、机动车的快速普及, 以及人们活动范围的不断扩大,城市道 路交通拥堵问题日渐严重,即使在一些非中心城市,道路交通拥堵问题也成为影响地方经 济发展和百姓幸福感的一个“痛点”,是相关部门的棘手难题之一。 考虑一个拥有知名景区

005:VTK世界坐标系中的相机和物体

VTK医学图像处理---世界坐标系中的相机和物体 左侧是成像结果                                                    右侧是世界坐标系中的相机与被观察物体 目录 VTK医学图像处理---世界坐标系中的相机和物体 简介 1 在三维空间中添加坐标系 2 世界坐标系中的相机 3 世界坐标系中vtkImageData的参数 总结:

Unity3D在2D游戏中获取触屏物体的方法

我们的需求是: 假如屏幕中一个棋盘,每个棋子是button构成的,我们希望手指或者鼠标在哪里,就显示那个位置的button信息。 网上有很多获取触屏物体信息的信息的方法如下面代码所示: Camera cam = Camera.main; // pre-defined...if (touch.phase == TouchPhase.Bagan)){ // 如果触控点状态为按下Ray

Unity --- 各种关节(Joints)来模拟物体之间的连接

目录 一:2D关节 一:1 固定关节 (Fixed Joint 2D) 功能: 适用场景: 1. 平台游戏中的固定平台: 2. 拼图游戏中的固定部件: 3. 建筑游戏中的固定结构:  一:2 铰链关节 (Hinge Joint 2D) 功能: 适用场景:  一:3 弹簧关节 (Spring Joint 2D) 功能: 适用场景: 1. 弹性绳索或弹簧: 2. 弹性

图形API学习工程(0):工程目的环境配置

工程目的 我想要不借助引擎,而直接使用底层图形API(如DirectX和OpenGL等)来生成图像。 我认为这将有利于图形学算法与渲染框架相关的学习,因为: 游戏引擎往往对渲染进行了豪华的封装,而不利于看到图形学算法本质。UE4虽然开放了源代码,但是想要完全掌握渲染方面的代码也需要较高成本。 另外,我想对不止一个主流API进行封装,而是多个图形API进行封装,包括: OpenGLD3D1

公司数字化转型的目的是什么?

不同行业公司,其数字化转型的目的也不一样。下面我列举几个行业,给大家讲讲其数字化转型的真正目的。 制造数字化转型 制造业来说,数字化转型的本质是通过新一代信息技术与制造技术的融合,实现以数据为核心的资源要素变革、以网络化为牵引的生产方式重构、以扁平化为方向的企业形态转型、以平台赋能为导向的业务模式创新;构建全感知、全联接、全场景、全智能的数字工厂,优化产品的研发生产和营销流程,对传统管

读软件设计的要素02概念的目的

1. 要素 1.1. 概念的定义包括名称、目的、状态、操作和操作原则 1.2. 操作原则(operational principle) 1.2.1. 操作原则用于展示如何通过操作实现目的,这是理解概念的关键 1.2.2. 展示如何通过操作的组合实现概念的目的,包含一个或多个典型的使用场景 1.2.3. 操作原则并没有增加任何信息,因为你完全可以从操作规范中推理出任何使用场景 1

行空板上YOLO和Mediapipe视频物体检测的测试

Introduction 经过前面三篇教程帖子(yolov8n在行空板上的运行(中文),yolov10n在行空板上的运行(中文),Mediapipe在行空板上的运行(中文))的介绍,我们对如何使用官方代码在行空板上运行物体检测的AI模型有了基本的概念,并对常见的模型进行了简单的测试和对比。 在行空板上YOLO和Mediapipe图片物体检测的测试(中文)中我们对于行空板上使用YOLO和Medi

redis缓存的目的、场景、实现、一致性问题

文章目录 1、加缓存的目的(作用):2、加缓存的场景:读多写少3、加不加缓存的标准:4、缓存的实现:5、缓存的实现方案:6、缓存的粒度问题7、缓存的一致性问题 专辑详情和声音详情属于并发量较高的数据,如果每次访问都实时到数据库获取数据,数据库的访问压力太大。而这些信息一般更新的频率比较低,短时间内不会发生改变。因此,我们可以考虑在前台系统中,增加一层缓存,把这些数据缓存起来,请求到来

物体重识别

物体重识别(Object Re-identification,简称Re-ID)是一种计算机视觉任务,旨在通过识别和匹配不同视角或不同时间拍摄的同一物体,从而实现对该物体的再识别。这个任务通常涉及对物体特征进行提取和匹配,以在复杂的环境中准确地识别和跟踪目标。 在物体重识别中,视觉Transformer(ViT)是一种新兴的技术,其通过自注意力机制来处理图像数据。然而,ViT存在一个问题,即它容易