2

I'm currently trying to write a LookAt function in C++ with the Source SDK. I did some research and found many links but many of this were about Unity or Glm and were using quaternions and rotation matrix, but I don't need this.

So, here is my problem:
I'm in Portal 2. I have a Target with position coordinates x, y, z and I have the position of my player and his rotation in degrees (yaw, pitch, roll). When I use my function with the target coordinates as parameters, I want my player to look at the target.
I found this : Point look at Point but it doesn't work really well, the final angle was never good.

I think it's because in Portal 2, if I refer to this image:
For rotation, the yaw axis correspond to the y coordinate in the game, the pitch is the z one (from back to front of the player), and the roll is the x one.

For translation :
The z axis of the image correspond to the z axis in the game, the y is the x one, and the x is the y one.

It's pretty hard for me to adapt codes I found on internet to my needs.
Could you help me for this ?

Thank you in advance.

The code I currently have is this one :

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 };
meowgoesthedog
  • 14,670
  • 4
  • 27
  • 40
PortalBlend
  • 31
  • 1
  • 5
  • Here's an explanation of how the lookAt function works: https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/lookat-function – Serket Mar 01 '21 at 12:29

2 Answers2

3

I assume you wanted camera is a 4x4 homogenous transform matrix

What you need for propper implementing of look at is:

  1. camera position pos

    as this is for player so your position is fixed and known ...

  2. target position target

  3. view direction dir

    can be simply computed by:

     dir = target-pos
     dir /= |dir|
    
  4. some align direction (like UP)

    this one depends on your game ... for terrain based games you can use UP vector (like (0,1,0)) or normal to surface etc ... for 6 DOF based apps you can use some player local vector ... Be careful this align vector must not be parallel to dir otherwise the cross product latter would not work properly. In such case you can chose different align vector like RIGHT,NORT,etc.

To construct a 3D transform matrix you need position O and 3 basis vectors (X,Y,Z) which are unit and perpendicular to each other. The position is pos and one of the basis vectors is the dir (which depends on which axis is your looking one for example perspective OpenGL uses usually -Z). So what you need is to compute the other two basis vectors. Let us consider we will be viewing in -Z direction so:

-Z =  dir
 Z = -dir

to get the other 2 basis vectors just exploit cross product ...

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

and the origin is simply the camera position:

O = pos

The order of operands inside cross will determine the sign of the result so in case you got reversed some axis just swap the operands ...

Now just simply feed O,X,Y,Z into unit 4x4 matrix. How depends on the notation your engine is using. As camera is usually inverted (also depends on notation) then invert it and you got your resulting matrix. Here OpenGL layout:

OpenGL matrix layout

In case you need Euler angles extract them from the matrix using goniometry...

Spektre
  • 49,595
  • 11
  • 110
  • 380
1

Thank you very much for your answer ! It really helped me.

Your post helped me to have a clearer idea on what I should do in order to make this function working.

I didn't use quaternion or rotation maxtrix, cause it was a bit too complex for a so simpler function. Here's my code for those who would like to implement it:

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);
}

Thank you again !

PortalBlend
  • 31
  • 1
  • 5