Автор Тема: Ротация и Матрица  (Прочитано 3848 раз)

Оффлайн Saint

  • Прохожий
  • *
  • Сообщений: 83
  • Репутация: +1/-0
  • Saint Games
    • saint36rus
    • Просмотр профиля
Ротация и Матрица
« : Февраль 23, 2020, 11:38:53 pm »
в Игре есть опкоды

0453 установить объекту Ротацию, но нет опкода чтобы её узнать

написал я вот такие функции, но видимо что-то тут не верно у меня, прошу пожалуйста помощи

По оси Z вроде как определяет верно при условии что опкод 0176 (get_object_z_angle) это и есть Ротация по Оси Z

но с X и Y беда(

Код: C++
  1. float CObject::GetObjectRotX() // RC 8-2 T13 // RC 8-3
  2. {//------------------------------------------------------------------------------------------------------------------------
  3.  
  4.         if (m_pObject) // m_pObject = GamePool_Object_GetAt(m_dwObjectGameID);
  5.         {
  6.                 //-----------------------------------------------------------------------------------------------------------------
  7.  
  8.                 float fRotX = atan2(-m_pObject->physical.entity.placeable.matMatrix.vLookAt.X, m_pObject->physical.entity.placeable.matMatrix.vLookAt.Y) * 180.0f/PI;
  9.  
  10.                 // Bound it to [0, 360)
  11.                 while(fRotX < 0.0f)
  12.                         fRotX += 360.0f;
  13.                 while(fRotX >= 360.0f)
  14.                         fRotX -= 360.0f;
  15.                
  16.                 //-----------------------------------------------------------------------------------------------------------------
  17.  
  18.                 return fRotX;
  19.         }
  20.  
  21.         return 0;
  22.  
  23. }//------------------------------------------------------------------------------------------------------------------------
  24.  
  25. float CObject::GetObjectRotY() // RC 8-2 T13 // RC 8-3
  26. {//------------------------------------------------------------------------------------------------------------------------
  27.  
  28.         if (m_pObject) // m_pObject = GamePool_Object_GetAt(m_dwObjectGameID);
  29.         {
  30.                 //-----------------------------------------------------------------------------------------------------------------
  31.  
  32.                 float fRotY = atan2(-m_pObject->physical.entity.placeable.matMatrix.vLookRight.X, m_pObject->physical.entity.placeable.matMatrix.vLookRight.Y) * 180.0f/PI;
  33.  
  34.                 // Bound it to [0, 360)
  35.                 while(fRotY < 0.0f)
  36.                         fRotY += 360.0f;
  37.                 while(fRotY >= 360.0f)
  38.                         fRotY -= 360.0f;
  39.                
  40.                 //-----------------------------------------------------------------------------------------------------------------
  41.  
  42.                 return fRotY;
  43.         }
  44.  
  45.         return 0;
  46.  
  47. }//------------------------------------------------------------------------------------------------------------------------
  48.  
  49. float CObject::GetObjectRotZ() // RC 8-2 T13 // RC 8-3
  50. {//------------------------------------------------------------------------------------------------------------------------
  51.  
  52.         if (m_pObject) // m_pObject = GamePool_Object_GetAt(m_dwObjectGameID);
  53.         {
  54.                 //-----------------------------------------------------------------------------------------------------------------
  55.  
  56.                 float fRotZ = atan2(-m_pObject->physical.entity.placeable.matMatrix.vLookUp.X, m_pObject->physical.entity.placeable.matMatrix.vLookUp.Y) * 180.0f/PI;
  57.  
  58.                 // Bound it to [0, 360)
  59.                 while(fRotZ < 0.0f)
  60.                         fRotZ += 360.0f;
  61.                 while(fRotZ >= 360.0f)
  62.                         fRotZ -= 360.0f;
  63.                
  64.                 //-----------------------------------------------------------------------------------------------------------------
  65.  
  66.                 return fRotZ;
  67.         }
  68.  
  69.         return 0;
  70.  
  71. }//------------------------------------------------------------------------------------------------------------------------
  72.  
« Последнее редактирование: Февраль 24, 2020, 12:59:27 am от Saint »

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #1 : Февраль 24, 2020, 12:42:33 am »
Вот пример опкодов получения/задания поворотов транспорта в New Epic Opcodes(всё то же самое применимо для педов и объектов):

Код: C++
  1. //0E24=4,store_vehicle %1d% rotation_to %2d% %3d% %4d%
  2. eOpcodeResult WINAPI StoreVehicleRotation(CScript* script)
  3. {
  4.         script->Collect(1);
  5.         unsigned int VehicleStruct = _GetVehicleStructByHandle(Params[0].nVar);
  6.         float VehicleRotMatrix[9];
  7.         VehicleRotMatrix[0] = *(float *)(VehicleStruct + 0x04);
  8.         VehicleRotMatrix[1] = *(float *)(VehicleStruct + 0x04 + 0x04);
  9.         VehicleRotMatrix[2] = *(float *)(VehicleStruct + 0x04 + 0x08);
  10.         VehicleRotMatrix[3] = *(float *)(VehicleStruct + 0x04 + 0x10);
  11.         VehicleRotMatrix[4] = *(float *)(VehicleStruct + 0x04 + 0x14);
  12.         VehicleRotMatrix[5] = *(float *)(VehicleStruct + 0x04 + 0x18);
  13.         VehicleRotMatrix[6] = *(float *)(VehicleStruct + 0x04 + 0x20);
  14.         VehicleRotMatrix[7] = *(float *)(VehicleStruct + 0x04 + 0x24);
  15.         VehicleRotMatrix[8] = *(float *)(VehicleStruct + 0x04 + 0x28);
  16.         float VehicleAngleXaYaZa[3];
  17.         RotationMatrixToEulerianAngle((float *)VehicleRotMatrix, (float *)VehicleAngleXaYaZa);
  18.         EulerianAngleNormalize360((float *)VehicleAngleXaYaZa);
  19.         Params[0].fVar = VehicleAngleXaYaZa[0];
  20.         Params[1].fVar = VehicleAngleXaYaZa[1];
  21.         Params[2].fVar = VehicleAngleXaYaZa[2];
  22.         script->Store(3);
  23.         return OR_CONTINUE;
  24. }
  25.  
  26. //0E25=4,set_vehicle %1d% rotation %2d% %3d% %4d%
  27. eOpcodeResult WINAPI SetVehicleRotation(CScript* script)
  28. {
  29.         script->Collect(4);
  30.         unsigned int VehicleStruct = _GetVehicleStructByHandle(Params[0].nVar);
  31.         float VehicleAngleXaYaZa[3];
  32.         VehicleAngleXaYaZa[0] = Params[1].fVar;
  33.         VehicleAngleXaYaZa[1] = Params[2].fVar;
  34.         VehicleAngleXaYaZa[2] = Params[3].fVar;
  35.         float VehicleRotMatrix[9];
  36.         EulerianAngleToRotationMatrix((float *)VehicleAngleXaYaZa, (float *)VehicleRotMatrix);
  37.         *(float *)(VehicleStruct + 0x04) = VehicleRotMatrix[0];
  38.         *(float *)(VehicleStruct + 0x04 + 0x04) = VehicleRotMatrix[1];
  39.         *(float *)(VehicleStruct + 0x04 + 0x08) = VehicleRotMatrix[2];
  40.         *(float *)(VehicleStruct + 0x04 + 0x10) = VehicleRotMatrix[3];
  41.         *(float *)(VehicleStruct + 0x04 + 0x14) = VehicleRotMatrix[4];
  42.         *(float *)(VehicleStruct + 0x04 + 0x18) = VehicleRotMatrix[5];
  43.         *(float *)(VehicleStruct + 0x04 + 0x20) = VehicleRotMatrix[6];
  44.         *(float *)(VehicleStruct + 0x04 + 0x24) = VehicleRotMatrix[7];
  45.         *(float *)(VehicleStruct + 0x04 + 0x28) = VehicleRotMatrix[8];
  46.         return OR_CONTINUE;
  47. }

Как видно из кода, там происходит перевод матриц поворота в углы Эйлера, и обратно.
Для этих нужд были написаны на основе примеров в инете и частей кода SA(т.к. у GTA "своя атмосфера" и не всё из интернета к ней применимо) следующие функции:

Код: C++
  1. void RotationMatrixToEulerianAngle(float* RotMx, float* EulAng)
  2. {
  3.         //double rm00 = RotMx[3*0+0];
  4.         //double rm01 = RotMx[3*0+1];
  5.         double rm02 = RotMx[3*0+2];
  6.         double rm10 = RotMx[3*1+0];
  7.         double rm11 = RotMx[3*1+1];
  8.         double rm12 = RotMx[3*1+2];
  9.         //double rm20 = RotMx[3*2+0];
  10.         //double rm21 = RotMx[3*2+1];
  11.         double rm22 = RotMx[3*2+2];
  12.         EulAng[2] = (float)(-atan2(rm10, rm11) * 57.295776);
  13.         EulAng[0] = (float)(-asin(-rm12) * 57.295776);
  14.         EulAng[1] = (float)(-atan2(rm02, rm22) * 57.295776);
  15. }
  16.  
  17. void EulerianAngleNormalize360(float* EulAng)
  18. {
  19.         if(EulAng[0]<0) EulAng[0] = EulAng[0] + 360;
  20.         if(EulAng[0]>=360) EulAng[0] = EulAng[0] - 360;
  21.         if(EulAng[1]<0) EulAng[1] = EulAng[1] + 360;
  22.         if(EulAng[1]>=360) EulAng[1] = EulAng[1] - 360;
  23.         if(EulAng[2]<0) EulAng[2] = EulAng[2] + 360;
  24.         if(EulAng[2]>=360) EulAng[2] = EulAng[2] - 360;
  25. }
  26.  
  27. void EulerianAngleToRotationMatrix(float* EulAng, float* RotMx)
  28. {
  29.         double cosx = cos(EulAng[0] / 57.295776);
  30.         double sinx = sin(EulAng[0] / 57.295776);
  31.         double cosy = cos(EulAng[1] / 57.295776);
  32.         double siny = sin(EulAng[1] / 57.295776);
  33.         double cosz = cos(EulAng[2] / 57.295776);
  34.         double sinz = sin(EulAng[2] / 57.295776);
  35.         RotMx[3*0+0] = (float)(cosz * cosy - sinz * sinx * siny);
  36.         RotMx[3*0+1] = (float)(cosz * sinx * siny + sinz * cosy);
  37.         RotMx[3*0+2] = (float)(-cosx * siny);
  38.         RotMx[3*1+0] = (float)(-sinz * cosx);
  39.         RotMx[3*1+1] = (float)(cosz * cosx);
  40.         RotMx[3*1+2] = (float)(sinx);
  41.         RotMx[3*2+0] = (float)(sinz * sinx * cosy + cosz * siny);
  42.         RotMx[3*2+1] = (float)(sinz * siny - cosz * sinx * cosy);
  43.         RotMx[3*2+2] = (float)(cosx * cosy);
  44. }
« Последнее редактирование: Февраль 24, 2020, 12:45:09 am от Shagg_E »

Оффлайн Saint

  • Прохожий
  • *
  • Сообщений: 83
  • Репутация: +1/-0
  • Saint Games
    • saint36rus
    • Просмотр профиля
Re: Ротация и Матрица
« Ответ #2 : Февраль 24, 2020, 12:57:15 am »
и как мне это применить к моей матрице?

Код: C++
  1. typedef struct _MATRIX4X4 // RwMatrix struc ; (sizeof=0x40) // 64  байта
  2. {
  3.         VECTOR vLookRight; // 4 + 4 + 4 // 12
  4.         float  pad_r;                                   // 16
  5.  
  6.         VECTOR vLookUp;                                 // 28 // top // Rotation
  7.         float  pad_u;                                   // 32
  8.  
  9.         VECTOR vLookAt;                                 // 44
  10.         float  pad_a;                                   // 48
  11.  
  12.         VECTOR vPos;                                    // 60
  13.         float  pad_p;                                   // 64
  14.  
  15. } MATRIX4X4, *PMATRIX4X4;
  16.  
« Последнее редактирование: Февраль 24, 2020, 12:59:48 am от Saint »

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #3 : Февраль 24, 2020, 03:27:12 am »
и как мне это применить к моей матрице?

Это тоже самое, просто у тебя она подписана, а у меня сразу берутся значения из адресов. Вот, смотри:

Код: C++
  1.         // Это вектор vLookRight:
  2.         VehicleRotMatrix[0] = *(float *)(VehicleStruct + 0x04);
  3.         VehicleRotMatrix[1] = *(float *)(VehicleStruct + 0x04 + 0x04);
  4.         VehicleRotMatrix[2] = *(float *)(VehicleStruct + 0x04 + 0x08);
  5.  
  6.         // float  pad_r нам не нужен(он то ли не используется, то ли юзается для какой-то фигни - где-то на SannyBuilder то ли Seeman то ли Listener об этом писали), поэтому оффсет *(float *)(VehicleStruct + 0x04 + 0x0C) я пропустил.
  7.  
  8.         // Далее - ветор vLookUp:
  9.         VehicleRotMatrix[3] = *(float *)(VehicleStruct + 0x04 + 0x10);
  10.         VehicleRotMatrix[4] = *(float *)(VehicleStruct + 0x04 + 0x14);
  11.         VehicleRotMatrix[5] = *(float *)(VehicleStruct + 0x04 + 0x18);
  12.  
  13.         // опять же - пропускаем float  pad_u, поэтому оффсет *(float *)(VehicleStruct + 0x04 + 0x1C) идет лесом
  14.  
  15.         // ну и наконец - последние 3 значения матрицы поворота - vLookAt:
  16.         VehicleRotMatrix[6] = *(float *)(VehicleStruct + 0x04 + 0x20);
  17.         VehicleRotMatrix[7] = *(float *)(VehicleStruct + 0x04 + 0x24);
  18.         VehicleRotMatrix[8] = *(float *)(VehicleStruct + 0x04 + 0x28);
  19.  
  20.         // опять же - пропускаем float  pad_a, поэтому оффсет *(float *)(VehicleStruct + 0x04 + 0x2C) идет туда же, что и предыдущие
  21.  

У тебя представлена полная матрица позиции и поворота(4x4, 16 значений), поэтому внизу затесались еще VECTOR vPos и последняя "пустышка" float  pad_p, поэтому в данном случае просто не юзай их.

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #4 : Февраль 26, 2020, 06:55:00 pm »
Да, вектором в RW называется последовательность трех значений XYZ. Не всегда это стоит воспринимать как буквально координаты XYZ, просто привыкни, что это 3 значения.

Оффлайн Saint

  • Прохожий
  • *
  • Сообщений: 83
  • Репутация: +1/-0
  • Saint Games
    • saint36rus
    • Просмотр профиля
Re: Ротация и Матрица
« Ответ #5 : Февраль 26, 2020, 06:57:46 pm »
Да, вектором в RW называется последовательность трех значений XYZ. Не всегда это стоит воспринимать как буквально координаты XYZ, просто привыкни, что это 3 значения.

да то я немного тупанул, не увидел твой последний ответ (усталость)

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #6 : Февраль 26, 2020, 07:01:50 pm »
да то я немного тупанул, не увидел твой последний ответ (усталость)
Знакомая история) Береги здоровье и сон, чувак!

