首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在C#单位位置给定力,计算GameObject的转速

在C#单位位置给定力,计算GameObject的转速
EN

Stack Overflow用户
提问于 2018-06-06 22:35:14
回答 1查看 1.4K关注 0票数 1

我找到了这个脚本,它返回转速(考虑到作用力的位置和离质心的距离)。

代码语言:javascript
复制
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);
}

对于2100牛顿,我得到了0.6弧度(36度)的旋转。

代码语言:javascript
复制
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)

但是使用AddForceAtPosition用相同的力旋转飞船,我得不到相同的结果

代码语言:javascript
复制
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);
}

它不是每秒36度-我通过计算做一个完整的360度旋转需要多长时间来测试,理应在10秒内完成,但它只需要10秒就能旋转到90度。

在第一个脚本中有很多我不理解的地方,就像大多数物理部分一样,但我没有看到它考虑到我的船的质量(body.worldCenterOfMass?),可能是这样吗?

我需要这个,这样我才能更精确地旋转我的船。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-07 04:14:24

主要的错误是混淆了加速度和速度。应用扭矩会产生角加速度(每秒弧度/秒),角加速度由test (绕Y轴的36.1 deg / s^2)给出。这不是角速度,而是变化率,因此您不应期望相同的结果。

(传递给ForceToTorque的力也只是所需力的一半。)

快速物理注释-扭矩方程:

I是转动惯量张量,一个由上面的积分给出的3x3矩阵,覆盖了物体的所有质量元素。它的索引ij显然是对称的,所以它是可对角化的(任何像样的线性代数书籍):

D是物体主轴基础上的M-of-I张量,R是从主体到当前基础的旋转矩阵。D的对角线元素是向量body.inertiaTensor的值,这意味着Unity总是将对象的主轴与世界轴对齐,并且我们总是有I = D

因此,要获得由扭矩引起的角加速度:

其中最后一行由Div执行。

确保精确旋转的一种更好的方法是应用角脉冲,它直接改变角速度。所需的Q和相应的线性脉冲P都满足:

这会直接改变物体的角速度。(*)是输入参数必须满足的条件。您仍然可以在ForceMode.Impulse中使用AddForceAtPosition。代码:

代码语言:javascript
复制
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);
}

申请:

代码语言:javascript
复制
var test = AngularvelocityToImpulse(...);
body.AddForceAtPosition(test, shipFront.position, ForceMode.Impulse);
body.AddForceAtPosition(-test, shipBack.position, ForceMode.Impulse);
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50723064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档