我正在研究一种机制,用于控制对象相对于3D空间中的controlPoint围绕着anchorPoint的位置和旋转。对象可以具有任何初始旋转,因此必须使用旋转偏移量,以便在移动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处的局部轴发生偏移,这将产生外观旋转,其中local forward = control-> anchor and local up≈up from R 。
也就是说,
R * X = lookrotation(anchor - control, transform.up)
因此,为了找到X,将方程式的两边乘以左边的inverse(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和带有从〜close-enough〜转换向上的lookRot中,因此通过将两边乘以右边的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;
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句