带偏移量的旋转
Look rotation with offset
我正在研究一种机制来控制对象围绕 anchorPoint 相对于 3D 中的 controlPoint 的位置和旋转 space。对象可以有任何初始旋转,需要使用旋转偏移,以便在移动 controlPoint 时保持相对对齐。统一场景层次结构中不存在控件和锚点,因为它们存储为 Vector3。然而,该对象利用 unity 的 Transform 并且可能有一个或多个父对象,每个对象都有自己的旋转。
预期的行为与局部旋转 Gizmo 非常相似,您可以在其中单击 Gizmo 的环来设置对象的旋转。
我尝试使用 FromToRotation、LookRotation 作为身份旋转以及从先前旋转状态的增量旋转来实现此功能,但没有成功。
下面是我得到的最接近的,但是如果对象或其父对象在计算偏移量时有 Z 轴旋转,则该对象会按预期旋转,但也包括围绕观察轴的不需要的滚动。
public Vector3 anchorPoint = Vector3.zero;
public Vector3 controlPoint = Vector3.left;
Quaternion rotationOffset = Quaternion.identity;
//Called when the object is "attached" to the anchor to store the difference between it's rotation and the directional vector from the control to the anchor
public void StoreOffset() {
//The unit vector pointing from the controlPoint to it's anchorPoint
Vector3 controlFwd = (anchorPoint - controlPoint).normalized;
//Generate a rotation using the direction vector while respecting the objects local up.
Quaternion lookRot = Quaternion.LookRotation(controlFwd, transform.up);
//Subtract the object's rotation from the lookRotation to determine the rotational offset between the two.
//Invert the offset rotation to save on calculations during update
rotationOffset = Quaternion.Inverse(Quaternion.Inverse(transform.rotation) * lookRot);
}
//Called any time the control point is moved to update the objects rotation
public void UpdateRotation() {
//The unit vector pointing from the controlPoint to it's anchorPoint
Vector3 controlFwd = (anchorPoint - controlPoint).normalized;
//Generate a rotation using the above direction vector while respecting the objects local up.
Quaternion lookRot = Quaternion.LookRotation(controlFwd, transform.up);
//Assign the new look rotation to the object then apply the offset rotation.
//ToLocalRotation is a Quaternion extension that converts rotations from world to local space
transform.localRotation = (lookRot * rotationOffset).ToLocalRotation(transform);
}
示例动画
第一个 .gif 显示正确的功能,只要父对象没有旋转。
如果父对象的 Z 轴旋转为 10°,则第二个 .gif 显示错误旋转
所以在 storeoffset 发生之前,你有一个当前旋转 R。你想要计算一个偏移 X,使得从旋转 R 处的局部轴开始,这将产生外观旋转,其中局部向前 = 控制-> 锚点和局部向上≈ 从 R.
也就是说,
R * X = lookrotation(anchor - control, transform.up)
所以,为了求出X,在等式两边乘以左边的逆(R):
inverse(R) * R * X = inverse(R) * lookrotation(anchor-control, transform.up)
X = inverse(R) * lookrotation(anchor-control, transform.up)
所以,StoreOffset
的结尾应该是:
rotationOffset = Quaternion.Inverse(transform.rotation) * lookRot;
然后,在 UpdateRotation
中,您有 X 和 lookRot 以及来自 ~close-enough~ 变换的 up,所以通过在右侧将两边乘以 inverse(X) 来求解 R:
R * X = lookrotation(anchor-control, transform.up)
R * X * inverse(X) = lookrotation(anchor-control, transform.up) * inverse(X)
R = lookrotation(anchor-control, transform.up) * inverse(X)
所以,UpdateRotation
的结尾应该是:
transform.rotation = lookRot * Quaternion.inverse(rotationOffset);
或者,由于 UpdateRotation
可能比 StoreOffset
更频繁地被调用,所以在赋值之前进行反转:
rotationOffsetInverse = Quaternion.inverse(Quaternion.Inverse(transform.rotation)
* lookRot);
// ...
transform.rotation = lookRot * rotationOffsetInverse;
所以,一共:
public Vector3 anchorPoint = Vector3.zero;
public Vector3 controlPoint = Vector3.left;
Quaternion rotationOffsetInverse = Quaternion.identity;
Quaternion GetControlLookRot()
{
// The unit vector pointing from the controlPoint to it's anchorPoint
Vector3 controlFwd = (anchorPoint - controlPoint).normalized;
// Generate a rotation using the direction vector while respecting the
// objects local up.
return Quaternion.LookRotation(controlFwd, transform.up);
}
// Called when the object is "attached" to the anchor to store the difference between
// its rotation and the directional vector from the control to the anchor
public void StoreOffset()
{
rotationOffsetInverse = Quaternion.inverse(Quaternion.Inverse(transform.rotation)
* GetControlLookRot());
}
// Called any time the control point is moved to update the objects rotation
public void UpdateRotation()
{
// Assign the new look rotation to the object then apply the offset rotation.
transform.rotation = GetControlLookRot() * rotationOffsetInverse;
}
我正在研究一种机制来控制对象围绕 anchorPoint 相对于 3D 中的 controlPoint 的位置和旋转 space。对象可以有任何初始旋转,需要使用旋转偏移,以便在移动 controlPoint 时保持相对对齐。统一场景层次结构中不存在控件和锚点,因为它们存储为 Vector3。然而,该对象利用 unity 的 Transform 并且可能有一个或多个父对象,每个对象都有自己的旋转。
预期的行为与局部旋转 Gizmo 非常相似,您可以在其中单击 Gizmo 的环来设置对象的旋转。
我尝试使用 FromToRotation、LookRotation 作为身份旋转以及从先前旋转状态的增量旋转来实现此功能,但没有成功。
下面是我得到的最接近的,但是如果对象或其父对象在计算偏移量时有 Z 轴旋转,则该对象会按预期旋转,但也包括围绕观察轴的不需要的滚动。
public Vector3 anchorPoint = Vector3.zero;
public Vector3 controlPoint = Vector3.left;
Quaternion rotationOffset = Quaternion.identity;
//Called when the object is "attached" to the anchor to store the difference between it's rotation and the directional vector from the control to the anchor
public void StoreOffset() {
//The unit vector pointing from the controlPoint to it's anchorPoint
Vector3 controlFwd = (anchorPoint - controlPoint).normalized;
//Generate a rotation using the direction vector while respecting the objects local up.
Quaternion lookRot = Quaternion.LookRotation(controlFwd, transform.up);
//Subtract the object's rotation from the lookRotation to determine the rotational offset between the two.
//Invert the offset rotation to save on calculations during update
rotationOffset = Quaternion.Inverse(Quaternion.Inverse(transform.rotation) * lookRot);
}
//Called any time the control point is moved to update the objects rotation
public void UpdateRotation() {
//The unit vector pointing from the controlPoint to it's anchorPoint
Vector3 controlFwd = (anchorPoint - controlPoint).normalized;
//Generate a rotation using the above direction vector while respecting the objects local up.
Quaternion lookRot = Quaternion.LookRotation(controlFwd, transform.up);
//Assign the new look rotation to the object then apply the offset rotation.
//ToLocalRotation is a Quaternion extension that converts rotations from world to local space
transform.localRotation = (lookRot * rotationOffset).ToLocalRotation(transform);
}
示例动画
第一个 .gif 显示正确的功能,只要父对象没有旋转。
如果父对象的 Z 轴旋转为 10°,则第二个 .gif 显示错误旋转
所以在 storeoffset 发生之前,你有一个当前旋转 R。你想要计算一个偏移 X,使得从旋转 R 处的局部轴开始,这将产生外观旋转,其中局部向前 = 控制-> 锚点和局部向上≈ 从 R.
也就是说,
R * X = lookrotation(anchor - control, transform.up)
所以,为了求出X,在等式两边乘以左边的逆(R):
inverse(R) * R * X = inverse(R) * lookrotation(anchor-control, transform.up)
X = inverse(R) * lookrotation(anchor-control, transform.up)
所以,StoreOffset
的结尾应该是:
rotationOffset = Quaternion.Inverse(transform.rotation) * lookRot;
然后,在 UpdateRotation
中,您有 X 和 lookRot 以及来自 ~close-enough~ 变换的 up,所以通过在右侧将两边乘以 inverse(X) 来求解 R:
R * X = lookrotation(anchor-control, transform.up)
R * X * inverse(X) = lookrotation(anchor-control, transform.up) * inverse(X)
R = lookrotation(anchor-control, transform.up) * inverse(X)
所以,UpdateRotation
的结尾应该是:
transform.rotation = lookRot * Quaternion.inverse(rotationOffset);
或者,由于 UpdateRotation
可能比 StoreOffset
更频繁地被调用,所以在赋值之前进行反转:
rotationOffsetInverse = Quaternion.inverse(Quaternion.Inverse(transform.rotation)
* lookRot);
// ...
transform.rotation = lookRot * rotationOffsetInverse;
所以,一共:
public Vector3 anchorPoint = Vector3.zero;
public Vector3 controlPoint = Vector3.left;
Quaternion rotationOffsetInverse = Quaternion.identity;
Quaternion GetControlLookRot()
{
// The unit vector pointing from the controlPoint to it's anchorPoint
Vector3 controlFwd = (anchorPoint - controlPoint).normalized;
// Generate a rotation using the direction vector while respecting the
// objects local up.
return Quaternion.LookRotation(controlFwd, transform.up);
}
// Called when the object is "attached" to the anchor to store the difference between
// its rotation and the directional vector from the control to the anchor
public void StoreOffset()
{
rotationOffsetInverse = Quaternion.inverse(Quaternion.Inverse(transform.rotation)
* GetControlLookRot());
}
// Called any time the control point is moved to update the objects rotation
public void UpdateRotation()
{
// Assign the new look rotation to the object then apply the offset rotation.
transform.rotation = GetControlLookRot() * rotationOffsetInverse;
}