|
1.先创建一个大脚车的简单模型,要有必要的部件,例如四个轮子及轴和车身。效果测试满意后可以用细模替代。再创建一块崎岖的地面。 
2.创建四个长方体,作为轮子位置的参考物。 3.将四个长方体与地面进行几何体和法线约束,然后调整到车轮的位置。 
如图。 
4.定义轮子相对各自参考物的倾斜角,如下: $a[1]=a1.translateY; $a[2]=a2.translateY; $a[3]=b1.translateY; $a[4]=b2.translateY; wheel_r1.rotateX=clamp(max((-$angerWu1+85),(b1.rotateX+90)), min((-$angerWu1+120),(b1.rotateX+90)),(b1.rotateX+90));
wheel_r2.rotateX=clamp(max((-$angerWu2+85),(b2.rotateX+90)), min((-$angerWu1+120),(b2.rotateX+90)),(b2.rotateX+90));
wheel_l1.rotateX=clamp(max((-$angerWu1+85),(a1.rotateX+90)), min((-$angerWu2+120),(a1.rotateX+90)),(a1.rotateX+90));
wheel_l2.rotateX=clamp(max((-$angerWu2+85),(a2.rotateX+90)), min((-$angerWu2+120),(a2.rotateX+90)),(a2.rotateX+90));
$a[1]-$a[4]表示四个轮子参考物的y轴向的位置。$angerWu1,$angerWu2表示轮轴的倾斜角,以上命令是控制轮子一方面受地形影响一方面受轮轴角度限制。关于clamp函数参考帮助文件。
5.定义轮子和车身x,z轴向的位置:具体命令如下:
wheel_r1.translateX=b1.translateX; wheel_r2.translateX=b2.translateX; wheel_l1.translateX=a1.translateX; wheel_l2.translateX=a2.translateX; wheel_r1.translateZ=b1.translateZ; wheel_r2.translateZ=b2.translateZ; wheel_l1.translateZ=a1.translateZ; wheel_l2.translateZ=a2.translateZ; body.translateX=(wheel_l1.translateX+wheel_l2.translateX+wheel_r1.translateX+wheel_r2.translateX)/4; body.translateZ=(wheel_l1.translateZ+wheel_l2.translateZ+wheel_r1.translateZ+wheel_r2.translateZ)/4; 轮子位置为其各自参照物位置控制。车身位置是近似计算,简单的说,车身就是取四个轮子空间位置的平均值。
6.定义四个轮子中心的y轴向的初始位置。 if(frame==1) { $nb=$nu=$nv=0; $Awy[1]=$Awy[2]=$Awy[3]=$Awy[4]=$Aby=0; $Twyv=$Vwy[1]=$Vwy[2]=$Vwy[3]=$Vwy[4]=$Vby=0; $Twy[1]=a1.translateY+1.4; $Twy[2]=a2.translateY+1.4; $Twy[3]=b1.translateY+1.4; $Twy[4]=b2.translateY+1.4; 1.4为轮子受车身及自身重力后离地面的高度。
7.定义四轮构成体系($angerWu,$angerWv)的横向和纵向的倾斜角,定义车身($angerBu,$angerBv)的横向和纵向的倾斜角。 $abu=$abv=$awu=$awv=0; $vbu=$vbv=0; $u=$v=0; $twu=($Twy[1]+$Twy[2])-($Twy[3]+$Twy[4]); $twv=($Twy[1]+$Twy[3])-($Twy[4]+$Twy[2]); $angerWu=-asind($twu/8); $angerWv=-asind($twv/10); $angerBu=$angerWu; $angerBv=$angerWv; 8.定义车身的y轴向的初始位置 $Twyv=($Twy[1]+$Twy[2]+$Twy[3]+$Twy[4])/4; $Tby=$Twyv+4.0;
9.计算四个轮子的y轴向的位移,其中轮子所受到的压力为y轴向车身和自身的位移加速度和重力的影响而计算得出,车轮与地面的高度受压力影响,压力大时车轮与地面相对距离减小,压力小时车轮与地面相对距离加大。模拟轮胎受压变形。未考虑车身角度倾斜和车身转动的扭矩的影响。对于地形特别崎岖的环境,这将有较大的误差。 if(frame>1) { for($i=1;$i<5;$i++) { $Twa[$i]=$Twy[$i]-$a[$i]-1.4; $Fw[$i]=1*$M*$Aby/4+1*$M*$au[$i]+1*$M*$av[$i]; if($Twa[$i]>0.1) $Nw[$i]=-0.2*$kw*($Twa[$i]/0.5) ; else $Nw[$i]=-1*$kw*$Twa[$i]*abs($Twa[$i]/0.5);//定义不同情况下的支持力计算方法,没办法,一时没有精确的算法,按线性比例和平方比及指数关系都会出问题。 $Awy[$i]=($Nw[$i]-$Fw[$i])/$m;//轮子加速度 $Awy[$i]=clamp(-1000,1000,$Awy[$i]);//限制加速度最大值 $Vwy[$i]=($Vwy[$i]+1.5*$Awy[$i]*$t)*1.0-$Vwy[$i]*0.2; $Twy[$i]=$Twy[$i]+$Vwy[$i]*$t+0.5*$Awy[$i]*$t*$t;//y轴位置。
避免轮子小幅度的长久的震荡。当其位移变化幅度小(0.03)时,强制其静止。其中$nw[$i]是计数器,记录连续小幅度位移(小于0.03)变化的帧数,在这我定义的为15帧。 if(abs($Twa[$i])<0.03) $nw[$i]+=1; else $nw[$i]=0; if($nw[$i]<15) $Twy[$i]=$Twy[$i]; else $Twy[$i]=$a[$i]+1.4;
下面这一段限制了轮子与车身的最大位移量及限制了前后帧间轮子位移变化的极限值,这些限制在大脚车高速在起伏比较大的地面上行驶时有用,若低速行驶,可以不考虑这些限制。 $Twy[$i]=clamp($Tby-5,$Tby-3,$Twy[$i]); if($Twa[$i]<-0.1) $Twy[$i]=$a[$i]+1.3;
$Twy[$i]=clamp($T[$i]-0.4,$T[$i]+0.4,$Twy[$i]); $T[$i]=$Twy[$i];
避免车身小幅度的长久的震荡。当其长时间(15帧)位移变化幅度小(0.03)时,强制其相对四个轮子构成的系统静止($Tby=$Twyv+4;)。 其中$nb是计数器,记录车身小幅度位移变化的帧数,我定义的为15帧。另外下面的程序定义了车身的位移加速度和速度的计算方法。
if(abs($Twb)<0.051) $nb+=1; else $n=0; if($nb<15) $Tby=$Tby+$Vby*$t+0.5*$Aby*$t*$t; else $Tby=$Twyv+4; $Twyv=($Twy[1]+$Twy[2]+$Twy[3]+$Twy[4])/4; $Twb=$Tby-$Twyv-4;//4表示车身的高度 当车身与轮子构成的系统之间的y轴向的位移超过0.8个单位时,强制其为0.8。 if(abs($Twb)>0.8) $Tby=$Twyv+4.0+sign($Twb)*0.8; $Aby=-$kb*$Twb*abs($Twb); $Vby=$Vby+$Aby*$t-sign($Vby)*0.5;
12.计算车身的旋转角度,具体思路与计算车身y轴位移的相同,不同的是要通过四个轮子的空间位置计算车轮系统的角度及角加速度,通过车轮系统计算出来的角度及角加速度计算出车身的角度及角加速度。具体的一些比例系数大部分是试验结果。
$twu=($Twy[1]+$Twy[2])-($Twy[3]+$Twy[4]); $twv=($Twy[1]+$Twy[3])-($Twy[4]+$Twy[2]); $angerWu=-asind($twu/8); $angerWv=-asind($twv/10);
$u=$angerBu-$angerWu; $abu=-$ku*sign($u)*($u/2)*($u/2); $vbu=$vbu+$abu*$t-$vbu*0.5; $angerBu=$angerBu+$vbu*$t+0.5*$abu*$t*$t; $angerBu=clamp($angerWu-10,$angerWu+10,$angerBu); $v=$angerBv-$angerWv; $abv=-$kv*sign($v)*($v/3)*($v/3); $vbv=$vbv+$abv*$t-sign($vbv)*5; $angerBv=$angerBv+$vbv*$t+0.5*$abv*$t*$t; $angerBv=clamp($angerWv-20,$angerWv+20,$angerBv); if(abs($u<1)) $nu+=1; else $nu=0; if($nu<15) $angerBu=$angerBu; else $angerBu=$angerWu;
if(abs($v<1)) $nv+=1; else $nv=0; if($nv<15) $angerBv=$angerBv; else $angerBv=$angerWv;
$angerWv1=asind(0.2*($Twy[1]-$Twy[2])); $angerWv2=asind(0.2*($Twy[3]-$Twy[4])); $v1=$angerBv-$angerWv1; $v2=$angerBv-$angerWv2; $av[1]=-$kav*$v1; $av[2]=$kav*$v1; $av[3]=-$kav*$v2; $av[4]=$kav*$v2; $angerWu1=asind(0.25*($Twy[1]-$Twy[3])); $angerWu2=asind(0.25*($Twy[2]-$Twy[4])); $u1=$angerBu-$angerWu1; $u2=$angerBu-$angerWu2; $au[1]=-$kau*$u1; $au[2]=-$kau*$u2; $au[3]=$kau*$u1; $au[4]=$kau*$u2;
13.给轮子及车身赋值 wheel_l1.translateY=$Twy[1]; wheel_l2.translateY=$Twy[2]; wheel_r1.translateY=$Twy[3]; wheel_r2.translateY=$Twy[4];
body.translateY=$Tby; body.rotateX=$angerBu; body.rotateZ=$angerBv;
我定义了一个名为aaaa的位置指示物体驱动四个轮子运动。 a1.translateX=b1.translateX=aaaa.translateX+3; a2.translateX=b2.translateX=aaaa.translateX+7; a1.translateZ=a2.translateZ=aaaa.translateZ+2; b1.translateZ=b2.translateZ=aaaa.translateZ-2; 对于aaaa这个物体,我用关键帧控制其位移。可以考虑用表达式控制,控制速度顺应地形的变化。例如在上坡时速度会减速,下坡时会加速。这个表达式应该比较简单,有兴趣的朋友自己写写。
好了,大脚车的表达式基本就介绍完了,现在把全部表达式列出来,如下,供大家参考。表达式还有许多不足之处,望大家多多指正。例如不管坡度多么大,大脚车是不会翻滚的,呵呵。 以下是全部表达式,仅供参考,觉得对自己或别人有帮助的就多顶顶,觉得没什么意义就让它沉下去,说实话,对于表达式不熟悉的朋友看这些是要死不少脑细胞的。
global float $Twa[],$Twy[],$Tby,$Twyv,$Twb,$a[],$T[], $Twu,$Twv,$Vwy[],$Vby, $Awy[],$Aby,$Awu[],$Awv[],$g=9.8, $angerBu,$angerBv,$angerWu,$angerWv,$u,$v, $abu,$abv,$vbu,$vbv,$aby,$u1,$u2,$v1,$v2, $au[],$av[],$angerWu1,$angerWu2,$angerWv1, $angerWv2; float $Fw[],$Nw[],$M=5,$m=0.5,$kau=0.02,$kav=0.04, $kw=10*($m+$M/4)*$g,$kb=5*$M*$g, $ku=250,$kv=200,$t=0.03; int $i,$j,$nw[],$nb,$nu,$nv;
$a[1]=a1.translateY; $a[2]=a2.translateY; $a[3]=b1.translateY; $a[4]=b2.translateY; wheel_r1.rotateX=clamp(max((-$angerWu1+85),(b1.rotateX+90)), min((-$angerWu1+120),(b1.rotateX+90)),(b1.rotateX+90)); wheel_r2.rotateX=clamp(max((-$angerWu2+85),(b2.rotateX+90)), min((-$angerWu1+120),(b2.rotateX+90)),(b2.rotateX+90)); wheel_l1.rotateX=clamp(max((-$angerWu1+85),(a1.rotateX+90)), min((-$angerWu2+120),(a1.rotateX+90)),(a1.rotateX+90)); wheel_l2.rotateX=clamp(max((-$angerWu2+85),(a2.rotateX+90)), min((-$angerWu2+120),(a2.rotateX+90)),(a2.rotateX+90));
wheel_r1.translateX=b1.translateX; wheel_r2.translateX=b2.translateX; wheel_l1.translateX=a1.translateX; wheel_l2.translateX=a2.translateX; wheel_r1.translateZ=b1.translateZ; wheel_r2.translateZ=b2.translateZ; wheel_l1.translateZ=a1.translateZ; wheel_l2.translateZ=a2.translateZ; body.translateX=(wheel_l1.translateX+wheel_l2.translateX+wheel_r1.translateX+ wheel_r2.translateX)/4; body.translateZ=(wheel_l1.translateZ+wheel_l2.translateZ+wheel_r1.translateZ+ wheel_r2.translateZ)/4;
if(frame==1) { $nb=$nu=$nv=0; $Awy[1]=$Awy[2]=$Awy[3]=$Awy[4]=$Aby=0; $Twyv=$Vwy[1]=$Vwy[2]=$Vwy[3]=$Vwy[4]=$Vby=0; $Twy[1]=a1.translateY+1.4; $Twy[2]=a2.translateY+1.4; $Twy[3]=b1.translateY+1.4; $Twy[4]=b2.translateY+1.4;
$abu=$abv=$awu=$awv=0; $vbu=$vbv=0; $u=$v=0; $twu=($Twy[1]+$Twy[2])-($Twy[3]+$Twy[4]); $twv=($Twy[1]+$Twy[3])-($Twy[4]+$Twy[2]); $angerWu=-asind($twu/8); $angerWv=-asind($twv/10); $angerBu=$angerWu; $angerBv=$angerWv;
$Twyv=($Twy[1]+$Twy[2]+$Twy[3]+$Twy[4])/4; $Tby=$Twyv+4.0; }
if(frame>1) { for($i=1;$i<5;$i++) { $Twa[$i]=$Twy[$i]-$a[$i]-1.4; $Fw[$i]=1*$M*$Aby/4+1*$M*$au[$i]+1*$M*$av[$i]; if($Twa[$i]>0.1) $Nw[$i]=-0.2*$kw*($Twa[$i]/0.5) ; else $Nw[$i]=-1*$kw*$Twa[$i]*abs($Twa[$i]/0.5); $Awy[$i]=($Nw[$i]-$Fw[$i])/$m; $Awy[$i]=clamp(-1000,1000,$Awy[$i]); $Vwy[$i]=($Vwy[$i]+1.5*$Awy[$i]*$t)*1.0-$Vwy[$i]*0.2; $Twy[$i]=$Twy[$i]+$Vwy[$i]*$t+0.5*$Awy[$i]*$t*$t;
if(abs($Twa[$i])<0.03) $nw[$i]+=1; else $nw[$i]=0; if($nw[$i]<15) $Twy[$i]=$Twy[$i]; else $Twy[$i]=$a[$i]+1.4; $Twy[$i]=clamp($Tby-5,$Tby-3,$Twy[$i]); if($Twa[$i]<-0.1) $Twy[$i]=$a[$i]+1.3;
$Twy[$i]=clamp($T[$i]-0.4,$T[$i]+0.4,$Twy[$i]); $T[$i]=$Twy[$i]; }
if(abs($Twb)<0.051) $nb+=1; else $n=0; if($nb<15) $Tby=$Tby+$Vby*$t+0.5*$Aby*$t*$t; else $Tby=$Twyv+4;//difine $Tby $Twyv=($Twy[1]+$Twy[2]+$Twy[3]+$Twy[4])/4; $Twb=$Tby-$Twyv-4; if(abs($Twb)>0.8) $Tby=$Twyv+4.0+sign($Twb)*0.8; $Aby=-$kb*$Twb*abs($Twb);
$Vby=$Vby+$Aby*$t-sign($Vby)*0.5;
$twu=($Twy[1]+$Twy[2])-($Twy[3]+$Twy[4]); $twv=($Twy[1]+$Twy[3])-($Twy[4]+$Twy[2]); $angerWu=-asind($twu/8)*0.9; $angerWv=-asind($twv/10)*0.9;
$u=$angerBu-$angerWu; $abu=-$ku*sign($u)*($u/2)*($u/2); $vbu=$vbu+$abu*$t-$vbu*0.5; $angerBu=$angerBu+$vbu*$t+0.5*$abu*$t*$t; $angerBu=clamp($angerWu-10,$angerWu+10,$angerBu); $v=$angerBv-$angerWv; $abv=-$kv*sign($v)*($v/3)*($v/3); $vbv=$vbv+$abv*$t-sign($vbv)*5; $angerBv=$angerBv+$vbv*$t+0.5*$abv*$t*$t; $angerBv=clamp($angerWv-20,$angerWv+20,$angerBv); if(abs($u<1)) $nu+=1; else $nu=0; if($nu<15) $angerBu=$angerBu; else $angerBu=$angerWu;
if(abs($v<1)) $nv+=1; else $nv=0; if($nv<15) $angerBv=$angerBv; else $angerBv=$angerWv;
$angerWv1=asind(0.2*($Twy[1]-$Twy[2])); $angerWv2=asind(0.2*($Twy[3]-$Twy[4])); $v1=$angerBv-$angerWv1; $v2=$angerBv-$angerWv2; $av[1]=-$kav*$v1; $av[2]=$kav*$v1; $av[3]=-$kav*$v2; $av[4]=$kav*$v2; $angerWu1=asind(0.25*($Twy[1]-$Twy[3])); $angerWu2=asind(0.25*($Twy[2]-$Twy[4])); $u1=$angerBu-$angerWu1; $u2=$angerBu-$angerWu2; $au[1]=-$kau*$u1; $au[2]=-$kau*$u2; $au[3]=$kau*$u1; $au[4]=$kau*$u2;
}
wheel_l1.translateY=$Twy[1]; wheel_l2.translateY=$Twy[2]; wheel_r1.translateY=$Twy[3]; wheel_r2.translateY=$Twy[4];
body.translateY=$Tby; body.rotateX=$angerBu; body.rotateZ=$angerBv;
a1.translateX=b1.translateX=aaaa.translateX+3; a2.translateX=b2.translateX=aaaa.translateX+7; a1.translateZ=a2.translateZ=aaaa.translateZ+2; b1.translateZ=b2.translateZ=aaaa.translateZ-2;
print($Awy[3]+", "+$Vwy[3]+", "+$Twy[3]+", " +$Twa[3]+" "+$nw[3]+"\n"+ $angerWu1+" "+b1.rotateX+" "+(wheel_r1.rotateX-90)); 对于在本教程的学习中遇到任何疑问或有更好的建议,请到技术论坛讨论。
|