控制物体的运动-第九作坊物理运动引擎介绍

原创 2007年10月12日 17:35:00
 
 
游戏引擎的基本功能除了渲染以外最重要的就是物理运算,因为引擎不光要把物体“画”出来,还要在指定的位置,指定的大小,按照指定的姿态将物体正确的画出来。这些任务都是由物理运算完成的。引擎的物理运算都是在物理层完成的,物理对象决定渲染对象的物理属性。下面首先从最基本的刚体运动开始。
1.  刚体运动
刚体运动将所有物体看作不会发生形变的实体,对其进行的各种运算只需要考虑位移和旋转即可。所有刚体运动的内容都在Phyical_FRU中实现,除了位移和旋转之外该类也提供了缩放的功能,以便于调整物体的大小。“FRU”指的是该物理对象采用了三根基准轴:Front,Right,Up。这三根轴是执行位移变换的基准,旋转变换会直接应用到这三根轴上,再由这三根轴生成旋转矩阵。最终的世界矩阵由旋转矩阵*缩放矩阵*位移矩阵获得。

下面列出基础性的代码片段。

D3DXMatrixTranslation(&MatTranslation,NowState.position.x,NowState.position.y,NowState.position.z);
D3DXMatrixScaling(&MatScale,NowState.Scale.x,NowState.Scale.y,NowState.Scale.z);
MatWorld=MatRotation*MatScale*MatTranslation ;

     生成位移变换矩阵
     生成缩放变换矩阵。
     将旋转、位移、缩放组合在一起。
 
下面具体说明如何使用基准轴生成旋转矩阵:
 
这里4行代码用于使用基准轴构造渲染矩阵。旋转矩阵的“格式”如下:
 

front.x, right.x, up.x , 0
front.y, right.y, up.y , 0
front.z, right.z, up.z, 0
0,     0,     0,   1

 

D3DXMATRIX mat;
mat._11=Front.x;mat._21=Front.y;mat._31=Front.z;mat._41=0;
mat._12=Right.x;mat._22=Right.y;mat._32=Right.z;mat._42=0;
mat._13=Up.x;mat._23=Up.y;mat._33=Up.z;mat._43=0;
mat._14=0;mat._24=0;mat._34=0;mat._44=1;
D3DXMatrixTranspose(&MatRotation,&mat);

     按照这种方式构造旋转矩阵将使得物体“面向”Front所指的方向。

② 转置,以便和其他变换矩阵相乘。

D3DXMatrixRotationAxis(&mat,&Front,NowState.FrontAngle);
MatRotation*=mat;
D3DXVec3TransformCoord(&Right,&Right,&mat);
D3DXVec3TransformCoord(&Up,&Up,&mat);
D3DXVec3TransformCoord(&Front,&Front,&mat);

只要每侦都执行上面的代码就可以保证旋转矩阵和基准轴保持同步。这样在发生旋转变换时
只要变换基准轴就可以了。下面的代码对基准轴进行变换,实现指定角度的翻滚。 
 
     D3DXMatrixRotationAxis可以绕任意轴旋转的矩阵,第一个参数输出结果;第二个参数为旋转轴,这里直接使用基准轴Front,绕Front轴旋转的结果就是翻滚;第三个参数为旋转角度。
     将新的旋转矩阵叠加到当前的旋转矩阵上。
     使用新矩阵变换现有的基准轴,D3DXVec3TransformCoord用于变换3D向量。
图2-16显示了一个FRU物体进行俯仰、偏转、翻滚变换的情况。
到此为止,物体状态的设置就可以完成了。但是,这样还不够,因为游戏最终需要的是一个运动过程。为了对动态的过程进行描述和操作,在Phyical_FRU加入了两个状态的集合:NowState,NewState,它们都是FRUState结构的实例,FRUState结构包含了足以描述各种刚体运动状态的数据。NowState记录了当前时刻的运动状态,NewState记录了预计在一定时间内将要达到的运动状态。程序每一帧都会在两个状态之间插值以决定当前时刻的运动状态。当需要物体做出某种运动时,只要修改NewState的相关数值,并设定预计完成该动作的时间即可。
 
上图分别是一个游戏实体做出俯仰、偏转、翻滚变换的情况。
 
