Поворот персонажа через кватернион

S0Ft1k1337

Новичок
Автор темы
11
3
Всем привет!
Пытался повернуть персонажа на определенные игровые координаты через кватернион, но в результате получается полная вакханалия.

Большое спасибо @SR_team за открытые исходники

Сам кватернион:
struct Quaternion {
    float fW, fX, fY, fZ;
};

void SetQuaternion()( const Quaternion &quater ) {
    float SquarredQuaterW = 0.0f, SquarredQuaterX = 0.0f, SquarredQuaterY = 0.0f, SquarredQuaterZ = 0.0f;

    SquarredQuaterW = quater.fW * quater.fW;
    SquarredQuaterX = quater.fX * quater.fX;
    SquarredQuaterY = quater.fY * quater.fY;
    SquarredQuaterZ = quater.fZ * quater.fZ;
    right.fX        = SquarredQuaterX - SquarredQuaterY - SquarredQuaterZ + SquarredQuaterW;
    up.fY            = SquarredQuaterY - SquarredQuaterX - SquarredQuaterZ + SquarredQuaterW;
    at.fZ            = SquarredQuaterZ - ( SquarredQuaterY + SquarredQuaterX ) + SquarredQuaterW;

    float multXY = quater.fX * quater.fY;
    float multWZ = quater.fW * quater.fZ;
    up.fX         = multWZ + multXY + multWZ + multXY;
    right.fY     = multXY - multWZ + multXY - multWZ;

    float multXZ = quater.fX * quater.fZ;
    float multWY = quater.fW * quater.fY;
    at.fX         = multXZ - multWY + multXZ - multWY;
    right.fZ     = multWY + multXZ + multWY + multXZ;

    float multYZ = quater.fY * quater.fZ;
    float multWX = quater.fW * quater.fX;
    at.fY         = multWX + multYZ + multWX + multYZ;
    up.fZ         = multYZ - multWX + multYZ - multWX;
}

Quaternion GetQuaternion() {
    long double v13; // st7@1
    long double v14; // st7@3
    long double v15; // st5@5
    float        v16; // st6@5
    float        v17; // st7@5
    long double v18; // st6@7
    Quaternion    result;
    float        v23; // [sp+10h] [bp-20h]@7
    float        v24; // [sp+18h] [bp-18h]@9

    v13 = right.fX + up.fY + at.fZ + 1.0f;
    if ( v13 < 0.0f ) v13 = 0.0f;
    result.fW = (float)sqrt( v13 ) * 0.5f;
    v14          = right.fX + 1.0 - up.fY - at.fZ;
    if ( v14 < 0.0f ) v14 = 0.0f;
    v17 = (float)sqrt( v14 ) * 0.5f;
    v16 = 1.0f - right.fX;
    v15 = up.fY + v16 - at.fZ;
    if ( v15 < 0.0f ) v15 = 0.0f;
    v23 = (float)sqrt( v15 ) * 0.5f;
    v18 = v16 - up.fY + at.fZ;
    if ( v18 < 0.0f ) v18 = 0.0f;
    v24 = (float)sqrt( v18 ) * 0.5f;
    if ( result.fW < 0.0f ) result.fW = 0.0f;
    if ( v17 < 0.0f ) v17 = 0.0f;
    if ( v23 < 0.0f ) v23 = 0.0f;
    if ( v24 < 0.0f ) v24 = 0.0f;
    result.fX = (float)copysign( v17, at.fY - up.fZ );
    result.fY = (float)copysign( v23, right.fZ - at.fX );
    result.fZ = (float)copysign( v24, up.fX - right.fY );

    return result;
}

Функция поворота:
float GetAngleBetweenObjectsRad(float& x1, float& y1, float& x2, float& y2)
{
    float kx, ky;
    float t, a;

    kx = x2 - x1;
    ky = y2 - y1;
    if (kx == 0) kx = 0.00001f;
    t = kx / ky;
    if (t < 0) t = -t;

    a = (float)(180 * atan((float)t) / 3.1415);

    if ((kx <= 0) && (ky <= 0)) a = 180 - a;
    else if ((kx >= 0) && (ky >= 0)) a = 359.99999f - a;
    else if ((kx >= 0) && (ky <= 0)) a = -(180 - a);

    a = (a * 3.1415) / 180.0f;

    return a;
}

void RotateTo(CVector& vec)
{
    
    auto me = LOCAL_PLAYER->getPosition();
    float angle = -GetAngleBetweenObjectsRad(me.fX, me.fY, vec.fX, vec.fY);

    auto quat = GetQuaternion();
    quat.fX = cosf(angle / 2);
    quat.fW = sinf(angle / 2);
    SetQuaternion(quat);
}
 
  • Нравится
Реакции: Ya Zaregalsya

Vintik

Мечтатель
Проверенный
1,449
900
C++:
float GetAngleBetweenObjectsRad(float& x1, float& y1, float& x2, float& y2)
{
    float kx, ky;
    float t, a;

    kx = x2 - x1;
    ky = y2 - y1;
    if (kx == 0) kx = 0.00001f;
    t = kx / ky;
    if (t < 0) t = -t;

    a = (float)(180 * atan((float)t) / 3.1415);

    if ((kx <= 0) && (ky <= 0)) a = 180 - a;
    else if ((kx >= 0) && (ky >= 0)) a = 359.99999f - a;
    else if ((kx >= 0) && (ky <= 0)) a = -(180 - a);

    a = (a * 3.1415) / 180.0f;

    return a;
}
Если что, чтобы выглядело более красиво можно юзать atan2.
C++:
#include <cmath>

float GetAngleBetweenObjectsRad(float& x1, float& y1, float& x2, float& y2)
{
    return atan2(x2 - x1, y2 - y1);
}
Не очень понял что значит "через кватернион", можно же просто изменить угол поворота в системе XOY (heading).
 
Последнее редактирование:

S0Ft1k1337

Новичок
Автор темы
11
3
Не очень понял что значит "через кватернион", можно же просто изменить угол поворота в системе XOY (heading).
Можно конечно, но как ты его повернешь на игровые координаты мира
 

Vintik

Мечтатель
Проверенный
1,449
900
Можно конечно, но как ты его повернешь на игровые координаты мира
Очень просто, если я тебя верно понял.
C++:
#include <cmath>

float GetAngleBetweenObjectsRad(float& x1, float& y1, float& x2, float& y2)
{
    return atan2(x2 - x1, y2 - y1);
}

float TurnToCoordinates(DWORD& cped, float& x, float& y)
{
    DWORD mt = *(DWORD*)(cped + 0x14);
    float px = *(float*)(mt + 0x30), py = *(float*)(mt + 0x34);
    float heading = GetAngleBetweenObjectsRad(px, py, x, y);
    *(float*)(cped + 0x55C) = heading; // фактический угол поворота
    *(float*)(cped + 0x558) = heading; // чтобы не было "плавного поворота". если нужно плавно - удалить строку
}

void Main()
{
     // поворачиваем нашего игрока, чтобы он смотрел в сторону координат x = 100, y = 50
    DWORD myPlayer = *(DWORD*)(0xB6F5F0);
    TurnToCoordinates(myPlayer, 100, 50);
}
 
  • Нравится
Реакции: Ya Zaregalsya