Rea*_*One 0 c# physics vector unity-game-engine game-physics
我发现这个脚本可以返回旋转速度(考虑到施加力的位置和距质心的距离).
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);
}
Run Code Online (Sandbox Code Playgroud)
使用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)
Run Code Online (Sandbox Code Playgroud)
但是使用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);
}
Run Code Online (Sandbox Code Playgroud)
它没有给我36度/秒 - 我通过计算完成360度旋转需要多长时间进行测试,据说它应该在10秒内完成,但需要花费10秒才能旋转~90º.
在第一个剧本中有很多我不理解的东西,就像大多数物理部分一样,但是我没有看到它考虑到我的船质量(body.worldCenterOfMass?),可能就是这样吗?
我需要这个,所以我可以更精确地旋转我的船.
主要的错误是加速度和速度之间的混淆.施加转矩导致的角加速度(弧度每秒每秒),它是由给定的test(36.1 deg / s^2绕Y轴).这不是角速度,而是变化率,所以你不应该期望相同的结果.
(传递给力的力量ForceToTorque也只是所需力量的一半.)
快速物理笔记 - 扭矩方程:
I是惯性矩张量,是由上面积分给出的3x3矩阵,超过身体的所有质量元素.这显然是在对称的指数i和j,因此它是对角化(任何像样的线性代数书):
D是身体主轴基础上的M-of-I张量,R是从主体到当前基础的旋转矩阵.对角元素D是向量的值body.inertiaTensor,这意味着Unity总是将对象的主轴与世界轴对齐,而且我们总是如此I = D.
因此,要获得扭矩产生的角加速度:
最后一行的执行地点Div.
确保精确旋转的更好方法是应用角度脉冲,该角度脉冲直接改变角速度.Q并且P所需的相应线性脉冲都满足:
这直接改变了身体的角速度.(*)是输入参数必须满足的条件.您仍然可以使用AddForceAtPosition同ForceMode.Impulse.码:
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);
}
Run Code Online (Sandbox Code Playgroud)
申请:
var test = AngularvelocityToImpulse(...);
body.AddForceAtPosition(test, shipFront.position, ForceMode.Impulse);
body.AddForceAtPosition(-test, shipBack.position, ForceMode.Impulse);
Run Code Online (Sandbox Code Playgroud)