Оффлайн Saint

  • Прохожий
  • *
  • Сообщений: 83
  • Репутация: +1/-0
  • Saint Games
    • saint36rus
    • Просмотр профиля
Re: Ротация и Матрица
« Ответ #7 : Февраль 26, 2020, 07:11:16 pm »
да то я немного тупанул, не увидел твой последний ответ (усталость)
Знакомая история) Береги здоровье и сон, чувак!

короче получилась у меня такая функция вот

Код: C++
  1. void CObject::GetObjectRotation(float * fRotX, float * fRotY, float * fRotZ)
  2. {//------------------------------------------------------------------------------------------------------------------------
  3.  
  4.         if (m_pObject) // m_pObject = GamePool_Object_GetAt(m_dwObjectGameID);
  5.         {
  6.                 //ScriptCommand(&get_object_rotation, m_dwObjectGameID, X, Y, Z); // none opcode
  7.  
  8.                 float VehicleRotMatrix[9];
  9.  
  10.         VehicleRotMatrix[0] = m_pObject->physical.entity.placeable.matMatrix.vLookRight.X;
  11.         VehicleRotMatrix[1] = m_pObject->physical.entity.placeable.matMatrix.vLookRight.Y;
  12.         VehicleRotMatrix[2] = m_pObject->physical.entity.placeable.matMatrix.vLookRight.Z;
  13.  
  14.         VehicleRotMatrix[3] = m_pObject->physical.entity.placeable.matMatrix.vLookUp.X;
  15.         VehicleRotMatrix[4] = m_pObject->physical.entity.placeable.matMatrix.vLookUp.Y;
  16.         VehicleRotMatrix[5] = m_pObject->physical.entity.placeable.matMatrix.vLookUp.Z;
  17.  
  18.         VehicleRotMatrix[6] = m_pObject->physical.entity.placeable.matMatrix.vLookAt.X;
  19.         VehicleRotMatrix[7] = m_pObject->physical.entity.placeable.matMatrix.vLookAt.Y;
  20.         VehicleRotMatrix[8] = m_pObject->physical.entity.placeable.matMatrix.vLookAt.Z;
  21.  
  22.         float VehicleAngleXaYaZa[3];
  23.  
  24.         RotationMatrixToEulerianAngle((float *)VehicleRotMatrix, (float *)VehicleAngleXaYaZa);
  25.         EulerianAngleNormalize360((float *)VehicleAngleXaYaZa);
  26.  
  27.         *fRotX = VehicleAngleXaYaZa[0];
  28.         *fRotY = VehicleAngleXaYaZa[1];
  29.         *fRotZ = VehicleAngleXaYaZa[2];
  30.  
  31.         }
  32.  

вот так узнаём

нашу ротацию

Код: C++
  1.         float *fRot[3];
  2.  
  3.         GetObjectRotation(fRot[0], fRot[1], fRot[2]);
  4.  

но при попытке вывода на экран fRot[0], fRot[1], fRot[2] игра вылетает  :(

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #8 : Февраль 26, 2020, 07:56:42 pm »
Попробуй так:
Код: C++
  1.         float fRot[3];
  2.  
  3.         GetObjectRotation((float *)fRot);
Ну и в самой функции, соответственно, заюзать так:
Код: C++
  1. void CObject::GetObjectRotation(float * fRotXYZ)
  2. {//------------------------------------------------------------------------------------------------------------------------
  3.  
  4.         //...
  5.  
  6.         fRotXYZ[0] = VehicleAngleXaYaZa[0];
  7.         fRotXYZ[1] = VehicleAngleXaYaZa[1];
  8.         fRotXYZ[2] = VehicleAngleXaYaZa[2];
  9.  
  10.         }

Оффлайн Saint

  • Прохожий
  • *
  • Сообщений: 83
  • Репутация: +1/-0
  • Saint Games
    • saint36rus
    • Просмотр профиля
Re: Ротация и Матрица
« Ответ #9 : Февраль 26, 2020, 08:08:55 pm »
разобрался с ошибкой, короче работает, но не совсем верно

в принципе верно, но не совсем

допустим если менять Ротацию по Очереди сначало по X = 90, 180, 270, а Y и Z оставлять = 0
потом меняем только Y
потом только Z

вообщем суть проблемы в чём пололение объекта в пространстве например X 0 Y 0 Z 180
это тоже самое что и X 180 Y 180 Z 0

но если я меняю ротацию объкту на X 0 Y 0 Z 180 показует верно
а если я меняю ротацию на X 180 Y 180 Z 0 то функция мне выдаёт X 0 Y 0 Z 180, а по идеи должно быть X 180 Y 180 Z 0
я знаю что это одно и тоже как бы, но это не одно и тоже  ???

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #10 : Февраль 26, 2020, 08:13:29 pm »
Ну это не ошибка, а известная проблема углов Эйлера.
Именно поэтому, а также из-за так называемого Gimbal lock в реальных расчетах в 3D юзают кватернионы и матрицы поворота.

Оффлайн Saint

  • Прохожий
  • *
  • Сообщений: 83
  • Репутация: +1/-0
  • Saint Games
    • saint36rus
    • Просмотр профиля
Re: Ротация и Матрица
« Ответ #11 : Февраль 26, 2020, 08:20:43 pm »
Ну это не ошибка, а известная проблема углов Эйлера.
Именно поэтому, а также из-за так называемого Gimbal lock в реальных расчетах в 3D юзают кватернионы и матрицы поворота.

так как же мне сделать именно так как надо? есть вариант?

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #12 : Февраль 26, 2020, 08:24:12 pm »
так как же мне сделать именно так как надо? есть вариант?
Ну это зависит от твоих целей. Если X 180 Y 180 Z 0 и X 0 Y 0 Z 180 с технической стороны - это одно и то же, почему тебе это не подходит?

Оффлайн Saint

  • Прохожий
  • *
  • Сообщений: 83
  • Репутация: +1/-0
  • Saint Games
    • saint36rus
    • Просмотр профиля
Re: Ротация и Матрица
« Ответ #13 : Февраль 26, 2020, 08:30:59 pm »
так как же мне сделать именно так как надо? есть вариант?
Ну это зависит от твоих целей. Если X 180 Y 180 Z 0 и X 0 Y 0 Z 180 с технической стороны - это одно и то же, почему тебе это не подходит?

я думаю потому что могут возникнуть ошибки в синхронизации Ротации между Клиентами (игроками/играми)
например когда создаётся какой нибуть шлагбаум и мы будем менять только один параметр, ну или в синхронизации объектов с которыми игрок может взаимодействовать, толкать их перемещать и т.д.

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Ротация и Матрица
« Ответ #14 : Февраль 26, 2020, 09:54:40 pm »
Лучше тогда отправлять на сервер матрицу поворота или кватернион, вместо углов Эйлера. Понятно, что это довольно затратно, но что поделать...