2 . 碰撞与反弹
游戏实体在运动中应该受到物理定律的约束,这样才能带来真实的游戏体验。但是,由于时间关系,本课题只实现了最基本的物理现象模拟:碰撞。
2.1碰撞检测
在若干个多边形之间检测有没有发生碰撞绝对不像“看”起来那么简单。因为游戏实体的形状是没有特定规律可寻的,而且每个游戏实体都可能由成千上万个多边形组成,在这成千上万个多边形之间执行“严格”的检测绝对不是现在的家用计算机能够胜任的。另一方面,游戏过程中也没有必要进行如此精确的碰撞检测。所以使用包围盒进行碰撞检测就是一种比较“合算”的方法。但是只进行包围盒对包围盒的碰撞检测也是不够的,因为这样会忽略复杂物体表面的细节,产生很不自然的结果。所以,在编写碰撞检测时使用多种碰撞检测方式结合的方法往往可以带来最理想的结果。
在Phyical_Collision中实现了碰撞检测所需要的各种方法。碰撞检测的对象被分为碰撞主体和碰撞客体,碰撞主体必须为包围盒,这样可以避免在多边形之间进行碰撞检测;碰撞客体可以为包围盒也可以为多边形,但是碰撞客体的包围盒必须是“轴向”的(包围盒的所有边都和相应坐标轴平行)。这样整个碰撞检测的过程就可以分为包围盒对包围盒的碰撞以及包围盒对多边形的碰撞。
包围盒对包围盒的碰撞十分简单,只要判断碰撞主体的包围盒顶点是否在客体的最大点和最小点之间,能够这么做是因为客体使用“轴向”包围盒。
而包围盒对多边形的碰撞检测就相对复杂的多。为了加快运算速度,避免不必要的碰撞检测,可以考虑使用两极碰撞检测。具体的说就是先进行包围盒对包围盒的碰撞,当碰撞发生时再进行包围盒对多边形的碰撞检测。 上图可以看到碰撞检测时使用的包围盒、碰撞光线、以及碰撞点的法线。 
下面的伪码描述包围盒对多边形的碰撞检测过程。

For(碰撞主体每个包围盒的顶点)
{
以当前顶点为原点,向当前移动方向发射一条射线。
使用D3DXIntersect判断该射线是否穿过碰撞客体。
If(穿过)
计算交点到当前顶点的距离D。
If(D>碰撞主体的半径)继续下一个顶点
Else
{
出现碰撞,获得与射线相交的三角形序号
利用索引缓冲获得三角形顶点序号
利用三角形顶点序号访问顶点缓冲
获得每个顶点的法线信息
利用顶点法线插值计算交点法线
和其他信息一起添加到碰撞队列中①
返回真
}
}
Else
{继续下一个顶点}
}

 
①碰撞队列用于保存当前侦发生的碰撞信息,该队列由Physical _Manager管理,在每一侦开始前被清空。该队列的数据将在计算摩擦反弹以及处理游戏逻辑时使用。
 
  
2.2 反弹和摩擦
在碰撞检测中得到的碰撞点法线信息可以被用于计算碰撞发生后物体的运动方向。碰撞发生后可能会有两种极端的情况:1.沿着法线的方向移动(完全反弹) 2.沿着切线方向移动(完全摩擦)。这里可以使用摩擦系数和反弹系数来控制物体碰撞后的走向。下面的代码片段用于计算碰撞发生后的反弹方向:

D3DXVECTOR3 refdirNormalized,refdir,normalvel,transformvel,DirectionNormalized;
float normalfac,length;
D3DXVec3Normalize(&DirectionNormalized,&direction);
D3DXVec3Normalize(&Normal,&Normal);
refdirNormalized=DirectionNormalized+
Normal*(-2.0f*D3DXVec3Dot(&Normal,&DirectionNormalized ));
D3DXVec3Normalize(&refdirNormalized,&refdirNormalized);
 D3DXVECTOR3 NormalizedPart,TangentPart;
 float DotNR=D3DXVec3Dot(&Normal,&refdirNormalized);
 if(DotNR<=0)return D3DXVECTOR3(0,0,0);
