HLFX.Ru Forum (https://hlfx.ru/forum/index.php)
- Half-Life SDK (https://hlfx.ru/forum/forumdisplay.php?forumid=8)
-- Лажа со стрейфами (https://hlfx.ru/forum/showthread.php?threadid=3495)
Отправлено Ku2zoff 14-12-2012 в 06:16:
Назрел вопрос: что делает этот кусок кода?
C++ Source Code:
1 | for (i = 0; i < m_pStudioHeader->numbones; i++) |
3 | QuaternionMatrix( q[i], bonematrix ); |
5 | bonematrix[0][3] = pos[i][0]; |
6 | bonematrix[1][3] = pos[i][1]; |
7 | bonematrix[2][3] = pos[i][2]; |
9 | if (pbones[i].parent == -1) |
11 | if ( IEngineStudio.IsHardware() ) |
13 | ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); |
15 | // MatrixCopy should be faster... |
16 | //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); |
17 | MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); |
21 | ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); |
22 | ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); |
25 | // Apply client-side effects to the transformation matrix |
26 | StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); |
30 | ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); |
31 | ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); |
Про FX-траснформацию мне всё ясно, она на сервере не нужна. m_plighttransform это для освещения? Если да, то тоже нафиг не нужно на сервере.
StudioSlerpBones что именно интерполирует? Нужно ли это на сервере?
Отправлено Дядя Миша 14-12-2012 в 15:07:
Цитата:
Ku2zoff писал:
m_plighttransform это для освещения?
да
Цитата:
Ku2zoff писал:
StudioSlerpBones что именно интерполирует?
положение между прошлым и новым кадром.
Цитата:
Ku2zoff писал:
Нужно ли это на сервере?
Народу это не нужно. Народу плезиозавры нужны. Причём позарез.__________________
My Projects: download page
F.A.Q по XashNT
Блог разработчика в телеграме
Цитата:
C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'
Отправлено Ku2zoff 15-12-2012 в 05:22:
Дядя Миша спасибо, прояснил ситуацию 
Отправлено Ku2zoff 15-12-2012 в 14:13:
Нифга не получается. Ни портированный код с клиентки не фурычит, не перенесённый из ксаша. Причём под ксашем игра умудряется ещё и вылетать при обращении к pEdict. В исходниках движка ДМ оставил комментарий: Warning, pEdict is unused. Под GoldSRC не вылетает, но хитбоксы всё равно на полкарты. ЧЯДНТ?
Отправлено Дядя Миша 15-12-2012 в 14:42:
Ну почему у дяди Мишы всё прекрасно получается несколько раз и туда и обратно и бамп выдернули и на место вставили, а вы, толпой в пять человек уже четвертый год не можете решить ПРОСТЕЙШУЮ ПРОБЛЕМУ, почему, я не понимаю? Вам неприятно понимать что вы делаете? Вам интереснее тыкать наугад, пока не повезет или что?
__________________
My Projects: download page
F.A.Q по XashNT
Блог разработчика в телеграме
Цитата:
C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'
Отправлено Ku2zoff 15-12-2012 в 14:50:
Вроде же всё как надо делаю. Есть SV_StudioSetupBones с выкинутыми интерполяцией между анимациями и проигрыванием гейт-секвенций. Из неё вызываются ещё функции, они тоже есть. Studio Header я задаю прямо в теле SV_StudioSetupBones. bonetransform и rotationmatrix беру из движка, как и на клиенте делается. blending тоже из движка, его на сервере считать не надо. (Для стандартного халфовского блендинга).
Отправлено Дядя Миша 15-12-2012 в 14:53:
Цитата:
Ku2zoff писал:
Вроде же всё как надо делаю
engine\common\mod_studio.c - готовая рабочая реализация на классический халфовский блендинг. Для начала перенеси в игровую библиотеку её. А потом расширь до 9-way.
Я уже молчал-молчал, думал догадаются. Но куда там! В стену головой долбится куда интереснее.__________________
My Projects: download page
F.A.Q по XashNT
Блог разработчика в телеграме
Цитата:
C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'
Отправлено Ku2zoff 15-12-2012 в 14:57:
Цитата:
Дядя Миша писал:
Вам интереснее тыкать наугад
По аналогии с клиентом сделал. Ну если нет документации, как я узнаю, что нужен ещё один таинственный вызов таинственной функции откуда-нибудь из кода серверной дллки? Я StudioPlayerBlend на сервере не делал. Ну он же не повлияет на хитбоксы? Он ведь за наклоны игрока отвечает.
Добавлено 15-12-2012 в 21:57:
Цитата:
Дядя Миша писал:
engine\common\mod_studio.c - готовая рабочая реализация на классический халфовский блендинг.
Я думал, нафига этот файл вообще нужен? В sv_studio то же самое. Или я невнимательно смотрел.
Отправлено marikcool 15-12-2012 в 14:59:
ты параметры у себя в SV_StudioSetupBones местами поменял?
__________________
vk.com/skullcapstudios
Отправлено Дядя Миша 15-12-2012 в 15:03:
Цитата:
Ku2zoff писал:
Я думал, нафига этот файл вообще нужен? В sv_studio то же самое
не совсем. sv_studio.c уже полгода как валяется там неподключенный.
Это наследие.
Цитата:
marikcool писал:
ты параметры у себя в SV_StudioSetupBones местами поменял?
поменял, но сорцев пока нету. Как и говорил - после ревизии.__________________
My Projects: download page
F.A.Q по XashNT
Блог разработчика в телеграме
Цитата:
C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'
Отправлено Ku2zoff 15-12-2012 в 19:44:
Цитата:
marikcool писал:
ты параметры у себя в SV_StudioSetupBones местами поменял?
После того как поменял, начало вылетать и под Goldsrc при обращении к pEdict.
Добавлено 16-12-2012 в 02:44:
Цитата:
Дядя Миша писал:
Для начала перенеси в игровую библиотеку её.
Переносится без проблем, только не работает. То ли дело в неправильных аргументах SV_StudioSetupBones, то ли в том, что вместо float'ов в ксашдвижке используется matrix3x4.
Отправлено Ku2zoff 23-01-2014 в 08:11:
Простите, что поднимаю старую тему. Но несколько дней возни терять зря не хочется. На меня в последние дни что-то нашло, и я сделал ответную часть StudioSetupBones для 9-way blending'а на сервере. Благо, у нас теперь есть хоть какие-то исходники контр-страйка, и в них можно кое-что подглядеть 
Ошибка была в том, что для 9-way нужен, как бы это сказать, более продвинутый рассчёт угла поворота игрока по YAW. На данный момент всё работает, но не очень точно. То есть хитбоксы располагаются правильно и меняют положение в зависимости от направления взгляда игрока, только серверная часть не совсем совпадает с клиентской. Скорее всего, дело в каких-то переменных на серверной стороне. Я в подробности не вдавался и не сравнивал. Как бы то ни было, есть база для дальнейшей работы.
В туторы не пишу, потому что это не тутор, а копипаста.
Шаг первый: клиентская сторона.
Тырим код отсюдова, адаптируем код из исходников сервера контры (я делал так, но решил, что лучше перенести с клиента на сервер, а не наоборот), или пишем свой. Компилим клиент, подменяем player.mdl и нужную модельку игрока, корректируем анимации - вуаля! На клиенте у нас есть всё, что нужно.
Шаг второй: серверная сторона. Рассчёт углов поворота и прочей ереси игрока.
Открываем player.cpp и копипастим туда в самый низ файла вот этот код:
C++ Source Code:
3 | void CBasePlayer::StudioProcessGait(void) |
5 | mstudioseqdesc_t *pseqdesc; |
6 | float dt = gpGlobals->frametime; |
14 | CalculatePitchBlend(); |
16 | void *model = GET_MODEL_PTR(ENT(pev)); |
21 | studiohdr_t *pstudiohdr = (studiohdr_t *)model; |
23 | pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + pev->gaitsequence; |
25 | if (pseqdesc->linearmovement[0] > 0) |
26 | m_flGaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; |
28 | m_flGaitframe += pseqdesc->fps * dt * pev->framerate; |
30 | m_flGaitframe -= (int)(m_flGaitframe / pseqdesc->numframes) * pseqdesc->numframes; |
32 | if (m_flGaitframe < 0) |
33 | m_flGaitframe += pseqdesc->numframes; |
35 | // ALERT(at_notice, "Player sv_yaw: %f\n", m_flYaw); |
36 | // ALERT(at_notice, "Player sv_pitch: %f\n", m_flPitch); |
37 | // ALERT(at_notice, "Player sv_gaityaw: %f\n", m_flGaityaw); |
40 | void CBasePlayer::StudioEstimateGait(void) |
45 | dt = gpGlobals->frametime; |
58 | est_velocity[0] = pev->origin[0] - m_prevgaitorigin[0]; |
59 | est_velocity[1] = pev->origin[1] - m_prevgaitorigin[1]; |
60 | est_velocity[2] = pev->origin[2] - m_prevgaitorigin[2]; |
61 | m_prevgaitorigin[0] = pev->origin[0]; |
62 | m_prevgaitorigin[1] = pev->origin[1]; |
63 | m_prevgaitorigin[2] = pev->origin[2]; |
64 | m_flGaitMovement = sqrt(est_velocity[0] * est_velocity[0] + est_velocity[1] * est_velocity[1] + est_velocity[2] * est_velocity[2]); |
66 | if (dt <= 0 || m_flGaitMovement / dt < 5) |
69 | est_velocity[0] = est_velocity[1] = 0; |
72 | if (est_velocity[0] == 0 && est_velocity[1] == 0) |
74 | float flYawDiff = pev->angles[1] - m_flGaityaw; |
75 | float flYaw = flYawDiff; |
76 | flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; |
89 | if (flYaw > -5 && flYaw < 5) |
90 | m_flYawModifier = 0.05; |
92 | if (flYaw < -90 || flYaw > 90) |
93 | m_flYawModifier = 3.5; |
96 | flYawDiff *= dt * m_flYawModifier; |
100 | if (abs(flYawDiff) < 0.1) |
103 | m_flGaityaw += flYawDiff; |
104 | m_flGaityaw -= (int)(m_flGaityaw / 360) * 360; |
105 | m_flGaitMovement = 0; |
109 | m_flGaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); |
111 | if (m_flGaityaw > 180) |
114 | if (m_flGaityaw < -180) |
119 | void CBasePlayer::CalculateYawBlend(void) |
126 | dt = gpGlobals->frametime; |
133 | StudioEstimateGait(); |
136 | flYaw = pev->angles[1] - m_flGaityaw; |
140 | else if (flYaw > 180) |
143 | if (m_flGaitMovement != 0) |
148 | m_flGaitMovement = -m_flGaitMovement; |
151 | else if (flYaw < -120) |
154 | m_flGaitMovement = -m_flGaitMovement; |
159 | flYaw = (flYaw / 90) * 128.0 + 127.0; |
166 | blend_yaw = maxyaw - flYaw; |
167 | pev->blending[0] = (int)(blend_yaw); |
171 | void CBasePlayer::CalculatePitchBlend(void) |
176 | temp = (int)(pev->angles[0] * 3); |
181 | iBlend = ((45.0 - temp) / (45.0 + 45)) * 255; |
185 | pev->blending[1] = iBlend; |
189 | float GetPlayerYaw(const edict_t *pEdict) |
191 | entvars_t *pev = VARS((edict_t *)pEdict); |
192 | CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance(pev); |
197 | return pPlayer->m_flYaw; |
200 | float GetPlayerPitch(const edict_t *pEdict) |
202 | entvars_t *pev = VARS((edict_t *)pEdict); |
203 | CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance(pev); |
208 | return pPlayer->m_flPitch; |
211 | int GetPlayerGaitsequence(const edict_t *pEdict) |
213 | entvars_t *pev = VARS((edict_t *)pEdict); |
214 | CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance(pev); |
219 | return pPlayer->m_iGaitsequence; |
222 | float GetPlayerGaitframe(const edict_t *pEdict) |
224 | entvars_t *pev = VARS((edict_t *)pEdict); |
225 | CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance(pev); |
230 | return pPlayer->m_flGaitframe; |
233 | float GetPlayerGaitYaw(int playerIndex) |
235 | CBasePlayer *pPlayer = NULL; |
237 | if (playerIndex > 0 && playerIndex <= gpGlobals->maxClients) |
239 | edict_t *pPlayerEdict = INDEXENT(playerIndex); |
241 | if (pPlayerEdict && !pPlayerEdict->free) |
243 | pPlayer = (CBasePlayer *)CBaseEntity::Instance(pPlayerEdict); |
246 | return pPlayer->m_flGaityaw; |
Кто разобрался с клиентской частью, тот поймёт, что здесь для чего. Далее открываем player.h и добавляем в класс игрока заголовки новых функций и новые переменные:
C++ Source Code:
1 | void StudioProcessGait( void ); |
2 | void StudioEstimateGait( void ); |
3 | void CalculateYawBlend( void ); |
4 | void CalculatePitchBlend( void ); |
13 | vec3_t m_prevgaitorigin; |
Компилим, если без ошибок - всё сделали правильно. Теперь находим в player.cpp функцию void CBasePlayer::PostThink() и в самый её низ вставляем:
C++ Source Code:
m_iGaitsequence = pev->gaitsequence; |
Надо же откуда-то вызывать все эти новые рассчёты, верно?
Далее, идём в функцию Spawn игрока, она находится ниже. В самое её начало засовываем:
C++ Source Code:
m_prevgaitorigin = Vector(0, 0, 0); |
Чтобы новые переменные обнулялись при спавне. Компилим. Без ошибок - молодцы!
Шаг третий: серверная сторона. Собственно, ответная часть блендинга.
Сразу скажу, что на правильность работы этот код не претендует, т.к. я только-только начал более или менее разбираться в механизме работы студиомодельрендерера. Но, судя по моим нескольким тестам, он работает, хоть и не совсем точно.
Открываем animation.cpp (да, копипастить удобнее в него, потому что почти всё нужные заголовки уже подключены), в самый низ вставляем вот этот код:
C++ Source Code:
2 | #include "r_studioint.h" |
6 | #define M_PI 3.14159265358979323846 |
9 | void SV_StudioSetupBones( struct model_s *pModel, float frame, int sequence, const vec3_t angles, const vec3_t origin, const byte *pcontroller, const byte *pblending, int iBone, const edict_t *pEdict ); |
11 | server_studio_api_t IEngineStudio; |
12 | studiohdr_t *g_pStudioHeader; |
14 | float (*g_pRotationMatrix)[3][4]; |
15 | float (*g_pBoneTransform)[MAXSTUDIOBONES][3][4]; |
17 | sv_blending_interface_t sv_blending = |
19 | SV_BLENDING_INTERFACE_VERSION, |
23 | extern "C" _declspec(dllexport) int Server_GetBlendingInterface( int version, sv_blending_interface_t **pinterface, server_studio_api_t *pstudio, float ***rotationmatrix, float ****bonetransform ) |
25 | if (version != SV_BLENDING_INTERFACE_VERSION) |
28 | *pinterface = &sv_blending; |
30 | IEngineStudio.Mem_Calloc = pstudio->Mem_Calloc; |
31 | IEngineStudio.Cache_Check = pstudio->Cache_Check; |
32 | IEngineStudio.LoadCacheFile = pstudio->LoadCacheFile; |
33 | IEngineStudio.Mod_Extradata = pstudio->Mod_Extradata; |
35 | g_pRotationMatrix = (float (*)[3][4])rotationmatrix; |
36 | g_pBoneTransform = (float (*)[MAXSTUDIOBONES][3][4])bonetransform; |
38 | ALERT(at_console, "Server_GetBlendingInterface exported.\n"); |
Это недостающие заголовки и определения, а также код экспорта интерфейса. Ниже вставляем математические функции:
C++ Source Code:
1 | void ConcatTransforms(const float in1[3][4], const float in2[3][4], float out[3][4]) |
3 | out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; |
4 | out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; |
5 | out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; |
6 | out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3]; |
7 | out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; |
8 | out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; |
9 | out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; |
10 | out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3]; |
11 | out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; |
12 | out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; |
13 | out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; |
14 | out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; |
17 | void AngleQuaternion(const vec3_t angles, vec4_t quaternion) |
20 | float sr, sp, sy, cr, cp, cy; |
22 | angle = angles[2] * 0.5; |
25 | angle = angles[1] * 0.5; |
28 | angle = angles[0] * 0.5; |
32 | quaternion[0] = sr * cp * cy - cr * sp * sy; |
33 | quaternion[1] = cr * sp * cy + sr * cp * sy; |
34 | quaternion[2] = cr * cp * sy - sr * sp * cy; |
35 | quaternion[3] = cr * cp * cy + sr * sp * sy; |
38 | void QuaternionSlerp(const vec4_t p, vec4_t q, float t, vec4_t qt) |
41 | float omega, cosom, sinom, sclp, sclq; |
45 | for (i = 0; i < 4; i++) |
47 | a += (p[i]-q[i]) * (p[i]-q[i]); |
48 | b += (p[i]+q[i]) * (p[i]+q[i]); |
53 | for (i = 0; i < 4; i++) |
57 | cosom = p[0] * q[0] + p[1] * q[1] + p[2] * q[2] + p[3] * q[3]; |
59 | if ((1.0 + cosom) > 0.00000001) |
61 | if ((1.0 - cosom) > 0.00000001) |
65 | sclp = sin((1.0 - t) * omega) / sinom; |
66 | sclq = sin(t * omega) / sinom; |
74 | for (i = 0; i < 4; i++) |
75 | qt[i] = sclp * p[i] + sclq * q[i]; |
83 | sclp = sin((1.0 - t) * 0.5 * M_PI); |
84 | sclq = sin(t * 0.5 * M_PI); |
86 | for (i = 0; i < 3; i++) |
87 | qt[i] = sclp * p[i] + sclq * qt[i]; |
91 | void QuaternionMatrix(const vec4_t quaternion, float (*matrix)[4]) |
93 | matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2]; |
94 | matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2]; |
95 | matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1]; |
96 | matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2]; |
97 | matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2]; |
98 | matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0]; |
99 | matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1]; |
100 | matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0]; |
101 | matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1]; |
Их можно без изменений упереть из клиентской части.
А теперь очередь функций настройки костей. В чистом виде с клиента их не перенесёшь, нужна модификация. Но можно взять из ксашдвижка, что я и сделал. Вставляем ниже:
C++ Source Code:
1 | void StudioCalcBoneAdj( float *adj, const byte *pcontroller ) |
5 | mstudiobonecontroller_t *pbonecontroller; |
7 | pbonecontroller = (mstudiobonecontroller_t *)((byte *)g_pStudioHeader + g_pStudioHeader->bonecontrollerindex); |
9 | for( j = 0; j < g_pStudioHeader->numbonecontrollers; j++ ) |
11 | i = pbonecontroller[j].index; |
13 | // if( i == STUDIO_MOUTH ) |
14 | // continue; // ignore mouth |
16 | if( i <= MAXSTUDIOCONTROLLERS ) |
18 | // check for 360% wrapping |
19 | if( pbonecontroller[j].type & STUDIO_RLOOP ) |
21 | value = pcontroller[i] * (360.0f / 256.0f) + pbonecontroller[j].start; |
25 | value = pcontroller[i] / 255.0f; |
26 | if (value < 0.0f) value = 0.0f; |
27 | if (value > 1.0f) value = 1.0f; |
28 | value = (1.0f - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; |
32 | switch( pbonecontroller[j].type & STUDIO_TYPES ) |
37 | adj[j] = value * (M_PI / 180.0f); |
48 | void StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) |
52 | vec3_t angle1, angle2; |
53 | mstudioanimvalue_t *panimvalue; |
55 | for( j = 0; j < 3; j++ ) |
57 | if( panim->offset[j+3] == 0 ) |
59 | angle2[j] = angle1[j] = pbone->value[j+3]; // default; |
63 | panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); |
67 | if( panimvalue->num.total < panimvalue->num.valid ) |
70 | while( panimvalue->num.total <= k ) |
72 | k -= panimvalue->num.total; |
73 | panimvalue += panimvalue->num.valid + 1; |
75 | if( panimvalue->num.total < panimvalue->num.valid ) |
78 | // Bah, missing blend! |
79 | if( panimvalue->num.valid > k ) |
81 | angle1[j] = panimvalue[k+1].value; |
83 | if( panimvalue->num.valid > k + 1 ) |
85 | angle2[j] = panimvalue[k+2].value; |
89 | if( panimvalue->num.total > k + 1 ) |
90 | angle2[j] = angle1[j]; |
91 | else angle2[j] = panimvalue[panimvalue->num.valid+2].value; |
96 | angle1[j] = panimvalue[panimvalue->num.valid].value; |
97 | if( panimvalue->num.total > k + 1 ) |
99 | angle2[j] = angle1[j]; |
103 | angle2[j] = panimvalue[panimvalue->num.valid + 2].value; |
106 | angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; |
107 | angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; |
110 | if( pbone->bonecontroller[j+3] != -1 ) |
112 | angle1[j] += adj[pbone->bonecontroller[j+3]]; |
113 | angle2[j] += adj[pbone->bonecontroller[j+3]]; |
117 | if( !VectorCompare( angle1, angle2 )) |
119 | AngleQuaternion( angle1, q1 ); |
120 | AngleQuaternion( angle2, q2 ); |
121 | QuaternionSlerp( q1, q2, s, q ); |
125 | AngleQuaternion( angle1, q ); |
129 | void StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) |
132 | mstudioanimvalue_t *panimvalue; |
134 | for( j = 0; j < 3; j++ ) |
136 | pos[j] = pbone->value[j]; // default; |
137 | if( panim->offset[j] != 0.0f ) |
139 | panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); |
144 | if( panimvalue->num.total < panimvalue->num.valid ) |
147 | // find span of values that includes the frame we want |
148 | while( panimvalue->num.total <= k ) |
150 | k -= panimvalue->num.total; |
151 | panimvalue += panimvalue->num.valid + 1; |
154 | if( panimvalue->num.total < panimvalue->num.valid ) |
158 | // if we're inside the span |
159 | if( panimvalue->num.valid > k ) |
161 | // and there's more data in the span |
162 | if( panimvalue->num.valid > k + 1 ) |
164 | pos[j] += (panimvalue[k+1].value * (1.0f - s) + s * panimvalue[k+2].value) * pbone->scale[j]; |
168 | pos[j] += panimvalue[k+1].value * pbone->scale[j]; |
173 | // are we at the end of the repeating values section and there's another section with data? |
174 | if( panimvalue->num.total <= k + 1 ) |
176 | pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0f - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; |
180 | pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; |
185 | if( pbone->bonecontroller[j] != -1 && adj ) |
187 | pos[j] += adj[pbone->bonecontroller[j]]; |
192 | mstudioanim_t *StudioGetAnim(model_t *model, mstudioseqdesc_t *pseqdesc) |
194 | mstudioseqgroup_t *pseqgroup = (mstudioseqgroup_t *)((byte *)g_pStudioHeader + g_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; |
196 | if (!pseqdesc->seqgroup) |
197 | return (mstudioanim_t *)((byte *)g_pStudioHeader + pseqdesc->animindex); |
199 | cache_user_t *paSequences = (cache_user_t *)model->submodels; |
203 | paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc(16, sizeof(cache_user_t)); |
204 | model->submodels = (dmodel_t *)paSequences; |
207 | if (!IEngineStudio.Cache_Check(&paSequences[pseqdesc->seqgroup])) |
208 | IEngineStudio.LoadCacheFile(pseqgroup->name, &paSequences[pseqdesc->seqgroup]); |
210 | return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); |
213 | float StudioEstimateFrame( float frame, mstudioseqdesc_t *pseqdesc ) |
217 | if( pseqdesc->numframes <= 1 ) |
219 | else f = ( frame * ( pseqdesc->numframes - 1 )) / 256.0f; |
221 | if( pseqdesc->flags & STUDIO_LOOPING ) |
223 | if( pseqdesc->numframes > 1 ) |
224 | f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); |
225 | if( f < 0.0f ) f += (pseqdesc->numframes - 1); |
229 | if( f >= pseqdesc->numframes - 1.001f ) |
230 | f = pseqdesc->numframes - 1.001f; |
231 | if( f < 0.0f ) f = 0.0f; |
237 | void StudioCalcRotations( int boneused[], int numbones, const byte *pcontroller, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) |
240 | mstudiobone_t *pbone; |
241 | float adj[MAXSTUDIOCONTROLLERS]; |
244 | if( f > pseqdesc->numframes - 1 ) |
246 | else if( f < -0.01f ) |
252 | // add in programtic controllers |
253 | pbone = (mstudiobone_t *)((byte *)g_pStudioHeader + g_pStudioHeader->boneindex); |
255 | StudioCalcBoneAdj( adj, pcontroller ); |
257 | for( j = numbones - 1; j >= 0; j-- ) |
260 | StudioCalcBoneQuaterion( frame, s, &pbone[i], &panim[i], adj, q[i] ); |
261 | StudioCalcBonePosition( frame, s, &pbone[i], &panim[i], adj, pos[i] ); |
264 | if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f; |
265 | if( pseqdesc->motiontype & STUDIO_Y ) pos[pseqdesc->motionbone][1] = 0.0f; |
266 | if( pseqdesc->motiontype & STUDIO_Z ) pos[pseqdesc->motionbone][2] = 0.0f; |
269 | void StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) |
275 | if (s < 0.0f) s = 0.0f; |
276 | else if (s > 1.0f) s = 1.0f; |
279 | for( i = 0; i < g_pStudioHeader->numbones; i++ ) |
281 | QuaternionSlerp( q1[i], q2[i], s, q3 ); |
286 | pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; |
287 | pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; |
288 | pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; |
295 | ->index starts at 0 for the first set of bones |
298 | mstudioanim_t* LookupAnimation( model_t *pModel, mstudioseqdesc_t *pseqdesc, int index ) |
300 | mstudioanim_t *panim = NULL; |
302 | panim = StudioGetAnim( pModel, pseqdesc ); |
311 | if ( index > ( pseqdesc->numblends - 1 ) ) |
316 | panim += index * g_pStudioHeader->numbones; |
Остальное напишу потом, ибо просто не влазит в сообщение
Не пугайтесь
Напишите уже кто-нибудь что-нибудь, а то сообщение редактируется, а не добавляется новое.
Отправлено Ku2zoff 23-01-2014 в 13:08:
Ниже вставляете саму настройку костей:
C++ Source Code:
1 | void SV_StudioSetupBones_HL( struct model_s *pModel, float frame, int sequence, const vec3_t angles, const vec3_t origin, const byte *pcontroller, const byte *pblending, int iBone, const edict_t *pEdict ) |
3 | int i, j, numbones = 0; |
4 | int boneused[MAXSTUDIOBONES]; |
8 | mstudioseqdesc_t *pseqdesc; |
11 | static float pos[MAXSTUDIOBONES][3]; |
12 | static vec4_t q[MAXSTUDIOBONES]; |
13 | float bonematrix[3][4]; |
15 | static float pos2[MAXSTUDIOBONES][3]; |
16 | static vec4_t q2[MAXSTUDIOBONES]; |
17 | static float pos3[MAXSTUDIOBONES][3]; |
18 | static vec4_t q3[MAXSTUDIOBONES]; |
19 | static float pos4[MAXSTUDIOBONES][3]; |
20 | static vec4_t q4[MAXSTUDIOBONES]; |
22 | g_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata(pModel); |
24 | if( sequence < 0 || sequence >= g_pStudioHeader->numseq ) |
26 | ALERT( at_notice, "SV_StudioSetupBones: sequence %i/%i out of range for model %s\n", sequence, g_pStudioHeader->numseq, g_pStudioHeader->name ); |
30 | pseqdesc = (mstudioseqdesc_t *)((byte *)g_pStudioHeader + g_pStudioHeader->seqindex) + sequence; |
31 | pbones = (mstudiobone_t *)((byte *)g_pStudioHeader + g_pStudioHeader->boneindex); |
32 | panim = StudioGetAnim( pModel, pseqdesc ); |
34 | if( iBone < -1 || iBone >= g_pStudioHeader->numbones ) |
39 | numbones = g_pStudioHeader->numbones; |
40 | for( i = 0; i < g_pStudioHeader->numbones; i++ ) |
41 | boneused[(numbones - i) - 1] = i; |
45 | // only the parent bones |
46 | for( i = iBone; i != -1; i = pbones[i].parent ) |
47 | boneused[numbones++] = i; |
50 | f = StudioEstimateFrame( frame, pseqdesc ); |
51 | StudioCalcRotations( boneused, numbones, pcontroller, pos, q, pseqdesc, panim, f ); |
53 | if( pseqdesc->numblends > 1 ) |
57 | panim += g_pStudioHeader->numbones; |
58 | StudioCalcRotations( boneused, numbones, pcontroller, pos2, q2, pseqdesc, panim, f ); |
60 | s = (float)pblending[0] / 255.0f; |
62 | StudioSlerpBones( q, pos, q2, pos2, s ); |
64 | if( pseqdesc->numblends == 4 ) |
66 | panim += g_pStudioHeader->numbones; |
67 | StudioCalcRotations( boneused, numbones, pcontroller, pos3, q3, pseqdesc, panim, f ); |
69 | panim += g_pStudioHeader->numbones; |
70 | StudioCalcRotations( boneused, numbones, pcontroller, pos4, q4, pseqdesc, panim, f ); |
72 | s = (float)pblending[0] / 255.0f; |
73 | StudioSlerpBones( q3, pos3, q4, pos4, s ); |
75 | s = (float)pblending[1] / 255.0f; |
76 | StudioSlerpBones( q, pos, q3, pos3, s ); |
80 | AngleMatrix(angles, (*g_pRotationMatrix)); |
82 | (*g_pRotationMatrix)[0][3] = origin[0]; |
83 | (*g_pRotationMatrix)[1][3] = origin[1]; |
84 | (*g_pRotationMatrix)[2][3] = origin[2]; |
86 | for( j = numbones - 1; j >= 0; j-- ) |
90 | QuaternionMatrix(q[i], bonematrix); |
92 | bonematrix[0][3] = pos[i][0]; |
93 | bonematrix[1][3] = pos[i][1]; |
94 | bonematrix[2][3] = pos[i][2]; |
96 | if( pbones[i].parent == -1 ) |
97 | ConcatTransforms((*g_pRotationMatrix), bonematrix, (*g_pBoneTransform)[i]); |
99 | ConcatTransforms((*g_pBoneTransform)[pbones[i].parent], bonematrix, (*g_pBoneTransform)[i]); |
102 | ALERT(at_notice, "SV_StudioSetupBones_HL processing.\n"); |
Это функция для 2-way блендинга, если вам нужно, чтобы правильно работали монстры.
C++ Source Code:
3 | #define ANIM_FIRST_DEATH_SEQUENCE 30 |
5 | float GetPlayerYaw(const edict_t *pEdict); |
6 | float GetPlayerPitch(const edict_t *pEdict); |
7 | int GetPlayerGaitsequence(const edict_t *pEdict); |
8 | float GetPlayerGaitframe(const edict_t *pEdict); |
9 | float GetPlayerGaitYaw(int playerIndex); |
11 | void SV_StudioSetupBones( struct model_s *pModel, float frame, int sequence, const vec3_t angles, const vec3_t origin, const byte *pcontroller, const byte *pblending, int iBone, const edict_t *pEdict ) |
13 | int i, j, numbones = 0; |
14 | int boneused[MAXSTUDIOBONES]; |
17 | mstudiobone_t *pbones; |
18 | mstudioseqdesc_t *pseqdesc; |
21 | static float pos[MAXSTUDIOBONES][3]; |
22 | static vec4_t q[MAXSTUDIOBONES]; |
23 | float bonematrix[3][4]; |
25 | static float pos2[MAXSTUDIOBONES][3]; |
26 | static vec4_t q2[MAXSTUDIOBONES]; |
27 | static float pos3[MAXSTUDIOBONES][3]; |
28 | static vec4_t q3[MAXSTUDIOBONES]; |
29 | static float pos4[MAXSTUDIOBONES][3]; |
30 | static vec4_t q4[MAXSTUDIOBONES]; |
34 | if ((pEdict && !(pEdict->v.flags & FL_CLIENT)) || !pEdict) |
36 | SV_StudioSetupBones_HL( pModel, frame, sequence, angles, origin, pcontroller, pblending, iBone, pEdict ); |
40 | g_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata(pModel); |
42 | if( sequence < 0 || sequence >= g_pStudioHeader->numseq ) |
44 | ALERT( at_notice, "SV_StudioSetupBones: sequence %i/%i out of range for model %s\n", sequence, g_pStudioHeader->numseq, g_pStudioHeader->name ); |
48 | pseqdesc = (mstudioseqdesc_t *)((byte *)g_pStudioHeader + g_pStudioHeader->seqindex) + sequence; |
49 | pbones = (mstudiobone_t *)((byte *)g_pStudioHeader + g_pStudioHeader->boneindex); |
50 | panim = StudioGetAnim( pModel, pseqdesc ); |
52 | if( iBone < -1 || iBone >= g_pStudioHeader->numbones ) |
57 | numbones = g_pStudioHeader->numbones; |
58 | for( i = 0; i < g_pStudioHeader->numbones; i++ ) |
59 | boneused[(numbones - i) - 1] = i; |
63 | // only the parent bones |
64 | for( i = iBone; i != -1; i = pbones[i].parent ) |
65 | boneused[numbones++] = i; |
68 | f = StudioEstimateFrame( frame, pseqdesc ); |
70 | if ( pseqdesc->numblends == 9 ) |
72 | float s = GetPlayerYaw(pEdict); // yaw (left -> right) |
73 | float t = GetPlayerPitch(pEdict); // pitch (top -> bottom) |
75 | // nine-way blends are done left -> right, top -> bottom |
77 | /*********************** |
89 | ***********************/ |
91 | // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to Right |
94 | // Scale 0-127 blending up to 0-255 |
99 | // Blending is 0-127 == Top to Middle, 128 to 255 == Middle to Bottom |
102 | // need to blend 0 - 1 - 3 - 4 |
104 | StudioCalcRotations( boneused, numbones, pcontroller, pos, q, pseqdesc, panim, f ); |
105 | panim = LookupAnimation( pModel, pseqdesc, 1 ); |
106 | StudioCalcRotations( boneused, numbones, pcontroller, pos2, q2, pseqdesc, panim, f ); |
107 | panim = LookupAnimation( pModel, pseqdesc, 3 ); |
108 | StudioCalcRotations( boneused, numbones, pcontroller, pos3, q3, pseqdesc, panim, f ); |
109 | panim = LookupAnimation( pModel, pseqdesc, 4 ); |
110 | StudioCalcRotations( boneused, numbones, pcontroller, pos4, q4, pseqdesc, panim, f ); |
114 | // Scale 128-255 blending up to 0-255 |
115 | t = 2.0 * ( t - 127.0 ); |
117 | // need to blend 3 - 4 - 6 - 7 |
119 | panim = LookupAnimation( pModel, pseqdesc, 3 ); |
120 | StudioCalcRotations( boneused, numbones, pcontroller, pos, q, pseqdesc, panim, f ); |
121 | panim = LookupAnimation( pModel, pseqdesc, 4 ); |
122 | StudioCalcRotations( boneused, numbones, pcontroller, pos2, q2, pseqdesc, panim, f ); |
123 | panim = LookupAnimation( pModel, pseqdesc, 6 ); |
124 | StudioCalcRotations( boneused, numbones, pcontroller, pos3, q3, pseqdesc, panim, f ); |
125 | panim = LookupAnimation( pModel, pseqdesc, 7 ); |
126 | StudioCalcRotations( boneused, numbones, pcontroller, pos4, q4, pseqdesc, panim, f ); |
131 | // Scale 127-255 blending up to 0-255 |
132 | s = 2.0 * ( s - 127.0 ); |
136 | // Blending is 0-127 == Top to Middle, 128 to 255 == Middle to Bottom |
139 | // need to blend 1 - 2 - 4 - 5 |
141 | panim = LookupAnimation( pModel, pseqdesc, 1 ); |
142 | StudioCalcRotations( boneused, numbones, pcontroller, pos, q, pseqdesc, panim, f ); |
143 | panim = LookupAnimation( pModel, pseqdesc, 2 ); |
144 | StudioCalcRotations( boneused, numbones, pcontroller, pos2, q2, pseqdesc, panim, f ); |
145 | panim = LookupAnimation( pModel, pseqdesc, 4 ); |
146 | StudioCalcRotations( boneused, numbones, pcontroller, pos3, q3, pseqdesc, panim, f ); |
147 | panim = LookupAnimation( pModel, pseqdesc, 5 ); |
148 | StudioCalcRotations( boneused, numbones, pcontroller, pos4, q4, pseqdesc, panim, f ); |
152 | // Scale 128-255 blending up to 0-255 |
153 | t = 2.0 * ( t - 127.0 ); |
155 | // need to blend 4 - 5 - 7 - 8 |
157 | panim = LookupAnimation( pModel, pseqdesc, 4 ); |
158 | StudioCalcRotations( boneused, numbones, pcontroller, pos, q, pseqdesc, panim, f ); |
159 | panim = LookupAnimation( pModel, pseqdesc, 5 ); |
160 | StudioCalcRotations( boneused, numbones, pcontroller, pos2, q2, pseqdesc, panim, f ); |
161 | panim = LookupAnimation( pModel, pseqdesc, 7 ); |
162 | StudioCalcRotations( boneused, numbones, pcontroller, pos3, q3, pseqdesc, panim, f ); |
163 | panim = LookupAnimation( pModel, pseqdesc, 8 ); |
164 | StudioCalcRotations( boneused, numbones, pcontroller, pos4, q4, pseqdesc, panim, f ); |
168 | // Normalize interpolants |
172 | // Spherically interpolate the bones |
173 | StudioSlerpBones( q, pos, q2, pos2, s ); |
174 | StudioSlerpBones( q3, pos3, q4, pos4, s ); |
176 | StudioSlerpBones( q, pos, q3, pos3, t ); |
180 | StudioCalcRotations( boneused, numbones, pcontroller, pos, q, pseqdesc, panim, f ); |
183 | // calc gait animation |
184 | // death sequences are last in the list of sequences, and we don't do gait for those |
185 | // ANIM_FIRST_DEATH_SEQUENCE marks the first death sequence |
187 | sequence < ANIM_FIRST_DEATH_SEQUENCE && |
188 | sequence != ANIM_SWIM_1 && |
189 | sequence != ANIM_SWIM_2 ) |
193 | int gaitsequence = GetPlayerGaitsequence(pEdict); |
195 | if (gaitsequence >= g_pStudioHeader->numseq) |
198 | if (gaitsequence < 0) |
201 | pseqdesc = (mstudioseqdesc_t *)( (byte *)g_pStudioHeader + g_pStudioHeader->seqindex ) + gaitsequence; |
203 | panim = StudioGetAnim( pModel, pseqdesc ); |
204 | StudioCalcRotations( boneused, numbones, pcontroller, pos2, q2, pseqdesc, panim, GetPlayerGaitframe(pEdict) ); |
206 | for ( i = 0; i < g_pStudioHeader->numbones; i++ ) |
208 | if ( !strcmp( pbones[i].name, "Bip01 Spine" ) ) |
212 | else if ( !strcmp( pbones[ pbones[i].parent ].name, "Bip01 Pelvis" ) ) |
219 | memcpy( pos[i], pos2[i], sizeof( pos[i] ) ); |
220 | memcpy( q[i], q2[i], sizeof( q[i] ) ); |
225 | VectorCopy(angles, temp_angles); |
229 | temp_angles[1] = GetPlayerGaitYaw(g_engfuncs.pfnIndexOfEdict(pEdict)); |
231 | if (temp_angles[1] < 0) |
232 | temp_angles[1] += 360; |
235 | AngleMatrix(temp_angles, (*g_pRotationMatrix)); |
237 | (*g_pRotationMatrix)[0][3] = origin[0]; |
238 | (*g_pRotationMatrix)[1][3] = origin[1]; |
239 | (*g_pRotationMatrix)[2][3] = origin[2]; |
241 | for( j = numbones - 1; j >= 0; j-- ) |
245 | QuaternionMatrix(q[i], bonematrix); |
247 | bonematrix[0][3] = pos[i][0]; |
248 | bonematrix[1][3] = pos[i][1]; |
249 | bonematrix[2][3] = pos[i][2]; |
251 | if( pbones[i].parent == -1 ) |
252 | ConcatTransforms((*g_pRotationMatrix), bonematrix, (*g_pBoneTransform)[i]); |
254 | ConcatTransforms((*g_pBoneTransform)[pbones[i].parent], bonematrix, (*g_pBoneTransform)[i]); |
257 | ALERT(at_notice, "SV_StudioSetupBones processing.\n"); |
А это 9-way. При необходимости можете убрать проверку на игрока и не использовать функцию для 2-way. Вот и всё.
Отправлено Дядя Миша 23-01-2014 в 15:43:
Ну вы поглядите на него! Вроде опытный учаснег, а всю ветку каким-то говно-кодом заспамил. Ребяты, так не годится. Если ты пишешь тутор, значит к каждому кусочку кода делай пояснение что это и зачем. Но ты этого сделать не в состоянии, поскольку и сам толком не понимаешь, как это работает. Значит бери и клади в аттач, всё равно оттуда удобнее копировать, чем эти простыни из постов.
Добавлено 23-01-2014 в 19:43:
Поглядел код. Ну навскидку - лерпинг надо убрать к чертям, на сервере он не нужен. И самое главное - pEdict всё-таки последний аргумент или iBone? Кто кого обманывает? Valve или maricool?
__________________
My Projects: download page
F.A.Q по XashNT
Блог разработчика в телеграме
Цитата:
C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'
Отправлено Ku2zoff 23-01-2014 в 16:04:
Дядя Миша я же написал, что это пока не тутор. Я понял, как работает StudioSetupBones, а в остальную прочую математику не вдавался, потому что со школы её терпеть не могу. Лерпинг вырежу, когда оформлю в виде тутора. Тогда кстати, сможешь затереть эти два моих поста. Ну или оставить в назидание другим, как хочешь. Я кстати разобрался, почему хитбоксы на сервере не совпадали с клиентскими и уже это поправил.
Цитата:
Дядя Миша писал:
И самое главное - pEdict всё-таки последний аргумент или iBone? Кто кого обманывает? Valve или maricool?
Когда аргументы располагаются как у Valve, то всё работает. Стоит поменять местами - вылетает под голдсорсом. Под ксашем наоборот, но началось это после того, как ты поменял аргументы местами в движке. А вообще, эдикт приходит верный, иначе yaw/pitch игрока невозможно было бы получить. И ещё - я делал в новом СДК, что в репозитарии валяется, не думаю, что Valve оставили бы код с такой ошибкой, учитывая, что там кусок контры в виде ботов имеется.