简体   繁体   English

在给定位置C#Unity的力的情况下计算GameObject的旋转速度

[英]Calculating rotational speed of a GameObject, given a force at position C# Unity

I found this script that returns rotational speed (taking into account where force is applied and distance from center of mass). 我发现此脚本返回旋转速度(考虑了施加力的位置以及距质心的距离)。

public Vector3 ForceToTorque(Vector3 force, Vector3 position, ForceMode forceMode = ForceMode.Force)
{
    Vector3 t = Vector3.Cross(position - body.worldCenterOfMass, force);
    ToDeltaTorque(ref t, forceMode);

    return t;
}

private void ToDeltaTorque(ref Vector3 torque, ForceMode forceMode)
{
    bool continuous = forceMode == ForceMode.VelocityChange || forceMode == ForceMode.Acceleration;
    bool useMass = forceMode == ForceMode.Force || forceMode == ForceMode.Impulse;

    if (continuous) torque *= Time.fixedDeltaTime;
    if (useMass) ApplyInertiaTensor(ref torque);
}

private void ApplyInertiaTensor(ref Vector3 v)
{
    v = body.rotation * Div(Quaternion.Inverse(body.rotation) * v, body.inertiaTensor);
}

private static Vector3 Div(Vector3 v, Vector3 v2)
{
    return new Vector3(v.x / v2.x, v.y / v2.y, v.z / v2.z);
}

With 2100 newtons I'm getting 0.6 radians (36 degrees) of rotation. 有了2100牛顿,我得到0.6弧度(36度)的旋转。

var test = rotationScript.ForceToTorque(shipFront.right * 2100, shipFront.position, ForceMode.Force);
Debug.Log(test + " " + test * Mathf.Rad2Deg);
// Above gives (0, 0.6, 0) and (0, 36.1, 0)

But using AddForceAtPosition to rotate the ship with the same force I don't get the same result 但是使用AddForceAtPosition以相同的力旋转船我没有得到相同的结果

if (currTurn > 0) {
    body.AddForceAtPosition(shipFront.right * 2100, shipFront.position, ForceMode.Force);
    body.AddForceAtPosition(-shipBack.right * 2100, shipBack.position, ForceMode.Force);
} else if (currTurn < 0) {
    body.AddForceAtPosition(-shipFront.right * 2100, shipFront.position, ForceMode.Force);
    body.AddForceAtPosition(shipBack.right * 2100, shipBack.position, ForceMode.Force);
}

It's not giving me 36 degrees per second - I tested by counting how long it took to do a full 360 spin, supposedly it should've been done in 10s but it took 10s to rotate only ~90º. 它不是每秒给我36度-我通过计算完成360度旋转所花费的时间进行了测试,据推测它应该在10s内完成,但仅用10s即可旋转约90º。

There's a lot I don't understand in the first script, like most of the physics part, but I don't see it taking into consideration my ships mass ( body.worldCenterOfMass ?), could that be it? 有很多我没有在第一个脚本了解,像极了物理学的一部分,但我没有看到它考虑到我的质量船舶( body.worldCenterOfMass ?),那会是什么?

I need this so I can rotate my ship more precisely. 我需要这个,以便我可以更精确地旋转我的船。

The major mistake was a confusion between acceleration and velocity . 主要的错误是加速度速度之间的混淆。 Applying a torque leads to angular acceleration (radians per second per second ), which is given by your test ( 36.1 deg / s^2 around the Y-axis). 施加转矩导致的角加速度(弧度每秒每秒 ),它是由你的给定test36.1 deg / s^2绕Y轴)。 This is not the angular velocity, but the rate-of-change , so you should not expect the same result. 这不是角速度,而是变化率 ,因此您不应期望得到相同的结果。

(Also the force passed to ForceToTorque is only half of the required force.) (另外,传递给ForceToTorque的力仅为所需力的一半。)


Quick physics notes - torque equation: 快速物理笔记-扭矩方程:

在此处输入图片说明

I is the moment-of-inertia tensor , a 3x3 matrix given by the integral above, over all mass elements of the body. I惯性矩张量 ,即上面的积分在身体所有质量元素上给出的3x3矩阵。 It is obviously symmetric in its indices i and j , so it is diagonalizable (any decent linear algebra book): 它的索引ij显然是对称的,因此它是对角线化的(任何体面的线性代数书):

在此处输入图片说明

D is the M-of-I tensor in the body's principal axes basis, and R is the rotation matrix from the principal to the current basis. D是在人体主轴基础上的I M张量, R是从主轴基础到当前基础的旋转矩阵。 The diagonal elements of D are the values of the vector body.inertiaTensor , which means that Unity always aligns the object's principal axes with the world axes, and that we always have I = D . D的对角元素是矢量body.inertiaTensor的值,这意味着Unity始终将对象的主轴与世界轴对齐,并且我们始终具有I = D

Therefore to obtain the angular acceleration arising from a torque: 因此,要获得由转矩引起的角加速度:

在此处输入图片说明

Where the last line is performed by Div . 最后一行由Div执行。


A better way to ensure accurate rotation is to apply an angular impulse , which directly changes the angular velocity. 一种确保准确旋转的更好方法是施加角冲动 ,该冲动会直接改变角速度。 Q and the corresponding linear impulse P required both satisfy: Q和所需的相应线性脉冲P都满足:

在此处输入图片说明

This directly changes the angular velocity of the body. 这直接改变了身体的角速度。 (*) is a condition that the input parameters must satisfy. (*)是输入参数必须满足的条件。 You can still use AddForceAtPosition with ForceMode.Impulse . 您仍然可以将AddForceAtPositionForceMode.Impulse AddForceAtPosition使用。 Code: 码:

Vector3 AngularvelocityToImpulse(Vector3 vel, Vector3 position)
{
   Vector3 R = position - body.worldCenterOfMass;
   Vector3 Q = MultiplyByInertiaTensor(vel);

   // condition (*)
   if (Math.Abs(Vector3.Dot(Q, R)) > 1e-5) 
      return new Vector3();

   // one solution
   // multiply by 0.5 because you need to apply this to both sides
   // fixes the factor-of-2 issue from before
   return 0.5 * Vector3.Cross(Q, R) / R.sqrMagnitude;
} 

Vector3 MultiplyByInertiaTensor(Vector3 v)
{
   return body.rotation * Mul(Quaternion.Inverse(body.rotation) * v, body.inertiaTensor);
}

Vector3 Mul(Vector3 v, Vector3 a)
{
   return new Vector3(v.x * a.x, v.y * a.y, v.z * a.z);
}

To apply: 申请:

var test = AngularvelocityToImpulse(...);
body.AddForceAtPosition(test, shipFront.position, ForceMode.Impulse);
body.AddForceAtPosition(-test, shipBack.position, ForceMode.Impulse);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM