编写一个LookAt函数

时间:2018-11-04 17:01:01

标签: c++ math 3d camera

我目前正在尝试使用Source SDK用C ++编写LookAt函数。 我做了一些研究,发现了很多链接,但是其中许多链接是关于Unity或Glm的,并且使用了四元数和旋转矩阵,但是我不需要它。

所以,这是我的问题:
我在Portal 2中。我有一个目标,其位置坐标为x,y,z,并且我有玩家的位置及其旋转角度(偏航,俯仰,横滚)。使用目标坐标作为参数的函数时,我希望播放器查看目标。
我发现了这个问题:Point look at Point,但是效果不是很好,最终角度永远都不好。

我认为这是因为在Portal 2中,如果我引用this image
对于旋转而言,偏航轴与游戏中的y坐标相对应,俯仰角为z一(从玩家的前到后),掷骰为x一。

翻译:
图像的z轴对应于游戏中的z轴,y为x一,x为y一。

我很难适应在互联网上找到的代码以适应我的需求。
你能帮我吗?

谢谢。

我当前拥有的代码是这个:

float xdistance = pos.x - target.x;
float ydistance = pos.y - target.y;
float zdistance = pos.z - target.z;
float xzdistance = sqrtf(xdistance * xdistance + zdistance * zdistance);

//Final angle: 
QAngle a = { RAD2DEG((atan2f(ydistance, zdistance))), RAD2DEG(-(atan2f(xdistance, zdistance))), 0 };

2 个答案:

答案 0 :(得分:1)

我假设您希望相机是4x4 homogenous transform matrix

要正确实现外观,您需要的是:

  1. 相机位置pos

    因为这是给玩家的,所以您的位置是固定的并且是已知的...

  2. 目标排名target

  3. 查看方向dir

    可以简单地通过以下方式计算:

    dir = target-pos
    dir /= |dir|
    
  4. 一些对齐方向(例如UP)

    这取决于您的游戏...对于基于地形的游戏,您可以使用UP向量(例如(0,1,0))或法线对表面等...对于基于6 DOF的应用程序,您可以使用一些玩家本地向量。 .. 请注意,此对齐向量不得与dir 平行,否则叉积不能正常工作。在这种情况下,您可以选择不同的对齐向量,例如RIGHT,NORT等。

要构建3D变换矩阵,您需要位置O和3个基本向量(X,Y,Z),它们相互成直角并相互垂直。位置是pos,基本向量之一是dir(取决于您所看的是哪个轴,例如OpenGL通常使用-Z的透视图)。因此,您需要计算其他两个基本向量。让我们考虑一下,我们将朝-Z方向观看,因此:

-Z =  dir
 Z = -dir

要获取其他2个基向量,只需利用叉积...

X = cross(UP,Z)
X /= |X|
Y = cross(Z,X)
Y /= |Y|

并且原点就是相机位置:

O = pos

cross中操作数的顺序将确定结果的符号,因此如果您反转了某个轴,只需交换操作数...

现在,只需将O,X,Y,Z馈入4x4单元矩阵中即可。如何取决于您的引擎使用的符号。由于摄像机通常是倒置的(也取决于符号),因此将其倒置即可得到结果矩阵。这里是OpenGL布局:

OpenGL matrix layout

如果需要欧拉角,可以使用测角法将其从矩阵中提取出来...

答案 1 :(得分:0)

非常感谢您的回答!它真的帮助了我。

您的帖子帮助我对使该功能正常工作应该做什么有一个更清晰的认识。

我没有使用四元数或旋转maxtrix,因为它对于一个如此简单的函数来说有点太复杂了。 这是我的代码,供那些想要实现的人使用:

void TasTools::AimAtPoint(float x, float y, float z)
{
    Vector target = { y, x, z };

    //The camera is 64 units higher than the player:
    Vector campos = client->GetAbsOrigin() + client->GetViewOffset();
    campos = { campos.y, campos.x, campos.z };

    // Axis in the game, need to know it to fix up:
    //              : L - R  ; F - B ;  U - D
    // Rotation Axis:   x        z        y
    // Translation  :   y        x        z

    float xdis = target.x - campos.x;
    float ydis = target.z - campos.z;
    float zdis = target.y - campos.y;
    float xzdis = sqrtf(xdis * xdis + zdis * zdis);

    QAngle angles = { RAD2DEG(-atan2f(ydis, xzdis)), RAD2DEG(-(atan2f(-xdis, zdis))), 0 };

    engine->SetAngles(angles);
}

再次感谢您!