NormalizedPart=Normal*DotNR;
TangentPart=refdirNormalized-NormalizedPart; 
 refdir=bumpfac*NormalizedPart+TangentPart*frictionfac
        
     计算反弹方向,该方向为摩擦系数等于反弹系数时的运动方向。

     利用法线和反弹方向的点乘判断反弹方向是否保持在物体的正面。
     计算法线方向上的反弹分量。
     计算切线方向上的摩擦分量。
     利用摩擦系数和反弹系数算出最终的移动方向。
通过修改摩擦系数和反弹系数就可以适应不同情况的要求了。
 

【Cocos2d-x】物理引擎使用入门

相关概念 什么是物理引擎? 科学模型:科学研究中对事物的合理简化。 物理引擎是一个计算机程序模拟牛顿力学模型,使用质量、速度、摩擦力和空气阻力等变量。 可以用来预测这种不同情况下的效果。它主要...
  • linchaolong
  • linchaolong
  • 2015年01月12日 02:07
  • 2692

opencv检测运动物体的基础_特征提取

特征提取是计算机视觉和图像处理中的一个概念。它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。特征提取的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连...
  • u014328353
  • u014328353
  • 2015年12月18日 11:08
  • 1160

基于OpenCv的运动物体检测算法

基于一个实现的基于OpenCv的运动物体检测算法,可以用于检测行人或者其他运动物体。 #include #include #include #include ...
  • llp1992
  • llp1992
  • 2015年01月24日 16:14
  • 5249

opencv实现运动追踪(2)

简介   本篇继续讲解opencv上使用BackgroundSubtractorGMG,进行运动物体跟踪,并将跟踪到运动物体用圆框选起来。本篇是基于opecncv官方实例: bgfg_gmg.cpp...
  • u011630458
  • u011630458
  • 2015年05月21日 19:00
  • 8002

读视频文件和运动物体检测

例程 来自于仕琪的讲稿《使用OpenCV进行图像处理》中的例程 简要说明:本程序 尝试打开本电脑上的摄像头作为视频输入设备,或者将命令行的输入参数作为文件名来打开的视频文件。不管是哪一种方法,最后...
  • mirkerson
  • mirkerson
  • 2014年07月26日 16:21
  • 1483

【OpenCV学习笔记】三十九、运动物体检测(一)

运动物体检测(一) 1.背景减法 2.运动物体检测——帧差法
  • abc8730866
  • abc8730866
  • 2017年04月14日 11:09
  • 5581

运动物体检测与跟踪——累积权重构建背景模型

运动物体检测与跟踪中的帧差分法,除了相邻帧差分法和三帧差分法外,还有一种差分方法,可以通过建立不含前景的背景模型,用当前帧和背景模型做差,差值就可以体现运动物体大概的位置和大小信息。 相比相邻帧差分法...
  • dcrmg
  • dcrmg
  • 2016年08月21日 00:25
  • 2387

Unity 实现 曲线运动轨迹(也可以攻击曲线标志等曲线)

之前有个需求 屏幕上用鼠标拖动然后就能射出箭 箭随着标线运动 之前想麻烦了  以为贝塞尔曲线能够完成 后来发现 完全不对劲 直接运用最基础的物理知识即可 例如 要实现曲线运动 给定一个点 pos和 方...
  • u013617409
  • u013617409
  • 2017年12月14日 22:35
  • 153

运动图像分割

简介   最近在继续看《数字图像处理》,发现上面一个分割运动图像的案例,用简单的代码实现,并整理了出来。 原理介绍   该方式主要是用在监控上面,用来处理在监控画面中运动的物体。原理可以大致为比较...
  • u011630458
  • u011630458
  • 2016年01月12日 20:11
  • 1457

Unity中物体运动方法总结

简介在Unity3D中,有多种方式可以改变物体的坐标,实现移动的目的,其本质是每帧修改物体的position。 通过Transform组件移动物体Transform 组件用于描述物体在空间中的状态,它...
  • UIUCGOGOGO
  • UIUCGOGOGO
  • 2017年07月19日 15:21
  • 841
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:控制物体的运动-第九作坊物理运动引擎介绍
举报原因:
原因补充:

(最多只允许输入30个字)