gpt4 book ai didi

c# - 夹紧旋转/四元数

转载 作者:行者123 更新时间:2023-12-04 15:37:00 25 4
gpt4 key购买 nike

仍在进行 VR 交互,我希望能够旋转对象,但我面临一个问题。

例如,我想在 VR 中用手打开/关闭笔记本电脑的上部。为了实现这一目标,我正在做的是我像这样放置前锋:

laptopForward

我正在使用位置、向前、向上创建一个平面。然后获取与我的 VR Controller 对应的平面上最近的点,然后使用 transform.LookAt。

这工作正常,但我希望能够夹紧旋转,所以我不能旋转太多(见视频结尾)。

我一直在尝试一切,使用 eulerAngle 和 Quaternion,但我无法做到。

我做了一些助手(显示localEulerAngles的文本,以及LookAt的转换,所以我不必使用VR耳机,因为它变得非常乏味)

这是一个显示正在发生的事情的视频:https://www.youtube.com/watch?v=UfN97OpYElk

这是我的代码:

using UnityEngine;

public class JVRLookAtRotation : MonoBehaviour, IJVRControllerInteract
{

[SerializeField] private Transform toRotate;

[SerializeField] private Vector3 minRotation;
[SerializeField] private Vector3 maxRotation;

[Header("Rotation contraints")]
[SerializeField] private bool lockX;
[SerializeField] private bool lockY;
[SerializeField] private bool lockZ;

private JVRController _jvrController;
private bool _isGrabbed;
private Vector3 _targetPosition;
private Vector3 _tmp;

public Transform followTransform;

private void LateUpdate()
{

/*
if (!_isGrabbed) return;

if (_jvrController.Grip + _jvrController.Trigger < Rules.GrabbingThreshold)
{
_isGrabbed = false;
_jvrController.StopGrabbing();
_jvrController = null;
return;
}

*/

Vector3 up = toRotate.up;
Vector3 forward = toRotate.forward;
Vector3 pos0 = toRotate.position;
Vector3 pos1 = pos0 + up;
Vector3 pos2 = pos0 + forward;
Plane p = new Plane(pos0, pos1, pos2);

// Using followTransform just to no have to use VR, otherwise it's the controller pos
_targetPosition = p.ClosestPointOnPlane(followTransform.position);

toRotate.LookAt(_targetPosition, up);

/*
_tmp = toRotate.localEulerAngles;
_tmp.x = Mathf.Clamp(WrapAngle(_tmp.x), minRotation.x, maxRotation.x);
_tmp.y = WrapAngle(_tmp.y);
_tmp.z = WrapAngle(_tmp.z);
toRotate.localRotation = Quaternion.Euler(_tmp);
*/

}

public void JVRControllerInteract(JVRController jvrController)
{
if (_isGrabbed) return;
if (!(jvrController.Grip + jvrController.Trigger > Rules.GrabbingThreshold)) return;

_jvrController = jvrController;
_jvrController.SetGrabbedObject(this);
_isGrabbed = true;
}

private static float WrapAngle(float angle)
{
angle%=360;
if(angle >180)
return angle - 360;

return angle;
}

private static float UnwrapAngle(float angle)
{
if(angle >=0)
return angle;

angle = -angle%360;

return 360-angle;
}
}

最佳答案

假设显示器的父变换是笔记本电脑的主体/键盘。父级的局部轴如下所示:

local axes of parent

为了描述运动范围,您可以定义一个“旋转中心”向量(例如,标记为 C 的灰色向量),它是父对象的局部和一个角度(例如,每个紫色向量和灰色向量之间的 110 度)。例如:

[SerializeField] private Vector3 LocalRotationRangeCenter = new Vector3(0f, 0.94f, 0.342f);
[SerializeField] private float RotationRangeExtent = 110f;

然后,你可以取它“想要”去的前向向量,找到 RotationRangeCenter的世界方向之间的有符号角。和那个点,然后把它夹在± RotationRangeExtent :
Vector3 worldRotationRangeCenter = toRotate.parent.TransformDirection(RotationRangeCenter);

Vector3 targetForward = _targetPosition - toRotate.position;

float targetAngle = Vector3.SignedAngle(worldRotationRangeCenter, targetForward,
toRotate.right);

float clampedAngle = Mathf.Clamp(targetAngle, -RotationRangeExtent, RotationRangeExtent);

然后,找到对应于该角度的方向。最后,旋转显示器,使其向前与夹住的向前对齐,并且其右侧不会改变。您可以使用叉积来查找监视器的状态,然后使用 Quaternion.LookRotation找到相应的旋转:
Vector3 clampedForward = Quaternion.AngleAxis(clampedAngle, toRotate.right)
* worldRotationRangeCenter;

toRotate.rotation = Quaternion.LookRotation(clampedForward,
Vector3.Cross(clampedForward, toRotate.right));

如果有人试图将显示器拖离“边界”太远,它将从一个限制传送到另一个限制。如果这不是您想要的行为,您可以考虑从 SignedAngle(worldRotationRangecenter, targetForward, toRotate.right) 进行插值至 clampedAngle , 对于极限之间的运动:
private float angleChangeLimit = 90f; // max angular speed

// ...

Vector3 worldRotationRangeCenter = toRotate.parent.TransformDirection(RotationRangeCenter);

Vector3 targetForward = _targetPosition - toRotate.position;

float targetAngle = Vector3.SignedAngle(worldRotationRangeCenter, targetForward,
toRotate.right);

float clampedAngle = Mathf.Clamp(targetAngle, -RotationRangeExtent, RotationRangeExtent);

float currentAngle = Vector3.SignedAngle(worldRotationRangeCenter, toRotate.forward,
toRotate.right);

clampedAngle = Mathf.MoveTowards(currentAngle, clampedAngle,
angleChangeLimit * Time.deltaTime);

Vector3 clampedForward = Quaternion.AngleAxis(clampedAngle, toRotate.right)
* worldRotationRangeCenter;

toRotate.rotation = Quaternion.LookRotation(clampedForward,
Vector3.Cross(clampedForward, toRotate.right));

关于c# - 夹紧旋转/四元数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59392800/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com