В этой статье будет показан процесс отрисовки 3D моделей в главном меню и воспроизведение музыки.
Добавление 3D моделей в меню
Откройте файл GameMP/Game.cpp В начале файла включим заголовочный файл модели, которую будем использовать. Это необходимо для использования аттачментов через удобные макро-имена.
#include <Models/Enemies/Headman/headman.h>
В глобальной области необходимо определить несколько переменных:
static CModelObject g_ModelObject; static CPlacement3D g_ModelPlacement = CPlacement3D(FLOAT3D(0, -1.0, -1.75), ANGLE3D(160, 0, 0)); static FLOAT3D g_LightDirection = FLOAT3D(0.2f, -0.2f, -0.2f).Normalize(); static COLOR g_LightDiffuseColor = C_GRAY; static COLOR g_LightAmbientColor = C_vdGRAY;
По их именам легко понять их назначение. Определяются эти переменные в глобальной области для того, чтобы их значение сохранялось между вызовами отрисовки. Сами значения подобраны случайно, их можно менять любым образом.
Для удобства также добавим следующую вспомогательную функцию, которая поможет добавлять модели аттачменты с текстурами:
CModelObject& AddAttachmentToModel ( CModelObject& parentModel, INDEX attachmentIndex, const CTFileName& modelFilename, const CTFileName& diffuseTextureFilename, const CTFileName& reflectionTextureFilename = CTFILENAME(""), const CTFileName& specularTextureFilename = CTFILENAME("") ) { CAttachmentModelObject* pamo = parentModel.AddAttachmentModel(attachmentIndex); ASSERT(pamo != NULL); pamo->amo_moModelObject.SetData_t(modelFilename); pamo->amo_moModelObject.mo_toTexture.SetData_t(diffuseTextureFilename); if (reflectionTextureFilename.Length() > 0) pamo->amo_moModelObject.mo_toReflection.SetData_t(reflectionTextureFilename); if (specularTextureFilename.Length() > 0) pamo->amo_moModelObject.mo_toSpecular.SetData_t(specularTextureFilename); return pamo->amo_moModelObject; }
Сама отрисовка происходит в следующей функции:
void CGame::LCDRenderClouds1(void)
В самом ее конце поочередно добавляем следующие строчки кода:
if (_bPopup) return;
Данная проверка необходима для того, чтобы не отрисовывать модель дважды на экране настройки игрового персонажа - за его спиной (данная функция вызывается в этом меню отдельно для фона и для рамки, в которой отображается сетевая модель игрока).
Следующий блок кода:
if (g_ModelObject.GetData() == NULL) { g_ModelObject.SetData_t(CTFILENAME("Models\\Enemies\\Headman\\Headman.mdl")); g_ModelObject.mo_toTexture.SetData_t(CTFILENAME("Models\\Enemies\\Headman\\Rocketman.tex")); AddAttachmentToModel( g_ModelObject, HEADMAN_ATTACHMENT_HEAD, CTFILENAME("Models\\Enemies\\Headman\\Head.mdl"), CTFILENAME("Models\\Enemies\\Headman\\Head.tex")); AddAttachmentToModel( g_ModelObject, HEADMAN_ATTACHMENT_ROCKET_LAUNCHER, CTFILENAME("Models\\Enemies\\Headman\\RocketLauncher.mdl"), CTFILENAME("Models\\Enemies\\Headman\\RocketLauncher.tex"), CTFILENAME("Models\\ReflectionTextures\\LightMetal01.tex"), CTFILENAME("Models\\SpecularTextures\\Weak.tex")); g_ModelObject.PlayAnim(HEADMAN_ANIM_WALK, AOF_LOOPING | AOF_NORESTART); }
Тут производится начальная настройка модели.
Для примера была выбрана модель безголового ракетчика. Используя вспомогательную функцию, к нему сразу добавляются модели головы и оружия. Также у модели запускается проигрывание анимации ходьбы.
CPerspectiveProjection3D projection; projection.FOVL() = AngleDeg(90.0f); projection.ScreenBBoxL() = FLOATaabbox2D( FLOAT2D(0.0f, 0.0f), FLOAT2D(static_cast<float>(_pdp_SE->GetWidth()), static_cast<float>(_pdp_SE->GetHeight()))); projection.AspectRatioL() = 1.0f; projection.FrontClipDistanceL() = 0.1f; projection.ViewerPlacementL() = CPlacement3D(FLOAT3D(0, 0, 0), ANGLE3D(0, 0, 0));
Данный блок кода подготавливает проекцию, с помощью которой будет отрисована модель.
В примере проекция будет иметь горизонтальный угол обзора в 90 градусов, обозримая область будет занимать весь экран, а наблюдатель (камера) будет находится в нуле координатной системы.
Ближняя плоскость отсечения помещена на расстоянии 0.1. В общем случае это может быть любое число больше нуля, но желательно чтобы оно было небольшим, чтобы плоскость не отсекала часть видимой модели.
Стоит заметить, что в этой проекции соотношение сторон выставлено в 1. Это сделано по причине того, что размер экрана уже передан в обозримую область, и соотношение будет автоматически учтено.
_pdp_SE->FillZBuffer(1.0f); CAnyProjection3D genericProjection; genericProjection = projection; BeginModelRenderingView(genericProjection, _pdp_SE); CRenderModel renderModel; renderModel.rm_vLightDirection = g_LightDirection; renderModel.SetObjectPlacement(g_ModelPlacement); renderModel.rm_colLight = g_LightDiffuseColor; renderModel.rm_colAmbient = g_LightAmbientColor; g_ModelObject.SetupModelRendering(renderModel); g_ModelObject.RenderModel(renderModel); EndModelRenderingView();
В этом блоке кода произведена отрисовка модели.
Перед самой отрисовкой, буфер глубины очищается, это необходимо для того, чтобы модель рисовалась поверх фона.
Остальные строки кода заполняют заранее подготовленую информацию об отрисовке (положение модели, направление света, цвет).
После сборки и запуска, результат должен быть следующий:
Воспроизведение музыки
Для воспроизведения музыки необходимо ей выделить один из доступных каналов.
#define MUSIC_CHANNEL 0
Всего их доступно MAX_SCRIPTSOUNDS, причем последний ( MAX_SCRIPTSOUNDS-1) зарезервирован.
Перейдите к определению следующей функции:
void CGame::StopGame(void)
В ее начало необходимо добавить следующие строки:
if (IsScriptSoundPlaying(MUSIC_CHANNEL)) StopScriptSound(MUSIC_CHANNEL);
Они остановят воспроизведение музыки, когда показывается экран титров.
Также этот блок необходимо вставить в конце функции
void CGame::GameMainLoop(void)
Конец этой функции должен выглядить следующим образом:
if (gm_bGameOn) { // do main loop procesing if (IsScriptSoundPlaying(MUSIC_CHANNEL)) StopScriptSound(MUSIC_CHANNEL); _pNetwork->MainLoop(); }
Осталось только воспроизвести музыку. Для этого необходимо перейти к определению следующей функции:
void CGame::LCDRenderClouds1(void)
И в самом ее начале добавить следующий блок кода:
if (!IsScriptSoundPlaying(MUSIC_CHANNEL)) { FLOAT volume = 1.0f; FLOAT pitch = 1.0f; BOOL looping = TRUE; PlayScriptSound(MUSIC_CHANNEL, CTFILENAME("Music\\Fight\\Fight05.ogg"), volume, pitch, looping); }
Тут можно выбрать необходимый файл музыки, настроить высоту, громкость и включить либо выключить ее зацикленность.
Таким образом возможно улучшить главное меню, разнообразив его моделями с анимацией на фоне (либо вовсе заменив фон на модель) и добавив музыки.
Комментарии
Только у тебя в первом большом блоке кода есть html теги после "Это наша модель", хорошо бы было их выпилить. =)
А мне типо это надо?
А так кому не лень поюзать СДК и поднять свою жопу на изучение С++ то статья вери гут) Ну а кому лень те уже высказались.