限制相机间距

Posted

技术标签:

【中文标题】限制相机间距【英文标题】:Limit camera pitch 【发布时间】:2011-03-27 09:21:15 【问题描述】:

当我只有相机四元数时,如何有效地?我必须转换为欧拉角,然后再转换回四元数还是有其他方法?

【问题讨论】:

Wert,在过去的几个小时里,我试着想一个好的答案......伙计,我已经好几年没有处理四元数了......我现在有烟从我的耳朵里冒出来...... . 我放弃了... ;-) 【参考方案1】:

如果相机从不出现任何滚动(这在许多游戏中很常见,例如第一人称射击游戏),那么解决方案很简单。如果有滚动,那么还有一个额外的步骤。我先从没有滚动的情况下怎么办开始,然后将解决方案概括为如果有怎么办。

令 qc 为相机旋转。让 qy 以与 qc 相同的偏航角进行旋转,但俯仰角为零。如果没有滚动,则相机旋转是偏航旋转,然后是俯仰旋转:

qc = qp * qy

我们可以将俯仰旋转 qp 恢复为从 qy 到 qc 的旋转:

qp = qc * qy^-1

因此,诀窍是构造 qy,因此我们可以将其代入上述方程以求解 qp。令 vc 为指向相机镜头外的单位矢量,或“前向矢量”。设 vy 是相同的向量,但投影到水平面并归一化。最后,当摄像机旋转 qc 为恒等旋转时,设 v0 为前向向量。将 v0 旋转到 vy 的旋转是偏航旋转。角度可以表示为:

yaw = asin(Norm(cross(v0, vy)))

对应的yaw旋转为:

qy =  cos(yaw/2), up * sin(yaw/2) 

其中“up”是向上方向的单位矢量,也就是偏航旋转的轴。将其插入上面的 qp = qy^-1 * qc 以获得音高四元数 qp。最后,从 qp 得到俯仰角为:

pitch = 2*asin(Dot(right, [qp[1], qp[2], qp[3]]))

其中“right”是右方向的单位向量,也就是俯仰旋转的轴。

就像我说的,如果相机也有滚动,事情会变得更复杂,但总体策略是相同的。您将相机旋转公式化为旋转分量的乘积,然后隔离所需的分量(在本例中为俯仰)。例如,如果你用来定义“pitch”的欧拉序列是常见的yaw-pitch-roll序列,那么你将qc定义为:

qc = qr * qp * qy

我们可以将变量 qx 定义为组合的俯仰和横滚旋转:

qx = qr * qp

我们现在可以把 qc 写成:

qc = qx * qy

我们已经知道如何以这种形式求解 qx,通过回溯我们上面用于求解 qp 的步骤。重新排列 qx 的定义,我们得到:

qp = qr^-1 * qx

我们刚刚求解了 qx,所以要求解俯仰旋转 qp,我们只需要横滚 qr。我们可以像以前一样使用向量来构造它。让 vc 再次成为前向向量。滚动将围绕该矢量旋转。让 vu 是相机的向上向量(在世界坐标中),让 vu0 是相机的零滚动的向上向量。我们可以通过将全局上向量投影到垂直于 vc 的平面上,然后进行归一化来构造 vu0。滚动旋转 qr 是从 vu0 到 vu 的旋转。这个旋转的轴是前向矢量 vc。滚动角为

roll = asin(Dot(vc, cross(vu0, vu)))

对应的四元数是:

qr =  cos(roll/2), forward * sin(roll/2) 

其中“向前”是滚动旋转的轴。

【讨论】:

【参考方案2】:

俯仰只是完整旋转的一个组成部分,所以如果你想这样考虑你的旋转,你最好单独存储俯仰,可能使用欧拉角。

当您需要限制移动时,仅转换为欧拉角并返回可能效果不佳,因为您需要记住最后一帧(如果有)以查看您是否通过了限制,以及在什么情况下方向。

在我看来,四元数的主要观点是你不需要为这样的限制而烦恼。一切正常,没有任何奇点。为什么要限制音高?

【讨论】:

【参考方案3】:

相机旋转四元数可以定义为:

vector A = [x, y, z] 
Q.x = A.x * sin(theta/2)
Q.y = A.y * sin(theta/2)
Q.z = A.z * sin(theta/2)
Q.w = cos(theta/2)

其中 A 是位置,theta 是您要旋转相机的角度(调整俯仰角)。

因此,如果您有可用的四元数,则可以通过每次验证旋转角度加/减实际角度是否正常来限制俯仰角度。

我认为,如果您将限制设置为,则可以避免转换

+cos(supLim/2) < (Q.w + P.w) < -cos(infLim/2)

因为余弦是一个连续函数,所以它应该可以工作。

如果您可以发布您实际使用的代码,也许我们可以提供更多帮助。

【讨论】:

嗯.. A 不是旋转轴吗?如果超出限制,我该如何将四元数设置为音高限制? A 绝对是作为单位向量的轴。即使“位置”是一个错字,答案也只有在 Q 已经只是俯仰旋转而不是总相机旋转 C 时才有效。我们正在尝试从 C 中提取 Q。【参考方案4】:

我可能有点迟到了,但这就是我解决它的方法:

        // "Up" = local vector -> rotation * Vector3.UnitY
        // "Forward" = local vector -> rotation * Vector3.UnitZ
        // "Right" = local vector -> rotation * Vector3.UnitX

    public void Rotate(Vector3 axis, float angle)
    
        if (LerpRotation)
        
            RotationTarget *= Quaternion.FromAxisAngle(axis, angle);
        
        else
        
            Rotation *= Quaternion.FromAxisAngle(axis, angle);
        
        //Locking the Pitch in 180°
        float a = Vector3.CalculateAngle(Vector3.UnitY, Up);
        float sign = Math.Sign(Forward.Y);
        float delta = (float)Math.PI / 2 - a;
        if(delta < 0)
            Rotation *= Quaternion.FromAxisAngle(Right, delta * sign);
    

【讨论】:

以上是关于限制相机间距的主要内容,如果未能解决你的问题,请参考以下文章

离子电容器:如何从相机选项中限制图库?

如何检测相机是不是受用户限制

Android相机录制时间限制和最大尺寸

固定参数的相机标定

将图像保存到特定相册,但限制保存到相机胶卷文件夹

如何限制相机在 Y 轴上的旋转?帮我 §