Введение Наверно вы удивлены зачем использовать GLScene, а не чистое API ну или хотя бы другой движок. Скажу только одно, это статья для тех кто хотел попробовать написать что то своё с использованием 3д графики, но из за недостатка знаний не решался на сей шаг. Как показывает практика в странах бывшего Советского Союза очень популярен Pascal (и его разновидности), по этому в качестве языка программирования выбран Object Pascal. О преимуществе GLScene, я писал в другой своей статье, так что останавливаться на этом не будем. Сражу скажу, код тут не весь, я описал только самое сложное и то что может вызвать вопросы остальные вещи просты и не должны быть проблемой, по этой причине я вынес их из статьи. Ну что вперёд? Первая программа GLScene - это объектная надстройка над OpenGL для Borlan Delphi, хотя некоторые считают GLScene игровым движком. Оно и так и не так. GLScene упрощает жизнь многим программистам и открывает широкие возможности по работе с графикой. Последние версии библиотеки GLScene и множество примеров доступны на сайте http://www.glscene.org/. Установка Официально поддерживаются Delphi 5-7, Delphi 2005-2010 (и более новые) и Lazarus. 1) Распаковываем архив GLScene в нужную папку, например, С:\Borland\Delphi7\Source\GLScene. 2) Затем необходимо прописать пути к файлам GLScene. Для этого заходим в меню Tools -> Environment Options, переходим на вкладку Library и в Library path добавляем С:\Borland\Delphi7\Source\GLScene и все ее подпапки. Сейчас нужно скопировать 4 dll из папок …GLScene\Source\PhysicsAPIs и …GLScene\Source\SoundAPIs в папку …:\Windows\system32. Теперь ищем папку с пакетами для нужной версии Delphi и запускаем файлы GLScene.dpk (собственно Сцена) и GLSS_BASS.dpk, GLSS_FMOD.dpk, GLSS_OpenAL (поддержка звуковых библиотек BASS, FMOD и OpenAL), а в открывшихся окнах нажимаем кнопку "Compile" а потом "Install". Все, Сцена установлена. Ее компоненты можно найти на вкладках GLScene (основные компоненты), GLScene PFX (эффекты), GLScene Utils (вспомогательные компоненты), GLScene Terrain (компоненты для создания земной поверхности) и GLScene Shaders (компоненты для шейдеров). Создание Нашей первой программой не будет "Hello World!", мы напишем небольшую сценой с самым простым ландшафтом и ходящем по нему персонажем. Параметры объектов можете установить по вкусы, для примеры я поставил такие: GLSceneViewer1-> Camera GLCamera2 (Главное окно просмотра, в нем мы и увидим наш мир) Align alClient GLNavigator1-> MovingObject DummyCube2 (Используем его для управлением нашем Актером) UseVirtualUp True VirtualUp X=0, Y=0, Z=1 GLUserInterface1-> GLNavigator GLNavigator1 (Для подключения мыши к упавлению) MouseSpeed 20 GLCadencer1-> Scene GLScene1 (Главный таймер Сцены, будет обновлять сцену) GLWaterPlane1-> Position X=-25, Y=-100, Z=-40 (Вода) Scale X=2000, Y=2000, Z=2000 Elastic 5 RainForce 80 RainTimeInterval 1 Up X=0, Y=0, Z=1 GLLightSource1-> Position X=50, Y=50, Z=50 (Источник света) DummyCube2-> Up X=0, Y=0, Z=1 (Пустой куб) GLCamera1-> DepthOfView 1000 (Камера) Up X=0, Y=1, Z=0 GLTerrainRenderer1 HeightDataSource GLBitmapHDS1 (Рендер земли, на вход нужно подать 2х цветную карту высот) Material Texture-убрать галочку с Disable Scale X=10, Y=10, Z=0,5 Up X=0, Y=1, Z=0 Ещё добавим DCE физику. uses jpeg, tga, GLkeyboard, VectorGeometry,GLFile3DS, GLFilemd2; // загружаем карту высот для нашей земли GLBitmapHDS1.Picture.LoadFromFile('media\terrain.bmp'); // загружаем текстуру на землю GLTerrainRenderer1.Material.Texture.Image.LoadFromFile('media\clover.jpg');
//Здесь мы загружаем части тела Legs.LoadFromFile('.\model\lower.md3'); Torso.LoadFromFile('.\model\upper.md3'); Head.LoadFromFile('.\model\head.md3');
//Загружаем тэг лист, для корректного отображения частей модели LegsTags:=TMD3TagList.Create; LegsTags.LoadFromFile('.\model\lower.md3'); TorsoTags:=TMD3TagList.Create; TorsoTags.LoadFromFile('.\model\upper.md3'); //Подгружаем тектсуру LoadSkin('.\model\','default',Head,Torso,Legs,'.tga'); //Загрузка анимации
LoadQ3Anims(Legs.Animations,'.\model\animation.cfg','BOTH'); LoadQ3Anims(Legs.Animations,'.\model\animation.cfg','LEGS'); LoadQ3Anims(Torso.Animations,'.\model\animation.cfg','BOTH'); LoadQ3Anims(Torso.Animations,'.\model\animation.cfg','TORSO');
//Включаем циклическое повторение и активируем нужную анимацию Legs.AnimationMode:=aamLoop; Torso.AnimationMode:=aamLoop; Legs.SwitchToAnimation('LEGS_IDLE'); Torso.SwitchToAnimation('TORSO_STAND');
GLUserInterface1.MouseLookActivate;
//Пишем в Cadencer Progress //Суть движения такова, мы прикладываем силу к нашему Дамми кубу с моделью игрока и подключаем анимацию
if iskeydown(vk_escape)then close;
// обработка перемещения setvector(v, 0, 0, 0); if iskeydown(vk_shift)then spd:=180 else spd:=40; if iskeydown('s') then addvector(v, affinevectormake(-1, 0, 0)); if iskeydown('w') then addvector(v, affinevectormake(1, 0, 0)); if iskeydown('a') then addvector(v, affinevectormake(0, 0, -1)); if iskeydown('d') then addvector(v, affinevectormake(0, 0, 1));
if iskeydown(vk_down) then GLGameMenu1.SelectNext; if iskeydown(vk_up) then GLGameMenu1.SelectPrev; if iskeydown(vk_return) then begin case GLGameMenu1.Selected of 0: begin GLGameMenu1.Visible:=false; GLCadencer1.Enabled:=true; end; 1: begin GLFullScreenViewer1.Active:=true; GLGameMenu1.Visible:=false; end; 2:Close; end; end;
with GetOrCreateDCEDynamic(dc_player) do begin if iskeydown(vk_space)then Jump(2, 10); // корявый прыжок if(v[0]<>0)or(v[2]<>0)then ApplyAccel(vectorscale(vectornormalize(v), spd)); end;
if m_turn then begin adt:=0.2/(1+deltatime); dw:=width div 2; dh:=height div 2; dc_player.Turn(adt*(mouse.CursorPos.X-dw)); GLCamera1.MoveAroundTarget(adt*(dh-mouse.CursorPos.Y), 0); mouse.CursorPos:=point(dw, dh); end;
// анимация if(v[0]<>0)or(v[2]<>0)then begin if legs.CurrentAnimation='LEGS_IDLE' then legs.SwitchToAnimation('LEGS_WALK'); end else if legs.CurrentAnimation='LEGS_WALK' then legs.SwitchToAnimation('LEGS_IDLE');
m1:=LegsTags.GetTransform('tag_torso',Legs.CurrentFrame); m2:=LegsTags.GetTransform('tag_torso',Legs.NextFrameIndex); Torso.Matrix:=InterpolateMatrix(m1,m2,Legs.CurrentFrameDelta);
m1:=TorsoTags.GetTransform('tag_head',Torso.CurrentFrame); m2:=TorsoTags.GetTransform('tag_head',Torso.NextFrameIndex); Head.Matrix:=InterpolateMatrix(m1,m2,Torso.CurrentFrameDelta);
m1:=TorsoTags.GetTransform('tag_weapon',Torso.CurrentFrame); m2:=TorsoTags.GetTransform('tag_weapon',Torso.NextFrameIndex); Weapon.Matrix:=InterpolateMatrix(m1,m2,Torso.CurrentFrameDelta);
GLSceneViewer1.Invalidate;
function TForm1.InterpolateMatrix(m1, m2: TMatrix; delta: single): TMatrix; var i,j : integer; begin // Используем для стыковки модели в каждом кадре for j:=0 to 3 do for i:=0 to 3 do Result[i][j]:=m1[i][j]+(m2[i][j]-m1[i][j])*delta; end;
procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); begin // Приблежение и отдаление колёсиком мыши if wheeldelta > 0 then glcamera1.AdjustDistanceToTarget(0.98) else glcamera1.AdjustDistanceToTarget(1.02) end;
procedure TForm1.GLFullScreenViewer1MouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); begin if wheeldelta > 0 then glcamera1.AdjustDistanceToTarget(0.98) else glcamera1.AdjustDistanceToTarget(1.02) end;
Заключение В этом примере я некоторые вещи опустил, это те вещи каторые можно легко доделать в процессе написания. Статьи по теме можно поискать на glscene.ru и mir-games.ru p.s. пока я готовил материал и писал эту статьи я начал делать мальнькую игрушку.
|