unity3d collider的wheelcollider轮胎锁死问题

Unity3D教程:车辆性能算法 | Unity3D教程手册
当前位置 :
>> Unity3D教程:车辆性能算法
Unity3D教程:车辆性能算法
首先要了解真实车辆的原理:车辆分前轮驱动,后轮驱动和四驱动。动力由引擎提供,反应的力到轮胎上,因此产生转数,即RPM。引擎的功率可以由RPM得到公式为 : RPM = 引擎功率×60/2×pi , 这些都是模拟,只为了更好的为下面的动作服务。还有大众关心的“漂移” ,所谓 漂移就是,在后驱车辆中,前轮方向旋转大角度,地面给于一定向心力,同时后轮又给予更多动力,导致“漂移”动作。
首先,车辆不可能整个套一个外壳,原因是在接触地面时,对车辆所使的力不可能达到你预期的目标,引起,必须在车辆轮胎以上做外壳碰撞,轮胎以下就需要有力来支持它始终保持不掉下来。
Unity3D中有个WheelCollider , 它是专门模拟轮胎支持力和轮胎转数,以及轮胎横向力,前进力,以及悬架避震系统。这个东西非常方便,只要你把这个东西套在4个轮胎上,调试下他的forwardFriction 和 sidewaysFriction达到你想要的效果,然后对驱动轮的motorTorque进行赋值,你的车辆就能动了。
记得你需要无数次调试 前进摩擦力和横向摩擦力 。 至于悬架系统在你需要时也可以改变其值。还有,这两个摩擦力,是一个由低到高,再由高到稳定的一条曲线。
这个WheelCollider非常好用,曾一度沉迷于此。但后来发现,他有很多不合理的地方。想要得到最好的效果,还是抛弃了他。为了支持车辆的碰撞外壳不接触地面,必须写一个悬架动态支持力,在4个轮胎位置,支持整辆车悬浮于地面之上。
关于这个悬架动态支持力:
&&&01void SuspensionHoldForce()02{03
float fullCompressionSpringForce = this.rigidbody.mass * 0.25f * 2.0f * -Physics.gravity.y;04
this.OnGround = true;05&06
foreach( GameObject item in FwheelModels )07
RaycastHit hit;09
bool onGround = Physics.Raycast( item.transform.parent.position , -item.transform.parent.InverseTransformDirection(Vector3.up), out hit, this.suspensionTravel + this.radius);10&11
if (onGround && hit.collider.isTrigger)12
onGround = false;14
float dist = this.suspensionTravel + this.radius;15
RaycastHit[] hits = Physics.RaycastAll( item.transform.parent.position , -item.transform.parent.InverseTransformDirection(Vector3.up) , this.suspensionTravel + this.radius );16
foreach(RaycastHit test in hits)17
if (!test.collider.isTrigger && test.distance &= dist)19
hit = test;21
onGround = true;22
dist = test.distance;23
}26&27
if( onGround )28
Vector3 wheelVelo = this.rigidbody.GetPointVelocity (item.transform.parent.position);30
Vector3 localVelo = transform.InverseTransformDirection (wheelVelo);31
Vector3 groundNormal = transform.InverseTransformDirection (hit.normal);32
float damperForce = Vector3.Dot(localVelo, groundNormal) * 5000f;33
float compression = 1.0f - ((hit.distance - radius) / suspensionTravel);34
Vector3 springForce = ( fullCompressionSpringForce*compression - damperForce ) * item.transform.parent.InverseTransformDirection(Vector3.up);35&36
springForce.z = springForce.x = 0f;37&38
this.rigidbody.AddForceAtPosition( springForce , item.transform.parent.position );39&40
this.OnGround = false;44
}46&47
foreach( GameObject item in BwheelModels )48
RaycastHit hit;50
bool onGround = Physics.Raycast(
item.transform.parent.position, -item.transform.parent.InverseTransformDirection(Vector3.up), out hit, this.suspensionTravel + this.radius);51&52
if (onGround && hit.collider.isTrigger)53
onGround = false;55
float dist = this.suspensionTravel + this.radius;56
RaycastHit[] hits = Physics.RaycastAll( item.transform.parent.position, -item.transform.parent.InverseTransformDirection(Vector3.up) , this.suspensionTravel + this.radius );57
foreach(RaycastHit test in hits)58
if (!test.collider.isTrigger && test.distance &= dist)60
hit = test;62
onGround = true;63
dist = test.distance;64
}67&68
if( onGround )69
Vector3 wheelVelo = this.rigidbody.GetPointVelocity (item.transform.parent.position);71
Vector3 localVelo = transform.InverseTransformDirection (wheelVelo);72
Vector3 groundNormal = transform.InverseTransformDirection (hit.normal);73
float damperForce = Vector3.Dot(localVelo, groundNormal) * 5000f;74
float compression = 1.0f - ( ( hit.distance - radius ) / suspensionTravel );75
Vector3 springForce = ( fullCompressionSpringForce*compression - damperForce ) * item.transform.parent.InverseTransformDirection(Vector3.up);76
springForce.z = springForce.x = 0f;77
this.rigidbody.AddForceAtPosition( springForce , item.transform.parent.position );78
this.OnGround = false;82
}84}
那么在完成悬架支撑后,就该设计车辆动力了。
这里也有2种方法:一个方向是真实车辆行驶轨迹,另一个是模拟型车辆轨迹。
前者的方法是 , 将动力点放在车辆驱动轮上,例如后轮。用rigidbody的AddForceAtPosition可以做到,前轮只需要提供横向力就可以实现转弯的轨迹。但别看说说这么容易,这里面还涉及非常多的数值和曲线问题。在提供车辆动力时,你需要一条曲线,以致车辆不会匀加速,因为这样很不真实,还有在前轮横向力中,你必需是条由0到最高点,然后下降到平衡点的曲线。这样你的赛车才显得更真实。这些都需要用到几个数学知识。Unity3D教程手册
后者,是用算法来模拟的一种车辆轨迹。这个算法所有作用力作用在车辆的中心点。
转弯轨迹,我是用转弯半径来表示,使得车辆在转弯时有相当的真实性,必须改变车辆转弯速度。当然,用到了些数学知识。代码如下:
&&&01#region 计算转弯角度02void Steering( bool canSteer , Vector3 relativeVelocity )03{04
if( canSteer && this.OnGround )05
if( this.shiftthrottle == 1 )07
this.transform.RotateAround( this.transform.TransformPoint( ( this.FwheelModels[0].transform.localPosition + this.FwheelModels[1].transform.localPosition) * 0.5f ) , this.transform.up , this.rigidbody.velocity.magnitude *2f* this.steeringInput * Time.deltaTime * 2f );09
//~ this.rigidbody.AddForceAtPosition( this.FwheelModels[0].transform.TransformDirection(Vector3.right*this.steeringInput) * 3f * this.rigidbody.mass, this.FwheelModels[0].transform.position);10
//~ this.rigidbody.AddForceAtPosition( this.FwheelModels[1].transform.TransformDirection(Vector3.right*this.steeringInput) * 3f * this.rigidbody.mass, this.FwheelModels[1].transform.position);11
return ;12
}13&14
if( this.throttle * this.transform.InverseTransformDirection(this.rigidbody.velocity).z & 0 )15
return ;16&17
float turnRadius = 3.0f / Mathf.Sin( (90f - this.steering) * Mathf.Deg2Rad );18
float minMaxTurn = EvaluateSpeedToTurn(this.rigidbody.velocity.magnitude);19
float turnSpeed = Mathf.Clamp(relativeVelocity.z / turnRadius, -minMaxTurn / 10, minMaxTurn / 10);20
this.transform.RotateAround( this.transform.position + this.transform.right * turnRadius * this.steeringInput , transform.up , turnSpeed * Mathf.Rad2Deg * Time.deltaTime * this.steeringInput );21&22
//~ Vector3 debugStartPoint = transform.position + transform.right * turnRadius * this.steeringI23
//~ Vector3 debugEndPoint = debugStartPoint + Vector3.up * 5f;24&25
//~ Debug.DrawLine(debugStartPoint, debugEndPoint, Color.red);26
}27}28&29float EvaluateSpeedToTurn( float speed )30{31
if(speed & this.topSpeed / 2)32
return minimumTurn;33
float speedIndex = 1 - ( speed / ( this.topSpeed / 2 ) );34
return minimumTurn + speedIndex * (maximumTurn - minimumTurn);35}36#endregion
这个模拟车辆轨迹,不能达到漂移的性能,但我加了一个滑动比例计算的算法,用车辆横向移动速度,和前进速度,的比例来确定,该车辆是否处于漂移状态,如处于,则启动漂移滑动程序。当然,我的赛车是很自然的,不做做。至于轮胎痕迹,就是判断是否触底后,在该点生成轮胎痕迹gameobject,如此而已。Unity3D教程手册
最后,再介绍下,所有车辆都需要模拟的,行驶时,轮胎随速度旋转这个关系到车辆看起来真实性的东西。其实非常简单。代码如下:
&&&01#region 轮胎滚动与旋转模拟02void WheelRoll()03{04
float averageAngularVelo = ( this.rigidbody.GetPointVelocity(this.BwheelModels[0].transform.parent.position).magnitude + this.rigidbody.GetPointVelocity(this.BwheelModels[0].transform.parent.position).magnitude )/2f;05
float engineAngularVelo = averageAngularVelo * 3f;06&07
float rpm = engineAngularVelo * (60.0f/(2*Mathf.PI)) * (this.transform.InverseTransformDirection(this.rigidbody.velocity).z & 0f ? 1f : -1f );08&09
//~ Debug.Log(this.transform.InverseTransformDirection(this.rigidbody.velocity).z);10&11
FwheelModels[0].transform.rotation = FwheelModels[0].transform.parent.rotation *
Quaternion.Euler (RotationValue, this.steering , 0);//旋转12
FwheelModels[1].transform.rotation = FwheelModels[1].transform.parent.rotation * Quaternion.Euler (RotationValue, this.steering , 0);//旋转13&14
BwheelModels[0].transform.rotation = BwheelModels[0].transform.parent.rotation * Quaternion.Euler (RotationValue, 0, 0);//旋转15
BwheelModels[1].transform.rotation = BwheelModels[1].transform.parent.rotation * Quaternion.Euler (RotationValue, 0, 0);//旋转16&17
RotationValue += rpm * ( 360f/60f ) * Time.deltaTime;18}19#endregion
【上一篇】
【下一篇】
您可能还会对这些文章感兴趣!1061人阅读
最近接手了一个汽车相关的项目,要求实现汽车的基本运动控制,我使用了WheelCollider组件来实现4个轮子的驱动,但是当我在制作过程中遇到了一些麻烦。
麻烦1:Unity4.x中的WheelCollider和5.x中的WheelCollider属性是不同的,两者的ExtremumValue属性代表的意义也是不一样的,这样会很难升级。
麻烦2:Unity官方文档并没有对ExtremumSlip,ExtremumValue,AsymptoteSlip,AsymptoteValue这4个属性做出详细的说明,我们不知道他们所代表的数学意义,而且我们不知道他们的取值范围和单位。
来张截图对比一下:
相信很多使用Unity制作汽车类项目的人一定遇到了这些问题,尤其是不知道他们的单位,搞得无从下手,百度无果之后,无奈之下,我只好找到了汽车工程学里轮胎动力学的相关资料,总算是有了一些眉目。
轮胎动力学里介绍,Slip与Value实际代表了“滑动率”与“地面制动力系数”。
滑动率表示车轮运动成份所占的比例,用公式S=(uw-r*ww)/uw*100%来表示。
其中uw表示车轮中(轴)心速度,r表示车轮的半径,ww表示车轮的角速度。
滚动状态时:车轮中心速度uw约=r*ww
制动力增加时:uw&&r*ww
抱死拖滑时:ww=0,此时出于完全滑行,S=1
所以,S的取值范围为0到1
地面制动力系数:
1:此系数与制动器制动力,地面附着系数,地面法向反作用力有关。
制动器制动力可以理解为踏板施加的力。
以下是参考资料:
由此可知Fb的取值范围为0到最大地面附着力。
2:地面附着系数与路况,汽车当前运动速度,以及轮胎结构,花纹,材料等因素有关。
路况,我们可以简单的理解是不同路面的一种系数,比如雪地,泥泞路面。
而轮胎结构花纹材料,我们可以统一由一个系数来表示,叫做轮胎的摩擦性质。
这些值可以查表得到:
3:地面法向反作用力,暂时可以简单的理解为地面坡度支撑力在水平方向上的力的分量,具体的求法,请百度。
以下是制动力系数与法向反作用力之间的关系:
地面制动力系数为Tb
地面制动力因子为Fb
制动器制动力因子为Fu
地面法向反作用力因子为Fz
轮胎材质系数因子为Ts
路况系数因子为Tl
那么Tb可以表示为Fb/Fz,即Fu*Ts*Tl/Fz,先不考虑他们的取值范围和混合情况。
最后Tb与S之间的关系可以表示为Tb=F(S),其中F表示曲线函数。
细化一下:Fu*Ts*Tl/Fz=F((uw-r*ww)/uw*100%)
下边就是Tb与S之间的曲线图,大家有没有发现,这个图是不是跟Unity官方api里介绍的那个图很像啊?
通过以上讲解,我们回答了最初的问题
麻烦1:Unity4.x中的ExtremumValue属性,实际上是不符合现实中汽车轮胎动力学的意义的,所以我推测在4.x中Value值应该是一个不受限制的力,后来Unity5.x把它改的更有意义了一些(至少是粗略上的),。
麻烦2:Unity官方的曲线图意义可以由Fu*Ts*Tl/Fz=F((uw-r*ww)/uw*100%)公式来表示。
我们已经知道了ExtremumSlip,ExtremumValue,AsymptoteSlip,AsymptoteValue的实际含义,单位,和取值范围,并且还得到了一个理论公式,可是我们仍然不知道该怎么去实现。
问题1:地面制动力系数,要通过地面摩擦性质,当前车速,轮胎材质,通过查表才能得到,这样每时每刻的去通过复杂参数来查,效率会很差。
问题2:滑动率,我们也要由当前的轮轴速度,当前的角速度来计算,效率也会差。
问题3:我们虽然列出了理论公式,但是我们并不知道每个因子在其中发挥作用的大小,也就是说,我们还不知道他们的取值范围和影响的权重,而且理论值与物理引擎还有一定差距,所以我们还要加入这个差距系数。
问题4:Unity的WheelCollider只提供给我们ExtremumSlip,ExtremumValue,AsymptoteSlip,AsymptoteValue4个属性值,也就是说无论我们公式多么复杂,最终还是要反映到Tb、S这个曲线上,也就是说要模拟出一个Tb,S的曲线图,然后通过这4个属性的设定,Unity的物理引擎内部会黑盒计算(个人猜测)。
最后得出结论,我们需要简化因子,简化计算,在实际项目中,我们可能只会参考路况,轮胎材质对曲线的影响。
我们忽略车速对地面附着力系数的影响。
像轮轴速度,车轮角速度,我们可以简单的认为他们由物理引擎自己来即时计算完成。地面法向反作用力,我们始终认为是1(相当于忽略这个因素)。
我们也忽略制动器因速度,此动态值可以由物理引擎来计算。
现在,我们只需要通过地面材质参数就可以查表得到地面附着力系数。
此时,地面制动力系数就Tb就受&F(Tl)*Ts影响,其中F为查表操作。
这样我们只要设定一个基准的模拟ExtremumSlip,ExtremumValue的表,然后只要ExtremumValue*F(Tl)*Ts就可以得到可操作的函数值。
通过图4-5,我们知道,实际,x,y轴的取值范围都是0到1,表4-2中的值也是0到1,那么我们只需要限定Ts也在0到1,就可以得到一个符合范围要求的ExtremumValue值了,当然了,为了让物理引擎的效果与现实中的效果差不多,可能还需要加入一个系数T。
上边就变成了ExtremumValue*F(Tl)*Ts*T。
下面附上参考资料:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:19441次
排名:千里之外
原创:20篇
(3)(10)(2)(1)(1)(1)(1)(1)(1)主题 : 车轮碰撞(WheelCollider)之间怎么检测?
级别: 骑士
可可豆: 1539 CB
威望: 1539 点
在线时间: 120(时)
发自: Web Page
来源于&&分类
车轮碰撞(WheelCollider)之间怎么检测?&&&
给某个车轮上加了段代码貌似OnCollisionEnter只可以检测到车轮与地面(BoxCollider)之间的碰撞~但对其他的WheelCollider并无反应~~
欢迎真心喜欢技术的人加我qq,方便交流,其他的就不必了。。。
级别: 新手上路
可可豆: 180 CB
威望: 180 点
在线时间: 10(时)
发自: Web Page
......这个貌似是木有的吧只能对车身进行检测,或者你写个脚本判断两者同一平面和坐标距离即可实现。。。
级别: 侠客
可可豆: 520 CB
威望: 520 点
在线时间: 3(时)
发自: Web Page
一楼正解。。还真的没有
级别: 骑士
可可豆: 1539 CB
威望: 1539 点
在线时间: 120(时)
发自: Web Page
呀。。。&& 嗯~~后来我给车身和车轮加了个BoxCollider..谢谢楼上二位~~~
欢迎真心喜欢技术的人加我qq,方便交流,其他的就不必了。。。
关注本帖(如果有新回复会站内信通知您)
苹果公司现任CEO是谁?2字 正确答案:库克
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 浏览移动版WheelCollider相关问题【unity3d吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:74,250贴子:
WheelCollider相关问题收藏
我在制作一个坦克模型,给坦克轮子加上WheelCollider之后,在运行中发现,当车辆并非完全静止的时候(即震动、轻微位移(旋转不算)),给车辆施加向前推力或向后拉力车辆均可移动,但是如果车辆完全静止(即不震动、不位移),这时候给车辆添加力虽然坐标显示的数字会有变化但是在实际场景中坦克将无法起步,如果加大推力,坦克会被推得几乎竖起来,然后才会正常运动,有没有吧友遇到过类似的情况呢?是如何解决的呢?求解答
自己顶一下
怕不是刚体质量太小
不知道你为什么非要轮子转动。把坦克的轮子做成动画,再移动不就可以了
登录百度帐号推荐应用

我要回帖

更多关于 unity3d collider 的文章

 

随机推荐