0

概述

我已经四处寻找了一段时间,还没有找到答案,所以希望这里的社区可以帮助我。我正在重新设计我的观察相机(写于 2000 年之前),并且无法解决观察和向上矢量对齐导致相机疯狂旋转失控的问题。本来以为是云台锁,现在不太确定。

根据我对云台锁的理解,当俯仰与滚动对齐时,俯仰变为滚动;本质上这就是它的样子,但问题是变化率不应该仅仅因为轴对齐而增加,我应该得到一个平稳的滚动。相反,我得到了一个剧烈的滚动,我无法真正判断滚动的方向。


更新相机的位置

当用户移动鼠标时,我会根据鼠标XY坐标移动相机:

Vector2 mousePosition = new Vector2(e.X, e.Y);
Vector2 delta = mousePosition - mouseSave;
mouseSave = mousePosition;

ShiftOrbit(delta / moveSpeed);

在该方法中,我根据与上述鼠标事件传递的ShiftOrbit相关的查看、右和上向量计算新位置:delta

Vector3 lookAt = Position - Target;
Vector3 right = Vector3.Normalize(Vector3.Cross(lookAt, Up));
Vector3 localUp = Vector3.Normalize(Vector3.Cross(right, lookAt));

Vector3 worldYaw = right * delta.X * lookAt.Length();
Vector3 worldPitch = localUp * delta.Y * lookAt.Length();
Position = Vector3.Normalize(Position + worldYaw + worldPitch) * Position.Length();

这可以正常工作,并且可以在我选择的任何方向上围绕目标移动相机。


视图矩阵

这就是我遇到上面概述中提到的问题的地方。由于我的数据位于 ECR 坐标中,我的Up属性以前设置为始终。0, 0, 1然而,当我四处移动相机并更新视图矩阵时,这就是导致轴对齐的原因。我使用该SharpDX方法Matrix.CreateLookAtRH(Position, Target, Up)来创建我的视图矩阵。

在发现Up创建视图矩阵时使用的向量应该更新而不是总是更新后0, 0, 1,我遇到了另一个问题。我现在在引入偏航和俯仰时引起滚动。由于要求,这不应该发生,所以我立即开始寻求修复。

最初我进行了检查以查看是否接近轴对齐,如果是,那么我将Up用于创建我的视图矩阵的设置设置为相机的本地向上,如果不是,那么我只使用Z轴局部向上,以确保向上或向下。

float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
if (dot > 0.98)
    Up = localUp;
else
    Up = new Vector3(0, 0, localUp.Z);

然而,这有点跳动,似乎仍然不太对劲。经过一些试验和错误,以及对网络的一些广泛研究,试图找到潜在的解决方案,我记得线性插值如何在一段时间内从一个值平滑过渡到另一个值。然后我改为使用Vector3.Lerp

float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
Up = Vector3.Lerp(new Vector3(0, 0, localUp.Z), localUp, dot);

这非常平滑,并且仅在我非常接近轴对齐时才会导致任何滚动,这不足以让日常用户注意到。


问题

My camera also has the ability to attach to a point other than 0, 0, 0, and in this case, the up vector for the camera is set to the normalized position of the target. This causes the original issue in the overview when using Vector3.Lerp as above; so, in the case where my camera is attached to a point other than 0, 0, 0 I do the following instead:

Up = Vector3.Lerp(Vector3.Normalize(Target), localUp, dot);

However, even this doesn't work and I have no idea how to get it to do so. I've been working at this problem for a few days now and have made an extensive effort to fix it, and this is a big improvement so far.


What can I do to prevent the violent spinning using Vector3.Lerp when the up isn't equivalent to 0, 0, z?

4

1 回答 1

1

Imagine a vertical plane that is rotated around the vertical axis by yaw (ϕ):

enter image description here

The camera is only allowed to rotate with the plane or in the plane, its in-plane orientation given by the pitch (θ):

enter image description here

ϕ and θ should be stored and incremented with the input delta. With this setup, the camera will never tilt, and the local up direction can always be computed:

enter image description here

d and u are the local front and up directions respectively, and are always perpendicular (so alignment won't be an issue). The target can of course be taken as the position + d.

But wait, there's a catch.


Suppose if you move your mouse to the right; ϕ increases, and you observe:

  • If the camera is upright, the view rotates to the right.
  • If the camera is upside-down, the view rotates to the left.

Ideally this should be consistent regardless of the vertical orientation.

The solution is to flip the sign of increments to ϕ when the camera is upside down. One way would be to scale the increments by cos(θ), which also smoothly reduces the sensitivity as θ approaches 90 / 270 degrees so that there is no sudden change in horizontal rotational direction.

于 2019-01-04T23:53:32.897 回答