Модераторы: Rickert

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Программирование игрового движка GR-Engine, Введение 
:(
    Опции темы
Master Lucky
Дата 22.4.2009, 18:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 22.1.2008
Где: Торонто, Канада

Репутация: нет
Всего: нет



Цитата(Rickert @  22.4.2009,  05:14 Найти цитируемый пост)
Каждый день smile


Ну, я имел ввиду новичков. Вы, как я посмотрю, человек опытный, поэтому для вас это намного легче  smile 

PM MAIL   Вверх
Rickert
Дата 23.4.2009, 02:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: 6
Всего: 52



Цитата
"And remember, kids: the higher your postcount - the bigger your penis is"



--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
php
Дата 23.4.2009, 04:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 159
Регистрация: 20.2.2003

Репутация: 3
Всего: 3



Вообще в принципе ошибки на данном участке кода могут возникать довольно редко,
я по крайней мере на своей практике их не встречал, разве что из-за неправильно установленного или используемго SDK (версии SDK), мы ведь там просто указываем программе
какую версию DX мы хотим использовать, в принципе этот интерфейс нам больше и не нужен,
это всё так скать начально заготовочная "мишура" нужна лишь к подготовке к созданию нашего основного Direct3D устройства, вот там уже на этапе создания этого устройства согласен могут возникнуть уже серьёзные ошибки и отлавливать их нужно уже более внимательно, может там у меня в коде не всё гладко и чисто как хотелось бы, нужно бы подредактировать сделать более серьёзную обработку ошибок, замечания и предложения естественно принимаются!..  smile 

Теперь разберём этот искомый участок кода:
Я постараюсь просто объяснить подробнее почему я так сделал и в коде присутствует именно такая запись:

Код

 if (m_pDirect3D != NULL) m_pDirect3D->Release();//<-


С точки зрения мышления человека да это может и не правильно согласен, но давайте попробуем разобраться с точки зрения логики машины как бы смешно это не звучало:

Итак, что у нас сначала происходит заведомо обнуляем интерфейс:

Код

   IDirect3D9* m_pDirect3D = NULL; 


Затем указываем данному интерфейсу какую версию DX SDK мы хотим использовать здесь:

Код

  m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);


Создался там этот интерфейс или не создался нам глубоко "не важно"

Здесь мы выводим причину чисто для отладки:
Код

    if (m_pDirect3D != NULL) m_pDirect3D->Release();//<-
    MessageBoxA(NULL,"GR_Engine.cpp: Failed To Create Direct3D Interface..",
    "GreenRay Engine Error",MB_SYSTEMMODAL|MB_ICONERROR);
    m_pResult = E_FAIL; 


Здесь читаем медленно вдумавшись:  smile 
ЕСЛИ интерфейс не создан то он вернёт значение NULL, но вот здесь проверяем:
Код

 if (m_pDirect3D != NULL) m_pDirect3D->Release();//<-


ЕСЛИ ВДРУГ (не исключаем такую ситуацию) всё таки интерфейс был создан и вернул не NULL, то предварительно очищаем его, и  какой тогда сымысл если он вернул NULL его опять освобождать если он изначально был NULL, т.е освобождать освобождённое - это может уже привести даже к ошибкам в системе типа Access Violation и даже возникновению "синего экрана" (хотя это вряд-ли  smile )

В конце мы этот интерфейс вообще "выкидываем" за ненадобностью, т.к нужную версию SDK мы
определили и установили:

Код

  ....
  //m_pDevice->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);
  }

  if (m_pDirect3D != NULL) m_pDirect3D->Release(); //Освобождаем Direct3D интерфейс он 
  //выполнил своё предназначение
  ...


Так, что с точки зрения логики самой программы эта запись верна, и вообще честно говоря не вижу смысла здесь, что либо менять или переделывать, другое дело на этапе создания уже самого устройства там надо бы подлатать код, "грязновато" оформлен я бы сказал!

Это хорошо, что вы обратили внимание, я рад был разъяснить - обсуждение движка идёт полным ходом - это радует! Так, что спрашивайте или указывайте на ошибки всё будем разбирать вместе на то и делается уклон! Кстати скоро появится вторая часть статьи..

А комментарии мне пожалуй делать всё таки придётся, т.к здесь этот участок кода видимо остался без внимания и плоховато задокументирован и возникли небольшие вопросы..

Нда целая диссертация опять получилась, никак у меня не получается короче!  smile 

Это сообщение отредактировал(а) php - 23.4.2009, 04:28
--------------------
Джедаи не пройдут..
PM MAIL   Вверх
ISergeyN
Дата 23.4.2009, 11:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 11.10.2008
Где: Україна

Репутация: нет
Всего: 2



Ну с этим ладно. Но всёже прийдется немного доработать обработку ошибок.
Цитата(php @  23.4.2009,  04:26 Найти цитируемый пост)
Кстати скоро появится вторая часть статьи..

Будем ждать.
PM MAIL Skype   Вверх
php
Дата 6.7.2009, 06:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 159
Регистрация: 20.2.2003

Репутация: 3
Всего: 3



Часть 2. Программирование игрового движка (Продолжение..)

Вступление.

Итак продолжим разработку игрового движка, сорри за столь длительный перерыв,
было много дел..

В данных разделах мы рассмотрим, как осуществляется привязка камеры к движку,
также начнём работу с текстурированием и моделированием простейших объектов - 
создадим SkyBox, понятие SkyBox разбиралось в предыдущей статье так, что можно прочитать, что это такое и для чего это нужно именно там. 

Рассматривать и разбирать как делаются всякие детские вращающиеся кубики мы не будем, а займёмся серьёзными "игровыми" вещами.. мы же с вами делаем игру, а не рекламный ролик smile))

2.2. Привязка камеры к проекту.
В данном разделе статьи мы рассмотрим как привязать "камеру" к нашему проекту.
Как уже описывалось ранее сама камера будет реализована на DirectInput.

Для этого выполним следующие действия:

1) Для начала создадим новый файл под названием GR_Camera.cpp:
Для этого в "дереве" нашего проекта выбираем Source Files и нажимаем на нём правой кнопкой мыши, далее из выпадающего меню выбираем Add->New Item.. В общем делаем всё по аналогии как описано в пункте 2.1. предыдущей статьи, только не забудьте этот созданный модуль сохранить в папку Engine_Modules (или как она у вас там теперь называется?? smile)).

2) Также необходимо создать файл GR_Camera.h:
Для этого также в "дереве" проекта выбираем Header Files, и не забываем сохранить этот файл также в папке Engine_Modules.

Всё мы создали заготовки файлов GR_Camera.h и GR_Camera.cpp (пара - заголовочный .h и .cpp файлы). Начинаем программирование..

2.3. Подключение и инициализация устройства ввода DirectInput.
Для начала прежде чем работать с "камерой" в движке мы должны подготовить и инициализировать устройство ввода, т.е. иными словами подключить возможность управления объектами или вращением объектов используя клавиатуру или мышь, будь то просто управление "взглядом" камеры дающее возможность непосредственно
оглядываться да и просто смотреть по сторонам, или обработка нажатия кнопок мыши или клавиатуры для реализации "выстрелов" из оружия к примеру... Всё это мы будем делать и разбирать в дальнейшем.

Поток данных поступаемых от клавиатуры или мыши обрабатывается непрерывно в следствие чего возможна обработка одновременного нажатия нескольких кнопок на клавиатуре, мыши, тут же одновременного вращения и обзора мышью по сторонам, чем и был обусловлен переход GRE на DirectInput.

1) Для начала необходимо выбрать из "дерева" нашего проекта GR_Engine.h сделав на нём двойной щелчок мыши, 
стереть полностью его содержимое и заменить на это:

Код

/****************************************************************************/ 
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_Engine.h Visual Studio 8 Version.
// It's An GreenRay GREngine Header File.
// Made Specially For Implement 3D Engine Parameters.
/*****************************************************************************/
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX

//Windows And System Directives
#include <windows.h>
#include <atlstr.h>   
#include <stdio.h>
#include <tchar.h>
#include <wchar.h>
#include <strsafe.h>

//Direct3D Directives
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9core.h>
#include <d3dx9mesh.h>
#include <dinput.h>

//Sound System Directives
#include <mmsystem.h>
#include <dshow.h>
#include <dsound.h>
#include <dmusici.h>

////////////////////////////////////////////////////////////////////////////////
// External Definitions And Prototypes 
////////////////////////////////////////////////////////////////////////////////
HRESULT CreateDirect3D(HWND Hndl_Wnd);
void RenderingDirect3D();
void ReleaseDirect3D();

////////////////////////////////////////////////////////////////////////////////
// Global Variables
////////////////////////////////////////////////////////////////////////////////
extern HWND FormL_HWnd; //Global Form Layer HWnd Handle



Теперь разберём следующий участок кода:

Код

...
void ReleaseDirect3D();

////////////////////////////////////////////////////////////////////////////////
// Global Variables
////////////////////////////////////////////////////////////////////////////////
extern HWND FormL_HWnd; //Хендл нашего ранее созданного игрового полотна
...



Здесь в участке кода мы объявляем глобальную переменную FormL_HWnd которая будет хранить в себе значение или Handle нашего ранее созданного окна для вывода графики (обычно все окна в  системе Windows имеют свой уникальный номер (даже скрытые и невидимые) для того, чтобы ось (операционная система) могла определить различные привязки, вызовы, какие окна запущены и работают, и просто знать к какому конкретному окну происходит обращение, и обратиться к нему можно по 
этому уникальному номеру который и будет "передан" и присвоен этой нашей переменной).  В принципе, получив нужный Handle окна можно делать с ним практически, что угодно - менять заголовки,  надписи в самой форме этого окна, получать его изображение, но это мы пожалуй разбирать здесь  уже не будем, так как это уже выходит за рамки документации GRE.. 

2) Теперь из "дерева" проекта выбираем GR_Engine.cpp - делаем также на нём двойной щелчок мыши, стираем полностью его содержимое и меняем на это:

Код

/****************************************************************************/ 
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_Engine.cpp Visual Studio 8 Version.
// It's An GreenRay GREngine Source File.
// Made Specially For Implement 3D Engine Parameters.
/*****************************************************************************/
//#pragma comment(lib,"d3d9.lib");
//#pragma comment(lib,"d3dx9.lib");
#include <GR_Engine.h>
#include <GR_Methods.h>
#include <GR_Camera.h>
#include <GR_SkyBox.h>

////////////////////////////////////////////////////////////////////////////////
// Global Variables 
////////////////////////////////////////////////////////////////////////////////
IDirect3DDevice9* m_pDevice = NULL; //The Direct3D Device Interface
HWND FormL_HWnd; //Form Layer Handle

CGRDeltaTimer* gr_Timer = NULL; //GreenRay Delta Timer Interface Class
CGRCamera* gr_Camera = NULL; //GreenRay Camera Global Interface Class
CGRSkyBox* gr_SkyBox = NULL; //GreenRay SkyBox Global Interface Class

//-----------------------------------------------------------------------------
// Name: CreateDirect3D()
// Desc: Эта функция создаёт основное Direct3D устройство
//-----------------------------------------------------------------------------
HRESULT CreateDirect3D(HWND Hndl_Wnd)
{
  HRESULT m_pResult = S_OK; //Set Result By Default
  IDirect3D9* m_pDirect3D = NULL; //This General Direct3D Initialization Interface

  //Создаём объект Direct3D
  m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);

  //Проверяем, если возникнет ошибка то освобождаем D3D интерфейс
  if (!m_pDirect3D)
  {
    if (m_pDirect3D != NULL) m_pDirect3D->Release();
    MessageBoxA(NULL,"GR_Engine.cpp: Failed To Create Direct3D Interface..",
    "GreenRay Engine Error",MB_SYSTEMMODAL|MB_ICONERROR);
    m_pResult = E_FAIL;
  }

  //Автоматическая проверка параметров поддерживаемых дисплеем
  //далее полученные параметры помещаются в стркутуру m_pDisplay
  D3DDISPLAYMODE m_pDisplay; 
  if (FAILED(m_pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&m_pDisplay)))
  {
    if (m_pDirect3D != NULL) m_pDirect3D->Release();
    MessageBoxA(NULL,"GR_Engine.cpp: Failed Get Adapter Display Mode..",
    "GreenRay Engine Error",MB_SYSTEMMODAL|MB_ICONERROR);
    m_pResult = E_FAIL;
  }

  //All System Checks Passed, Create The Direct3D Device
  D3DPRESENT_PARAMETERS m_pD3DParam;
  memset(&m_pD3DParam,0,sizeof(m_pD3DParam));

  //Установка параметров и режимов работы Direct3D устройства 
  m_pD3DParam.SwapEffect                 = D3DSWAPEFFECT_DISCARD; //D3DSWAPEFFECT_COPY;
  
  //Установка разрешения
  m_pD3DParam.BackBufferWidth            = 640; 
  m_pD3DParam.BackBufferHeight           = 480;
  //Здесь указывается режим работы устройства в полный экран (FALSE) или в окне (TRUE)
  //угадайте в каком режиме будет у нас :-))
  m_pD3DParam.Windowed                   = TRUE;

  //Формат заднего буфера, обычно определяется автоматически (m_pDisplay.Format), 
  //но можно указать и вручную в зависимости от поставленных целей
  m_pD3DParam.BackBufferFormat           = m_pDisplay.Format; //D3DFMT_A8R8G8B8 

  //Данный параметр необходимо раскомментировать лишь в том случае, если наше 
  //приложение будет работать на полный экран (здесь как правило указывается 
  //частота развёртки монитора) крайне не советую "играться" с этим параметром, 
  //пусть уж частота определится автоматически (m_pDisplay.RefreshRate)
  //m_pD3DParam.FullScreen_RefreshRateInHz = m_pDisplay.RefreshRate; //D3DPRESENT_RATE_DEFAULT; 
  
  //Включение "стенсельного" буфера, в основном предназначен в дальнейшем для отрисовки
  //эффектов теней и зеркал, короче повторяет очертания исходного объекта
  m_pD3DParam.EnableAutoDepthStencil     = TRUE;

  //Здесь уже указывается формат "стенсельного" буфера
  m_pD3DParam.AutoDepthStencilFormat     = D3DFMT_D16; //D3DFMT_D16 D3DFMT_D15S1 D3DFMT_D24X8
                                                       //D3DFMT_D24S8 D3DFMT_D24X4S4 D3DFMT_D32
  
  //Количество задних буферов
  m_pD3DParam.BackBufferCount            = 2;

  //Кол-во степеней сглаживания для антиалиасинга
  m_pD3DParam.MultiSampleType            = D3DMULTISAMPLE_4_SAMPLES; //4_SAMPLES //For Antialiasing Mode On 4x
  
  //Качество сглаживания
  //m_pD3DParam.MultiSampleQuality       = 1;
  
  //Буфер глубины обычно активируется для создания эффекта Shadow Volume "тень" 
  //m_pD3DParam.Flags                    = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL; //|D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
  
  //Интервал представления отображаемых объектов и игровой сцены
  m_pD3DParam.PresentationInterval       = D3DPRESENT_INTERVAL_ONE;

  //Если раскомментировать этот параметр, то ощутится явный прирост fps и вообще
  //сцена начнёт отображаться существенно быстрее, т.е помимо видеокарты в процессе 
  //рендеринга начнёт участвовать ваш центральный процессор и загрузит его на 100%
  //Данный параметр использовать не рекомендуется, система работает на износ..
  //Да и вообще процессорное время лучше поберечь для других нужд, 
  //хотя-бы на обработку физики игры..
  //m_pD3DParam.PresentationInterval     = D3DPRESENT_INTERVAL_IMMEDIATE;

  FormL_HWnd = Hndl_Wnd; //Set Layer Window Handle

  //Создание Direct3D устройства, "скармливаем" ранее установленные параметры нашему устройству
  //Также указываем Handle (Hndl_Wnd) нашего ранее созданного окна, то бишь полотна куда будет выводиться графика 
  if (FAILED(m_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,Hndl_Wnd,
  D3DCREATE_HARDWARE_VERTEXPROCESSING,&m_pD3DParam,&m_pDevice)))
  {
    //Ошибка создания Direct3D устройства освобождаем его
    if (m_pDirect3D != NULL) m_pDirect3D->Release();    
    //Вообще если возникает подобная ошибка, значит мы "скормили" нашему устройству 
    //неверные или не поддерживаемые видеокартой параметры, попробуйте "поиграться" с другими 
    //значениями выставляемые в параметрах, а может вы забыли поставить "дрова" на видеокарту?? :-))))
    MessageBoxA(NULL,"GR_Engine.cpp: Error Creating Direct3D Device..",
    "GreenRay Engine Error",MB_SYSTEMMODAL|MB_ICONERROR);
    m_pResult = E_FAIL;
  }

  //Ending Direct3D Presets Parameters
  if (m_pDevice != NULL)
  {
    //Установка режимов рендера:
    //Весьма интересный и нужный режим состояния рендера
    //при этом режиме происходит "отсечение" невидимых взору граней (полигонов), т.е
    //граней находящихся с задней стороны модели или 3D объекта, они попросту не ренерятся
    //и не отображаюся, это позволяет очень сильно разгрузить работу нашей видеокарты и всей
    //системы в целом.
    //Режим D3DCULL_CW - устанавливает отсечение невидимый граней
    //Режим D3DCULL_CСW - устанавливает тоже отсечение только уже видимых граней (инверсия)
    //Режим D3DCULL_NONE - отключает оба этих режима рендерится вся модель как есть даже 
    //её внутренние части, это уже слишком тяжело для видеокарты, сразу же ощущается падение fps
    //после установки этого режима.
    m_pDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);
    
    //Включаем буфер глубины или Z-Buffer, или эффект отдаления объектов или моделей
    //"вглубь" экрана, да уж совсем образно объяснил..
    m_pDevice->SetRenderState(D3DRS_ZENABLE,D3DZB_TRUE);

    //Режим освещения, нам он пока не нужен, поэтому FALSE
    m_pDevice->SetRenderState(D3DRS_LIGHTING,FALSE); 
   
    //Режим рендера отображающий полигоны не цельными SOLID, а в режиме сетки WIREFRAME
    //m_pDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
    
    //Установка цвета амбиентного (общего) освещения
    //m_pDevice->SetRenderState(D3DRS_AMBIENT,0xFFFFFFFF);
    
    //Данная установка включает режим работы антиалиасинга (прменения эффекта сглаживания 
    //рёбер или неровности краёв полигона называется антиалиасингом), нам пока не нужен 
    //поэтому закомментирован
    //m_pDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS,TRUE);
    
    //Установка режима закраски по Гуро, обычно она устанавливается по умолчанию 
    //(закраска по Гуро обычно нужна для сглаживания одутлых или круглых поверхностей,
    //например чтобы шар походил на шар, а не на ребристый комок)
    //m_pDevice->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);



    //Cоздаём класс таймера.
    gr_Timer = new CGRDeltaTimer(); //Construct A CGRDeltaTimer Class

    //Cоздаём класс камеры
    gr_Camera = new CGRCamera(m_pDevice); //Construct A CGRCamera Class
    gr_Camera->SetCameraPos(D3DXVECTOR3(5.0f,50.78f,5.0f)); //Set Player Camera Position In Space
    gr_Camera->SetCameraSpeed(40.0f); //Set Player Camera Speed
    gr_Camera->SetMouseSpeed(0.3f); //Set Mouse Speed

    //Create SkyBox Class
    gr_SkyBox = new CGRSkyBox(m_pDevice); //Construct A CGRSkyBox Class  
    gr_SkyBox->CreateBox(100.0f,100.0f,100.0f); //Create Our SkyBox Model With Size WHD
    gr_SkyBox->SetTextures(TEXT("\Textures\\SkyBox\\Arch\\zneg.png"),
                           TEXT("\Textures\\SkyBox\\Arch\\xneg.png"),
                           TEXT("\Textures\\SkyBox\\Arch\\zpos.png"),
                           TEXT("\Textures\\SkyBox\\Arch\\xpos.png"),
                           TEXT("\Textures\\SkyBox\\Arch\\yneg.png"),
                           TEXT("\Textures\\SkyBox\\Arch\\ypos.png"));
  } //End if (m_pDevice != NULL)

  if (m_pDirect3D != NULL) m_pDirect3D->Release(); //Освобождаем Direct3D интерфейс он 
  //выполнил своё предназначение
  return m_pResult; //В конце возвращаем результат работы функции
} //EndCreateDirect3DFunction

//-----------------------------------------------------------------------------
// Name: RenderingDirect3D()
// Desc: Здесь в этой процедуре происходит отрисовка нашей игровой сцены
//-----------------------------------------------------------------------------
void RenderingDirect3D()
{   
  if (m_pDevice != NULL) 
  {
    if (gr_Timer != NULL) gr_Timer->UpdateTimer(); //Update GreenRay Timer Every Frame
    //Обновление и получение данных с камеры, 
    //код процедуры находится в модуле GR_Camera.cpp
    if (gr_Camera != NULL) gr_Camera->UpdateCamera(); //Update GreenRay Camera 

    //Здесь идёт очистка заднего и Z-буфера соответственно..
    m_pDevice->Clear(0,NULL,D3DCLEAR_TARGET/*|D3DCLEAR_STENCIL*/,
    D3DCOLOR_XRGB(0,0,0),1.0f,0);
    
    //Begin Scene
    if (SUCCEEDED(m_pDevice->BeginScene()))
    {
      //Рендерим SkyBox
      if (gr_SkyBox != NULL) gr_SkyBox->Render(); //Render The SkyBox ! 

      m_pDevice->EndScene();
    }
    m_pDevice->Present(NULL,NULL,NULL,NULL);
  }
} //EndRenderingDirect3DProcedure

//-----------------------------------------------------------------------------
// Name: ReleaseDirect3D()
// Desc: Освобождение ресурсов и устройства Direct3D
//-----------------------------------------------------------------------------
void ReleaseDirect3D()
{
  if (gr_Camera != NULL) { /*gr_Camera->Release();*/ ReleaseClass(gr_Camera); DeleteClass(gr_Camera); } //Free Camera Class 
  if (gr_SkyBox != NULL) { gr_SkyBox->Release(); ReleaseClass(gr_SkyBox); DeleteClass(gr_SkyBox); } //Free SkyBox Class
  
  if (m_pDevice != NULL) m_pDevice->Release();
} //EndReleaseDirect3DProcedure

//------------------------------------------------------------------------------



3) Теперь займемся программированием самой DirectInput "камеры" и DI-устройства,
для этого вернемся к ранее созданному модулю GR_Camera.h выделив и сделав на нем двойной щелчок мыши в  "дереве" проекта и заполним его следующим кодом:

Код

/****************************************************************************/ 
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_Camera.h
// It's An GreenRay GR_Camera Header File.
/*****************************************************************************/
#pragma once
#include <GR_Engine.h>
#include <GR_Methods.h>

////////////////////////////////////////////////////////////////////////////////
// Classes Used By This Header
////////////////////////////////////////////////////////////////////////////////
//class CGRCamera;

//-----------------------------------------------------------------------------
// Name: Struct CGRCamera
// Desc: 
//-----------------------------------------------------------------------------
#if !defined(AFX_CAMERA_H__)
#define AFX_CAMERA_H__
class CGRCamera
{    
public:
  /*Public Directives*/
  CGRCamera(LPDIRECT3DDEVICE9 pDevice);
  virtual ~CGRCamera();
  void Release();
  
  HRESULT CreateInputDevices(HWND _HWnd);
  void UpdateCamera();
  
  //Установка начального расположения камеры в игровом мире или
  //вообще установка "глаз" в нужное местоположение.
  void SetCameraPos(D3DXVECTOR3 Pos_XYZ) { Position = Pos_XYZ; }

  //Скорость передвижения камеры, т.е фактически здесь
  //мы задаём скорость для движения камеры в стороны при управлении с клавиатуры.
  void SetCameraSpeed(float Cam_Speed) { m_fCameraSpeed = Cam_Speed; } 

  //Здесь задаётся скорость вращения и обзора мыши.
  void SetMouseSpeed(float Mouse_Speed) { m_fMouseSpeed = Mouse_Speed; }
 
  //Функция возвращающая местоположение камеры в игровом мире.
  D3DXVECTOR3 Pos() { return Position; }
private:
  /*Private Directives*/ 
  LPDIRECT3DDEVICE9 d_pDevice;      //Pointer On Direct3D Device Interface
  IDirectInput8* m_pDirectInput;    //Base DirectInput Device
  IDirectInputDevice8* m_pMouse;    //Mouse Input Device
  IDirectInputDevice8* m_pKeyboard; //Keyboard Input Device

  //Base Camera Directives
  float Pitch,Yaw;
  D3DXVECTOR3 Position;
  D3DXVECTOR3 Target;
  D3DXVECTOR3 Up;
  D3DXVECTOR3 Velocity;
  D3DXVECTOR3 Look_Vector; //Base Look Vector
  D3DXMATRIX View;
  D3DXMATRIX Projection;

  float PosX,PosY,PosZ; 

  float m_fCameraSpeed; //Set Camera Speed
  float m_fMouseSpeed; //Set Mouse Speed

  //"Тайминг" интерфейс нам понадобится позже для обработки 
  //режима ведения огня из автоматического оружия или 
  //одиночными выстрелами соответственно.
  CGRTimer* m_pTimer; //Timing Interface
};
#endif //!defined(AFX_CAMERA_H__)

////////////////////////////////////////////////////////////////////////////////
// Global Variables Or Constants
////////////////////////////////////////////////////////////////////////////////
extern CGRCamera* gr_Camera; //GreenRay Camera Global Interface Class



4) Модуль GR_Camera.cpp заполняем этим кодом:

Код

/****************************************************************************/ 
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_Camera.cpp
// It's An GreenRay GR_Camera Source File.
/*****************************************************************************/
#include <GR_Camera.h>

//////////////////////////////////////////////////////////////////////////////
// Construction/Destruction For CGRCamera Class
//////////////////////////////////////////////////////////////////////////////
CGRCamera::CGRCamera(LPDIRECT3DDEVICE9 pDevice)
{
  //Set Default Parameters
  d_pDevice = pDevice; //Apropritate Device Pointer To Class
  m_pDirectInput = NULL;
  m_pMouse = NULL;
  m_pKeyboard = NULL;
  m_pTimer = NULL;

  //Create Input Devices
  if (SUCCEEDED(CreateInputDevices(FormL_HWnd)))
  {
    m_pMouse->Acquire();
    m_pKeyboard->Acquire();
  }
  
  m_fCameraSpeed = 0.01f;
  m_fMouseSpeed = 0.01f;

  Pitch = 0.0f;
  Yaw = 0.0f;
  Position = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  Target = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  Up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  Velocity = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  D3DXVec3Normalize(&Look_Vector,&(Target-Position));

  //Set The Projection Matrix
  float Aspect_Ratio = 1.0f;
  D3DXMatrixPerspectiveFovLH(&Projection,D3DX_PI/4,Aspect_Ratio,0.1f,1000.0f);
  d_pDevice->SetTransform(D3DTS_PROJECTION,&Projection);

  m_pTimer = new CGRTimer(); //Construct A Timer Class
} //EndConstructionDirectives

CGRCamera::~CGRCamera()
{
} //EndDestructionDirectives

//-----------------------------------------------------------------------------
// Name: CGRCamera::Release()
// Desc: Освобождение занятых ресурсов
//-----------------------------------------------------------------------------
void CGRCamera::Release()
{
  m_pMouse->Unacquire(); //UnControl Mouse
  m_pKeyboard->Unacquire(); //UnControl Keyboard

  ReleaseClass(m_pMouse); //Release Mouse
  ReleaseClass(m_pKeyboard); //Release Keyboard
  ReleaseClass(m_pDirectInput); //Release DirectInput

  if (m_pTimer != NULL) { m_pTimer = NULL; DeleteClass(m_pTimer); } //Free Timer Class 
} //EndReleaseProcedure

//-----------------------------------------------------------------------------
// Name: CGRCamera::CreateInputDevices()
// Desc: 
//-----------------------------------------------------------------------------
HRESULT CGRCamera::CreateInputDevices(HWND _HWnd)
{
  HRESULT Result = S_OK;
  //Create InputDevice
  //Создаём тут основной DirectInput интерфейс с указанием его версии для DX API
  if (FAILED(DirectInput8Create(GetModuleHandle(NULL),DIRECTINPUT_VERSION,
  IID_IDirectInput8,(void**)&m_pDirectInput,NULL))) 
  {
    //Интерфейс DirectInput вернул ошибку, чтож продолжать далее не имеет смысла
    //Выводим сообщение об ошибке:
    MessageBoxA(NULL,"Can't Create DirectInputContext","GreenRay Engine Error",
    MB_SYSTEMMODAL|MB_ICONEXCLAMATION); 
    Result = E_FAIL;
  }
  else //Всё в порядке продолжаем:
  {
    //Create Mouse Input Device
    //Создаём виртуальное устройство ввода для мыши
    if (FAILED(m_pDirectInput->CreateDevice(GUID_SysMouse,&m_pMouse,NULL)))
    {
      MessageBoxA(NULL,"Can't Create MouseInputDevice","GreenRay Engine Error",
      MB_SYSTEMMODAL|MB_ICONEXCLAMATION); 
      m_pDirectInput->Release(); 
      Result = E_FAIL;
    }

    //Создаем формат данных для мыши и передаём его в структуру 
    //DirectInput Data Format (DIDATAFORMAT)
    if (FAILED(m_pMouse->SetDataFormat(&c_dfDIMouse2))) 
    {
      MessageBoxA(NULL,"Can't Set MouseDataFormat","GreenRay Engine Error",
      MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
      m_pMouse->Release();
      m_pDirectInput->Release();
      m_pMouse = NULL;
      m_pDirectInput = NULL;
      Result = E_FAIL;
    }
 
    if (FAILED(m_pMouse->SetCooperativeLevel(_HWnd,DISCL_FOREGROUND|DISCL_EXCLUSIVE)))
    {
      MessageBoxA(NULL,"Can't Set Mouse CooperativeLevel","GreenRay Engine Error",
      MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
      m_pMouse->Release();
      m_pDirectInput->Release();
      m_pMouse = NULL;
      m_pDirectInput = NULL;
      Result = E_FAIL;
    }

    //Create Keyboard Input Device
    //Создаём виртуальное устройство ввода для клавиатуры
    if FAILED(m_pDirectInput->CreateDevice(GUID_SysKeyboard,&m_pKeyboard,NULL))
    {
      MessageBoxA(NULL,"Can't Create KeyboardInputDevice","GreenRay Engine Error",
      MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
      m_pKeyboard->Release();
      m_pKeyboard = NULL;
      Result = E_FAIL;
    }
    
    //Создаем формат данных для клавиатуры и передаём его в структуру 
    //DirectInput Data Format (DIDATAFORMAT)
    if (FAILED(m_pKeyboard->SetDataFormat(&c_dfDIKeyboard))) 
    {
      MessageBoxA(NULL,"Can't Set KeyboardDataFormat","GreenRay Engine Error",
      MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
      m_pMouse->Release();
      m_pKeyboard->Release();
      m_pDirectInput->Release();
      m_pDirectInput = NULL;
      Result = E_FAIL;
    }

    if (FAILED(m_pKeyboard->SetCooperativeLevel(_HWnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE)))
    {
      MessageBoxA(NULL,"Can't Set Keyboard CooperativeLevel","GreenRay Engine Error",
      MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
      m_pMouse->Release();
      m_pKeyboard->Release();
      m_pDirectInput->Release();
      m_pDirectInput = NULL;
      Result = E_FAIL;
    }

    /*DIPROPDWORD dipdw = {
    {
      sizeof(DIPROPDWORD),  //diph.dwSize
      sizeof(DIPROPHEADER), //diph.dwHeaderSize
      0,                    //diph.dwObj
      DIPH_DEVICE,},        //diph.dwHow
      DINPUT_BUFFERSIZE256, //dwData
    };
           
    if (FAILED(m_pKeyboard->SetProperty(DIPROP_BUFFERSIZE,&dipdw.diph)))
    {
      MessageBoxA(NULL,"Can't Set Property For KeyboardDevice","GreenRay Engine Error",
      MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
      m_pMouse->Release();
      m_pKeyboard->Release();
      m_pDirectInput->Release();
      m_pDirectInput = NULL;
      return;
    } */
  }
  return Result;
} //EndCreateInputDevicesFunction

//-----------------------------------------------------------------------------
// Name: CGRCamera::UpdateCamera()
// Desc: Poll The DirectInput Devices
//-----------------------------------------------------------------------------
void CGRCamera::UpdateCamera()

  DIMOUSESTATE2 Mouse_Data; //Value Keep Mouse States
  char Key_Buffer[256]; //Buffer To Hold Prev. Keyboard States

  //d_pDevice->TestCooperativeLevel(); 
  float m_fForward = 0;
  float m_fSideward = 0;

  //Donation: GetMouseState 
  if (m_pMouse != NULL) //Check On Ready Mouse
  {         
    //Get Mouse Input Data
    //Перехватываем и обрабатываем входные данные поступающие от "мыши". 
    ZeroMemory(&Mouse_Data,sizeof(Mouse_Data));
    m_pMouse->GetDeviceState(sizeof(Mouse_Data),&Mouse_Data);
    m_pMouse->Acquire();

    //Here Getting Mouse States:
    //Здесь получаем непосредственно координаты поступающие при движении
    //мышкой.
    Pitch-= (double)Mouse_Data.lY*gr_Timer->GetTime()*m_fMouseSpeed;
    Yaw-= (double)Mouse_Data.lX*gr_Timer->GetTime()*m_fMouseSpeed;
   
    //Mouse Button States (0- It's Button Up)
    //Обрабатываем нажатия кнопок мыши:
    if ((Mouse_Data.rgbButtons[0x00] & 0x80) != 0) 
    {
      //Здесь происходит обработка события когда нажата левая кнопка мыши
      //Это понадобится нам позже
    }

  }

  //Donation: GetKeyboardState
  if (m_pKeyboard != NULL) //Check On Ready Keyboard
  {
    //Keyboard Input Data
    //Перехватываем и обрабатываем входные данные поступающие от клавиатуры. 
    ZeroMemory(&Key_Buffer,sizeof(Key_Buffer));
    m_pKeyboard->GetDeviceState(sizeof(Key_Buffer),Key_Buffer);
    m_pKeyboard->Acquire();

    //Keyboard Contol Input Mode
    //Здесь реализовано WASD-овское управление игроком т.е вперёд, назад, вбок 
    //и Strafe соответственно, не долго думая при желании можно переделать его 
    //и в "тракторное" управление, кому как нравится и привычнее, тогда
    //в клавиатурном буфере нужно поменять на: Key_Buffer[DIK_UP], Key_Buffer[DIK_DOWN],
    //Key_Buffer[DIK_LEFT], Key_Buffer[DIK_RIGHT] соответственно..  
    if (Key_Buffer[DIK_W] & 0x80) m_fForward = m_fCameraSpeed*gr_Timer->GetTime();
    if (Key_Buffer[DIK_S] & 0x80) m_fForward = -m_fCameraSpeed*gr_Timer->GetTime();
    if (Key_Buffer[DIK_A] & 0x80) m_fSideward = -m_fCameraSpeed*gr_Timer->GetTime();
    if (Key_Buffer[DIK_D] & 0x80) m_fSideward = m_fCameraSpeed*gr_Timer->GetTime();
    
    //Эта строка понадобится, когда к движку будет подключен PhysX :))
    //и здесь будет обрабатываться "прыжок" игрока..
    //if (Key_Buffer[DIK_SPACE] & 0x80) gr_PhysX->JumpPhysXPlayer(m_fJumpSpeed); //Make The Player Jump
  }

  //Restrict The Ability To Look Too High Or Too Low
  //Здесь происходит ограничение взгляда камеры мышью в 
  //самой верхней точке, т.е когда мы смотрим в потолок, и 
  //в самой нижней когда смотрим в пол..
  //Если не применять этот "ограничитель" то при движении мышкой
  //камера начнет прокручиваться дальше и получится совсем ненужный
  //эффект вставания игрока в "мостик" или на "голову" при взгляде вниз.. :)))) 
  if (Pitch < -1.56f) Pitch = -1.56f; //Y
  if (Pitch > 1.56f) Pitch = 1.56f;
  
  if (Yaw >= 6.28f) Yaw = 0.0f;  //X
  if (Yaw <= -6.28f) Yaw = 0.0f;

  //Get Camera X,Y,Z Position Coordinates
  //Получение позиции камеры игрока в пространстве..
  //Это пригодится к примеру когда мы будем делать привязку SkyBox к
  //нашей камере и много еще для чего в дальнейшем..
  PosX = (cosf(Pitch)*cosf(Yaw)*10.0f);
  PosY = (sinf(Pitch)*10.0f);
  PosZ = (sinf(Yaw)*cosf(Pitch)*10.0f);

  //Здесь идёт расчёт и преобразоание по формуле - позиций, координат, векторов и
  //передача их в матрицы:
  //Set The Target Of The Camera
  Target = D3DXVECTOR3(PosX,PosY,PosZ)+Position;

  //Update The Look Vector
  D3DXVec3Normalize(&Look_Vector,&(Target-Position));
  D3DXVECTOR3 XZLook_Vector = Look_Vector;
  XZLook_Vector.y = 0;
  D3DXVec3Normalize(&XZLook_Vector,&XZLook_Vector);
  D3DXVECTOR3 Side_Vector(XZLook_Vector.z,0.0f,-XZLook_Vector.x);
  Velocity = (XZLook_Vector*m_fForward)+(Side_Vector*m_fSideward);
  

  //Временные преобразования, после подключения PhysX их не станет..
  //Apply Transform
  Position+= (XZLook_Vector*m_fForward)+(Side_Vector*m_fSideward);
  Target+= (XZLook_Vector*m_fForward)+(Side_Vector*m_fSideward);

  //Update The View Matix
  D3DXMatrixLookAtLH(&View,&Position,&Target,&Up);
  //Update The Active View
  d_pDevice->SetTransform(D3DTS_VIEW,&View);
} //EndUpdateCameraProcedure

//-----------------------------------------------------------------------------



А сейчас разберём следующий участок кода:

Код

...
  if (FAILED(m_pMouse->SetCooperativeLevel(_HWnd,DISCL_FOREGROUND|DISCL_EXCLUSIVE)))
  {
    MessageBoxA(NULL,"Can't Set Mouse CooperativeLevel","GreenRay Engine Error",
    MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
    m_pMouse->Release();
    m_pDirectInput->Release(); 
    m_pMouse = NULL;
    m_pDirectInput = NULL;
    Result = E_FAIL;
  }
...



Здесь происходит подключение и привязка устройства мыши к нашему окну, 
как видите, здесь фигурирует HWND переменная 
_HWnd - хендл нашего окна, вот здесь при подключении мыши и позже клавиатуры мы её и применяем.

Примечание! Следует также отметить, что после установки кооперативного режима мышь полностью перехватывается нашим приложением, и курсор мыши становится невидимым, но чтобы его увидеть вновь - необходимо вызвать метод m_pMouse->Unacquire(); и остановив обработчик gr_Camera->UpdateCamera(); тогда наше приложение "отпустит" мышь восвояси. 
Также курсор можно будет сэмулироать и отрисовывать отдельно, но это можно будет реализовать позже - уже при разработке графического интерфейса GRE..


Это сообщение отредактировал(а) php - 5.9.2014, 07:13
--------------------
Джедаи не пройдут..
PM MAIL   Вверх
php
Дата 6.7.2009, 06:53 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 159
Регистрация: 20.2.2003

Репутация: 3
Всего: 3



2.4. Собираем "куб".
1) Для начала создадим новый файл под названием GR_SkyBox.cpp:
Для этого в "дереве" нашего проекта выбираем Source Files и нажимаем на нём правой кнопкой мыши, далее из выпадающего меню выбираем Add->New Item.. Делаем те же действия, что и при создании файла модуля GR_Camera.cpp, не забываем этот файл сохранить в папке Engine_Modules.

Наполняем файл следующим кодом:

Код

/*******************************************************************************
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_SkyBox.cpp
// It's The GreenRay SkyBox Geometry Transform Engine Source File.
// Made Specially For Implementing Only SkyBox Geometry And Effects.
*******************************************************************************/
#include <GR_SkyBox.h>

//////////////////////////////////////////////////////////////////////////////
// Construction/Destruction For CGRSkyBox Class
//////////////////////////////////////////////////////////////////////////////
CGRSkyBox::CGRSkyBox(LPDIRECT3DDEVICE9 pDevice)
{
  //Присваивание и "передача" указателя Direct3D Device в наш класс
  d_pDevice = pDevice; //To Appropriate Device Pointer To Class
  
  //Подготовка вершинного буфера
  m_pVertexBuffer = NULL; //Prepare Vertex Buffer

  //Подготовка индексного буфера
  m_pIndexBuffer = NULL; //Prepare Index Buffer

  //Подготовка текстур, присваивание массиву текстур значения
  //NULL как видите идёт одной строкой:
  memset(m_pTex,0x00,sizeof(m_pTex)); 
} //EndConstructionDirectives

CGRSkyBox::~CGRSkyBox()
{  
} //EndDestructionDirectives

//------------------------------------------------------------------------------
// Name: CGRSkyBox::Release()
// Desc: 
//------------------------------------------------------------------------------
void CGRSkyBox::Release()
{
  for (UINT I = 0; I < 6; I++) { ReleaseClass(m_pTex[I]); m_TexPath[I] = NULL; } //Free Textures
  ReleaseClass(m_pVertexBuffer); //Free Vertex Buffer
  ReleaseClass(m_pIndexBuffer); //Free Index Buffer
  d_pDevice = NULL; //NULL Device Pointer
} //EndReleaseProcedure

//-----------------------------------------------------------------------------
// Name: CGRSkyBox::SetTextures()
// Desc: Loading And Init Textures
//-----------------------------------------------------------------------------
void CGRSkyBox::SetTextures(TCHAR* _TexBack,TCHAR* _TexLeft,
TCHAR* _TexFront,TCHAR* _TexRight,TCHAR* _TexFloor,TCHAR* _TexCeiling)
{
  m_TexPath[0] = _TexBack;
  m_TexPath[1] = _TexLeft;
  m_TexPath[2] = _TexFront;
  m_TexPath[3] = _TexRight;
  m_TexPath[4] = _TexFloor;
  m_TexPath[5] = _TexCeiling;

  //Create Some Textures
  for (UINT I = 0; I < 6; I++)
  {
    if (FAILED(D3DXCreateTextureFromFileEx(d_pDevice,m_TexPath[I],D3DX_DEFAULT,D3DX_DEFAULT,
    1,0,D3DFMT_UNKNOWN,D3DPOOL_MANAGED,D3DX_DEFAULT,D3DX_DEFAULT,0,NULL,NULL,&m_pTex[I])))
    {
      ShowMessage("GRWorld.cpp: Can't Load SkyBox Texture");
    }
  }
} //EndSetTexturesProcedure

//-----------------------------------------------------------------------------
// Name: CGRSkyBox::CreateBox()
// Desc: Создание "коробки" SkyBox-а с инициализацией вершинного и индексного
// буфера.
//-----------------------------------------------------------------------------
HRESULT CGRSkyBox::CreateBox(float fWidth,float fHeight,float fDepth)
{
  m_pWidth = fWidth;
  m_pHeight = fHeight;
  m_pDepth = fDepth;

  //Массив с описанием 6 сторон куба в данной структуре вершин 
  //описываются координаты вершин в пространстве и текстурные
  //"барицентрические" (Barycentric) TU - TV координаты.
  SKYBOX_VERTEX Vertexes[] =
  {
    //Width   Height   Depth  tu(W) tv(H)
    //Back Wall
    { fWidth, 0.0f,    0.0f, 0.0f, 1.0f, }, //A
    { fWidth, fHeight, 0.0f, 0.0f, 0.0f, }, //B
    { 0.0f,   fHeight, 0.0f, 1.0f, 0.0f, }, //C
    { 0.0f,   0.0f,    0.0f, 1.0f, 1.0f, }, //D
   
    //Left Wall
    { 0.0f, 0.0f,    0.0f,   0.0f, 1.0f, }, //A2
    { 0.0f, fHeight, 0.0f,   0.0f, 0.0f, }, //B2
    { 0.0f, fHeight, fDepth, 1.0f, 0.0f, }, //C2
    { 0.0f, 0.0f,    fDepth, 1.0f, 1.0f, }, //D2
    
    //Front Wall
    { 0.0f,   0.0f,    fDepth, 0.0f, 1.0f, }, //A3
    { 0.0f,   fHeight, fDepth, 0.0f, 0.0f, }, //B3
    { fWidth, fHeight, fDepth, 1.0f, 0.0f, }, //C3
    { fWidth, 0.0f,    fDepth, 1.0f, 1.0f, }, //D3
    
    //Right Wall
    { fWidth, 0.0f,    fDepth, 0.0f, 1.0f, }, //A4  
    { fWidth, fHeight, fDepth, 0.0f, 0.0f, }, //B4
    { fWidth, fHeight, 0.0f,   1.0f, 0.0f, }, //C4
    { fWidth, 0.0f,    0.0f,   1.0f, 1.0f, }, //D4
    
    //Floor    
    { fWidth, 0.0f, 0.0f,   1.0f, 1.0f, }, //A5
    { 0.0f,   0.0f, 0.0f,   0.0f, 1.0f, }, //B5
    { 0.0f,   0.0f, fDepth, 0.0f, 0.0f, }, //C5
    { fWidth, 0.0f, fDepth, 1.0f, 0.0f, }, //D5
     
    //Ceiling
    { fWidth, fHeight, fDepth, 1.0f, 1.0f, }, //A6 
    { 0.0f,   fHeight, fDepth, 0.0f, 1.0f, }, //B6
    { 0.0f,   fHeight, 0.0f,   0.0f, 0.0f, }, //C6
    { fWidth, fHeight, 0.0f,   1.0f, 0.0f, }, //D6
    //  x        y       z     tu(W) tv(H)
  }; //End Vertexes Description

  //Массив индексов содержащий и описывающий 6 сторон куба (12 треугольников)
  const unsigned short Index[] = 
  {
  0,1,2,    2,3,0,
  4,5,6,    6,7,4,
  8,9,10,   10,11,8,
  12,13,14, 14,15,12,
  16,17,18, 18,19,16,
  20,21,22, 22,23,20, 
  }; //End Indexes Description
    
  //Create Vertex Buffer
  //Создание буфера вершин
  if (FAILED(d_pDevice->CreateVertexBuffer(36*sizeof(SKYBOX_VERTEX),0, 
  D3DFVF_SKYBOXVERTEX,D3DPOOL_DEFAULT,&m_pVertexBuffer,NULL))) return E_FAIL;

  //Lock The Vertex Buffer
  //Блокируем вершинный буфер
  VOID* pBV;
  if (FAILED(m_pVertexBuffer->Lock(0,sizeof(Vertexes),(void**)&pBV,0))) return E_FAIL;
  
  //Заполнение вершинного буфера данными
  memcpy(pBV,Vertexes,sizeof(Vertexes)); //Copy Vertex Data To Memory

  //Разблокируем вершинный буфер
  m_pVertexBuffer->Unlock(); //Unlock The Vertex Buffer
    
  //Create Index Buffer
  //Создание индексного буфера, здесь всё происходит 
  //примерно тоже самое, что и при создании вершинного буфера.
  d_pDevice->CreateIndexBuffer(36*sizeof(Index),0,D3DFMT_INDEX16,D3DPOOL_DEFAULT,&m_pIndexBuffer,NULL);
    
  //Lock The Index Buffer
  VOID* pBI;
  m_pIndexBuffer->Lock(0,sizeof(Index),(void**)&pBI,0); 
    
  memcpy(pBI,Index,sizeof(Index)); //Copy Index Data To Memory
      
  m_pIndexBuffer->Unlock(); //Unlock The Index Buffer
 
  return S_OK;
} //EndCreateSkyBoxFunction

//-----------------------------------------------------------------------------
// Name: CGRSkyBox::Render()
// Desc: Rendering The SkyBox Geometry With Textures
//-----------------------------------------------------------------------------
void CGRSkyBox::Render()
{  
  //Устанавливаем параметры рендера и отключаем Z-Буфер
  d_pDevice->SetRenderState(D3DRS_ZENABLE,FALSE);
  d_pDevice->SetRenderState(D3DRS_ZWRITEENABLE,FALSE);
  d_pDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
  d_pDevice->SetRenderState(D3DRS_LIGHTING,FALSE);

  //VU Addr Задаём параметры текстурного сэмплера.
  d_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP);
  d_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_CLAMP);

  //Set Texture Mode
  //d_pDevice->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
  //d_pDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);    
  //d_pDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
  d_pDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
  d_pDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
  //d_pDevice->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_POINT);

  //Set Perspective View For Spherical Show SkyBox In Space (60 Degree) 
  //Установка камеры и "перспективы" FOV - Field Of View (область обзора)
  //в сферическое представление с углом в 60 градусов.
  float Aspect_Ratio = 1.1f;
  D3DXMATRIXA16 Mat_Proj;
  //FLOAT fAspectRatio = (float)m_d3dsdBackBuffer.Width/(float)m_d3dsdBackBuffer.Height;
  D3DXMatrixPerspectiveFovLH(&Mat_Proj,/*D3DX_PI/4*/D3DXToRadian(60.0f),Aspect_Ratio,1.0f,1000.0f);
  d_pDevice->SetTransform(D3DTS_PROJECTION,&Mat_Proj); 

  //Translation Matrices For The SkyBox Object
  //Устанавливаем размеры, позицию в центр, и привязываем SkyBox к камере,
  //чтобы SkyBox как бы двигался вместе с игроком и сам игрок не "приближался" 
  //к граням SkyBox в игровом пространстве.
  D3DXMATRIXA16 Mat_Trans,Mat_Rotate,Mat_Pos,Mat_Centered; 
  //                                        W           H           D
  D3DXMatrixTranslation(&Mat_Centered,-m_pWidth/2,-m_pHeight/2,-m_pDepth/2); 
  D3DXMatrixRotationYawPitchRoll(&Mat_Rotate,D3DX_PI,0.0f,0.0f);
  D3DXMatrixTranslation(&Mat_Pos,gr_Camera->Pos().x,gr_Camera->Pos().y,gr_Camera->Pos().z);
  Mat_Trans = (Mat_Centered*Mat_Rotate)*Mat_Pos; //Multiply Matrices
  d_pDevice->SetTransform(D3DTS_WORLD,&Mat_Trans); //Transform Object Position In Space

  //Draw The SkyBox Here
  //Set Vertex And Index Buffers To Render
  //Ну а здесь уже собственно происходит отрисовка самих граней (полигонов) 
  //SkyBox-куба и наложение текстур..
  d_pDevice->SetTexture(0,NULL);
 
  //Устанавливаем в устройстве текущий вершинный буфер
  d_pDevice->SetStreamSource(0,m_pVertexBuffer,0,sizeof(SKYBOX_VERTEX));
  //Устанавливаем подготовленный ранее FVF наших вершин D3DFVF_SKYBOXVERTEX)
  d_pDevice->SetFVF(D3DFVF_SKYBOXVERTEX); 
  //Устанавливаем индексы из ранее подготовленного индексного буфера:
  d_pDevice->SetIndices(m_pIndexBuffer);
  
  //Output For Created Objects
  //Рендеринг "стенок" куба и  текстур. Вывод примитивов 
  //посредством индексного буфера осуществляется методом DrawIndexedPrimitive

  //Render BackWall
  if (m_pTex[0] != NULL) d_pDevice->SetTexture(0,m_pTex[0]);
  d_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2 );
  
  //Render LeftWall
  if (m_pTex[1] != NULL) d_pDevice->SetTexture(0,m_pTex[1]);
  d_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 4, 0, 4, 0, 2 ); //Offset To 4 Base Vertex Index 

  //Render FrontWall
  if (m_pTex[2] != NULL) d_pDevice->SetTexture(0,m_pTex[2]);
  d_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 8, 0, 4, 0, 2 ); //Offset To 8 Base Vertex Index 

  //Render RightWall
  if (m_pTex[3] != NULL) d_pDevice->SetTexture(0,m_pTex[3]);
  d_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 12, 0, 4, 0, 2 ); //Offset To 12 Base Vertex Index 

  //Render Floor
  if (m_pTex[4] != NULL) d_pDevice->SetTexture(0,m_pTex[4]);
  d_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 16, 0, 4, 0, 2 ); //Offset To 16 Base Vertex Index

  //Render Ceiling
  if (m_pTex[5] != NULL) d_pDevice->SetTexture(0,m_pTex[5]);
  d_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 20, 0, 4, 0, 2 ); //Offset To 20 Base Vertex Index

  //Здесь уже возвращаем исходные параметры и активируем Z-Buffer, это необходимо
  //для устранения влияния параметров SkyBox на отрисовку последующих
  //элементов сцены которые будут рендериться после самого SkyBox-а в дальнейшем..
  d_pDevice->SetRenderState(D3DRS_ZENABLE,TRUE);
  d_pDevice->SetRenderState(D3DRS_ZWRITEENABLE,TRUE);
  
  //VU Addr Возвращаем исходные параметры для отрисовки текстур,
  //так называемые текстурные "сэмплеры" и устанавливаем их в режим 
  //"обёртки" - WRAP, если этого не сделать, то модель или другая геометрия
  //игрового "мира" имеющая текстуры будет рендериться некорректно, т.е 
  //изображение текстуры будет как бы растягиваться от краёв к центру, иными словами
  //будет сказываться влияние текстурного состояния CLAMP которое мы устанавливали
  //ранее для отрисовки SkyBox..
  d_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_WRAP);
  d_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_WRAP);
} //EndRenderProcedure

//-----------------------------------------------------------------------------



2) Создаем файл GR_SkyBox.h:
Для этого также в "дереве" проекта выбираем Header Files, и не забываем сохранить этот файл туда же в папку Engine_Modules и наполняем этот файл следующим кодом:

Код

/*******************************************************************************
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_SkyBox.h: Interface For The SkyBox Geometry Implementation Class.
// It's The GreenRay SkyBox Geometry Transform Engine.
// Made Specially For Implementing Only SkyBox Geometry And Effects.
*******************************************************************************/
#include <GR_Engine.h>
#include <GR_Methods.h>
#include <GR_Camera.h>

////////////////////////////////////////////////////////////////////////////////
// Classes Used By This Header
////////////////////////////////////////////////////////////////////////////////
//class CGRSkyBox;

//-----------------------------------------------------------------------------
// Name: CGRSkyBox
// Desc: The Box Class
//-----------------------------------------------------------------------------
#if !defined(AFX_SKYBOX_H__)
#define AFX_SKYBOX_H__

//Константа FVF содержащая формат и структуру вершин 
#define D3DFVF_SKYBOXVERTEX (D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_TEXCOORDSIZE3(0)) //Vertex Format

class CGRSkyBox
{
public:
   /*Public Directives*/
  //SkyBox Vertex, Normals, Texures Positions
  //Структура содержащая координаты вершин, нормали,
  //цвет и текстурные координаты.
  struct SKYBOX_VERTEX
  {
    FLOAT x,y,z;    //Coordinates
    FLOAT nx,ny,nz; //Normals
    DWORD _Color;   //Vertex Color
    FLOAT tu,tv;    //Textures
  }; //End SkyBox Vertex Formats

  CGRSkyBox(LPDIRECT3DDEVICE9 pDevice);
  virtual ~CGRSkyBox();
  void Release();
  void SetTextures(TCHAR* _TexBack,TCHAR* _TexLeft,TCHAR* _TexFront,
  TCHAR* _TexRight,TCHAR* _TexFloor,TCHAR* _TexCeiling);
  HRESULT CreateBox(float fWidth,float fHeight,float fDepth);
  void Render();
protected:
  /*Protected Directives*/
  LPDIRECT3DDEVICE9 d_pDevice; //Pointer On Direct3D Device Interface
  IDirect3DVertexBuffer9* m_pVertexBuffer; //The Vertex Buffer
  IDirect3DIndexBuffer9* m_pIndexBuffer; //The Index Buffer
  IDirect3DTexture9* m_pTex[6]; //Variable Keep Same Textures
  TCHAR* m_TexPath[6]; //Variable Keep Texture Path
  float m_pWidth,m_pHeight,m_pDepth; //Variables Keep SkyBox WHD Size
};
#endif //!defined(AFX_SKYBOX_H__)



3) Если заметите в разделе include я использую #include <GR_Methods.h>
В этом модуле содержатся различные вспомогательные процедуры и функции которые вызываются в движке это различные таймеры, диалоговые окна и др. Создаём и его - для этого в "дереве" нашего проекта выбираем Source Files и нажимаем на нём правой кнопкой мыши, далее из выпадающего меню выбираем Add->New Item.. и сохраняем его под именем GR_Methods.cpp в папку Engine_Modules.
Код файла модуля будет следующим:

Код

/******************************************************************************
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_Methods.cpp
// It's The GreenRay Direct3D Useful Control Interfaces Engine Source File.
// Made Specially For Implementing Useful Engine System Manipulations Parameters.
******************************************************************************/
#include <GR_Methods.h>

//-----------------------------------------------------------------------------
// Name: ShowMessage()
// Desc: 
//-----------------------------------------------------------------------------
void ShowMessage(LPCSTR Mes_String)
{
  MessageBoxA(NULL,Mes_String,"GreenRay Engine",MB_SYSTEMMODAL|MB_ICONERROR);
} //EndShowMessageProcedure

///////////////////////////////////////////////////////////////////////////////
// Construction/Destruction For CGRDeltaTimer Class
///////////////////////////////////////////////////////////////////////////////
CGRDeltaTimer::CGRDeltaTimer()
{
} //EndConstructionDirectives

CGRDeltaTimer::~CGRDeltaTimer()

} //EndDestructionDirectives

//-----------------------------------------------------------------------------
// Name: CGRDeltaTimer::UpdateTimer()
// Desc: Execute Each Frame To Establish Time Base
//-----------------------------------------------------------------------------
void CGRDeltaTimer::UpdateTimer()
{
  CurrentTime = timeGetTime();
  DeltaTime = (float)((CurrentTime-LastTime)*0.001f);
  LastTime = CurrentTime;
} //EndUpdateTimerProcedure

//-----------------------------------------------------------------------------
// Name: CGRDeltaTimer::GetTime()
// Desc:
//-----------------------------------------------------------------------------
float CGRDeltaTimer::GetTime()
{
  return DeltaTime;
} //EndGetTimeFunction

///////////////////////////////////////////////////////////////////////////////
// Construction/Destruction For CGRTimer Class
///////////////////////////////////////////////////////////////////////////////
CGRTimer::CGRTimer()
{
  m_bUsingQPF         = false;
  m_bTimerStopped     = true;
  m_llQPFTicksPerSec  = 0;

  m_llStopTime        = 0;
  m_llLastElapsedTime = 0;
  m_llBaseTime        = 0;

 //Use QueryPerformanceFrequency() To Get Frequency Of Timer.  
 LARGE_INTEGER qwTicksPerSec;
 m_bUsingQPF = (bool)(QueryPerformanceFrequency(&qwTicksPerSec) != 0);
 m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
} //EndConstructionDirectives

CGRTimer::~CGRTimer()

} //EndDestructionDirectives

//-----------------------------------------------------------------------------
// Name: CGRTimer::Reset()
// Desc: 
//-----------------------------------------------------------------------------
void CGRTimer::Reset()
{
  if (!m_bUsingQPF) return;

  //Get Either The Current Time Or The Stop Time
  LARGE_INTEGER qwTime;
  if (m_llStopTime != 0) qwTime.QuadPart = m_llStopTime;
  else QueryPerformanceCounter(&qwTime);

  m_llBaseTime = qwTime.QuadPart;
  m_llLastElapsedTime = qwTime.QuadPart;
  m_llStopTime = 0;
  m_bTimerStopped = FALSE;
} //EndResetProcedure

//-----------------------------------------------------------------------------
// Name: CGRTimer::Start()
// Desc: 
//-----------------------------------------------------------------------------
void CGRTimer::Start()
{
  if (!m_bUsingQPF) return;

  //Get The Current Time
  LARGE_INTEGER qwTime;
  QueryPerformanceCounter(&qwTime);

  if (m_bTimerStopped) m_llBaseTime+= qwTime.QuadPart-m_llStopTime;
  m_llStopTime = 0;
  m_llLastElapsedTime = qwTime.QuadPart;
  m_bTimerStopped = FALSE;
} //EndStartProcedure

//-----------------------------------------------------------------------------
// Name: CGRTimer::Stop()
// Desc: 
//-----------------------------------------------------------------------------
void CGRTimer::Stop()
{
  if (!m_bUsingQPF) return;

  if (!m_bTimerStopped)
  {
    //Get Either The Current Time Or The Stop Time
    LARGE_INTEGER qwTime;
    if (m_llStopTime != 0) qwTime.QuadPart = m_llStopTime;
    else QueryPerformanceCounter(&qwTime);

    m_llStopTime = qwTime.QuadPart;
    m_llLastElapsedTime = qwTime.QuadPart;
    m_bTimerStopped = TRUE;
  }
} //EndStopProcedure

//-----------------------------------------------------------------------------
// Name: CGRTimer::Advance()
// Desc: 
//-----------------------------------------------------------------------------
void CGRTimer::Advance()
{
  if (!m_bUsingQPF) return;
  m_llStopTime+= m_llQPFTicksPerSec/10;
} //EndAdvanceProcedure

//-----------------------------------------------------------------------------
// Name: CGRTimer::GetAbsoluteTime()
// Desc: 
//-----------------------------------------------------------------------------
double CGRTimer::GetAbsoluteTime()
{
  if (!m_bUsingQPF) return -1.0;

  //Get Either The Current Time Or The Stop Time
  LARGE_INTEGER qwTime;
  if (m_llStopTime != 0) qwTime.QuadPart = m_llStopTime;
  else QueryPerformanceCounter(&qwTime);

  double fTime = qwTime.QuadPart/(double) m_llQPFTicksPerSec;
  return fTime;
} //EndGetAbsoluteTimeFunction

//-----------------------------------------------------------------------------
// Name: CGRTimer::GetTime()
// Desc: 
//-----------------------------------------------------------------------------
double CGRTimer::GetTime()
{
  if (!m_bUsingQPF) return -1.0;

  //Get Either The Current Time Or The Stop Time
  LARGE_INTEGER qwTime;
  if (m_llStopTime != 0) qwTime.QuadPart = m_llStopTime;
  else QueryPerformanceCounter(&qwTime);

  double fAppTime = (double)(qwTime.QuadPart-m_llBaseTime)/(double)m_llQPFTicksPerSec;
  return fAppTime;
} //EndGetTimeFunction

//-----------------------------------------------------------------------------
// Name: CGRTimer::GetElapsedTime()
// Desc: 
//-----------------------------------------------------------------------------
double CGRTimer::GetElapsedTime()
{
  if (!m_bUsingQPF) return -1.0;

  //Get Either The Current Time Or The Stop Time
  LARGE_INTEGER qwTime;
  if (m_llStopTime != 0) qwTime.QuadPart = m_llStopTime;
  else QueryPerformanceCounter(&qwTime);

  double fElapsedTime = (double)(qwTime.QuadPart-m_llLastElapsedTime)/(double)m_llQPFTicksPerSec;
  m_llLastElapsedTime = qwTime.QuadPart;

  return fElapsedTime;
} //EndGetElapsedTimeFunction

//-----------------------------------------------------------------------------
// Name: CGRTimer::IsStopped()
// Desc: 
//-----------------------------------------------------------------------------
bool CGRTimer::IsStopped()
{
  return m_bTimerStopped;
} //EndIsStoppedFunction



4) Также создаём и файл GR_Methods.h выбрав для этого из "дерева" проекта Header Files, и сохранив в папку Engine_Modules.
Код модуля:

Код

/******************************************************************************
// It's Unofficial Version Of The GreenRay Engine v.3.0.0.2
// GR_Methods.h
// It's The GreenRay Direct3D Useful Control Interfaces Engine Header File.
// Made Specially For Implementing Useful Engine System Manipulations Parameters.
******************************************************************************/
#include <GR_Engine.h>

////////////////////////////////////////////////////////////////////////////////
// Directives For Release Classes
////////////////////////////////////////////////////////////////////////////////
#define ReleaseClass(_Ptr) { if (_Ptr) { (_Ptr)->Release(); (_Ptr) = NULL; } }
//Directive For Delete Classes
#define DeleteClass(_Ptr) { if (_Ptr) { delete(_Ptr); (_Ptr) = NULL; } }
//Directive For Delete Arrays
#define DeleteArray(_Ptr) { if (_Ptr) { delete[](_Ptr); (_Ptr) = NULL; } }

////////////////////////////////////////////////////////////////////////////////
// Exporting Procedures And Functions
////////////////////////////////////////////////////////////////////////////////
void ShowMessage(LPCSTR Mes_String);

////////////////////////////////////////////////////////////////////////////////
// Classes Used By This Header
////////////////////////////////////////////////////////////////////////////////
//class CGRFPSCounter;
//class CGRDeltaTimer;
//class CGRTimer;

//-----------------------------------------------------------------------------
// Name: Struct CGRDeltaTimer
// Desc:
//-----------------------------------------------------------------------------
#if !defined(AFX_DELTATIMER_H__)
#define AFX_DELTATIMER_H__

class CGRDeltaTimer

public:
  /*Public Directives*/
  CGRDeltaTimer();
  virtual ~CGRDeltaTimer();
  void UpdateTimer();
  float GetTime();
private:
  /*Private Directives*/
  DWORD CurrentTime; //Current Timer Value
  DWORD LastTime;    //Previous Timer Value
  float DeltaTime;   //Time Elapsed Since Last Frame
};
#endif //!defined(AFX_DELTATIMER_H__)

//-----------------------------------------------------------------------------
// Name: Struct CGRTimer
// Desc:
//-----------------------------------------------------------------------------
#if !defined(AFX_TIMER_H__)
#define AFX_TIMER_H__

class CGRTimer

public:
  /*Public Directives*/  
  CGRTimer();
  virtual ~CGRTimer();
  
  void Reset(); //Resets The Timer
  void Start(); //Starts The Timer
  void Stop(); //Stop (Or Pause) The Timer
  void Advance(); //Advance The Timer By 0.1 Seconds
  double GetAbsoluteTime(); //Get The Absolute System Time
  double GetTime(); //Get The Current Time
  double GetElapsedTime(); //Get The Time That Elapsed Between GetElapsedTime() Calls
  bool IsStopped(); //Returns True If Timer Stopped
private:
  /*Private Directives*/
protected:
  /*Protected Directives*/
  bool m_bUsingQPF;
  bool m_bTimerStopped;
  LONGLONG m_llQPFTicksPerSec;

  LONGLONG m_llStopTime;
  LONGLONG m_llLastElapsedTime;
  LONGLONG m_llBaseTime;
};
#endif //!defined(AFX_TIMER_H__)

////////////////////////////////////////////////////////////////////////////////
// Global Variables Or Constants
////////////////////////////////////////////////////////////////////////////////
extern CGRDeltaTimer* gr_Timer; //GreenRay Timer Interface Class



Добавлено @ 06:53
Ну вот теперь почти всё готово. Теперь разберём некоторые участки кода в модуле SkyBox.cpp:

Код

...
  if (FAILED(d_pDevice->CreateVertexBuffer(36*sizeof(SKYBOX_VERTEX),0, 
  D3DFVF_SKYBOXVERTEX,D3DPOOL_DEFAULT,&m_pVertexBuffer,NULL))) return E_FAIL;
...


Здесь происходит создание вершинного буфера, он служит для
хранения набора вершин объекта и представляет из себя сплошной
блок памяти, также позволяет вполне компактно хранить и обрабатывать
информацию о вершинах, в качестве параметров здесь указывается формат
вершин (структура хранящая данные о координатах, цвете и нормалях вершин, а
также координаты текстур и многое другое, иными словами называемая ещё 
как FVF (Flexible Vertex Format)) и размер буфера с параметрами размещения 
буфера в памяти.
Как мы видим, для указания формата вершин используется константа 
D3DFVF_SKYBOXVERTEX объявленная в модуле GR_SkyBox.h.

Для получения доступа к данным буфера используется метод Lock интерфейса
m_pVertexBuffer, здесь копируются в адрес Vertexes подготовленные 
описания наших вершин

Код

...
  VOID* pBV;
  if (FAILED(m_pVertexBuffer->Lock(0,sizeof(Vertexes),(void**)&pBV,0))) return E_FAIL;
...



После заполнения вершинного буфера данными необходимо вызвать метод Unlock,
если этого не сделать, то отрисовка SkyBox происходить не будет, 
да это может вызвать и ошибку работы движка, т.к сам буфер мы изначально 
перевели в заблокированное состояние, поэтому после всех манипуляций его 
необходимо разблокировать:

Код

...
  m_pVertexBuffer->Unlock(); //Unlock The Vertex Buffer
...


Создание индексного буфера

Код

...
  d_pDevice->CreateIndexBuffer(36*sizeof(Index),0,D3DFMT_INDEX16,D3DPOOL_DEFAULT,&m_pIndexBuffer,NULL);
...


Примечание! Вообще можно было бы обойтись созданием только лишь вершинным
буфером, но как оказывается на практике данный способ может приводить
к некоторым трудностям при работе только лишь с вершинами, оказывается,
что это очень неэкономичный способ, т.к приходится дублировать эти вершины в 
вершинном буфере, и применяется для создания лишь самой простейшей геометрии,
хотя наш "скайбокс" и не обладает сверхнавороченной геометрией, всё же лучше использовать индексный режим вывода геометрии, т.к данный способ позволяет использовать для описания треугольников не сами вершины, а их индексы (порядковые номера в вершинном буфере). Это позволяет не только не дублировать вершинные данные, но и экономить память (целочисленные индексы занимают намного меньше места, чем вершинные).

Далее разберём код в рендере самого SkyBox:

Код

...
  d_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP);
  d_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_CLAMP);
...


Тут задаются параметры текстурного сэмплера, здесь кроется 
ключевой момент в отрисовке и рендеринга текстур самого SkyBox-а.
Режим "сэмплера" CLAMP обеспечивает "затирание" стыков в углах и граней SkyBox, если этого не сделать, то сразу будут бросаться в глаза ярко выраженные линии стыков по углам, от чего вся иллюзия целостности и объемности пространства полностью сойдет на нет.. Но для того, чтобы добиться нормального результата работы данного 
режима "сэмплирования", каждая текстура кубической карты должна быть строго одинакового размера, если допустим у вас размер текстуры кубической карты 256x256 то и размер всех остальных текстур должен быть таким же, иначе может получиться эффект "сползания" текстуры вбок, и как результат некорректное и некрасивое отображение и отрисовка.. Вообще если заметить то стыки на границах "скайбокса" можно было наблюдать достаточно во многих старых играх, я встречал даже и в более новых..

5) В конце не забудьте положить скачанные текстуры SkyBox-а в папку, которая
создаётся после компиляции проекта и называется "Debug" в ней обычно создаётся и хранится сам скомпилированный *.exe-файл проекта GRDebugger.exe, а также файлы объектов *.obj которые создаются в результате компилирования модулей *.cpp и *.h самого GRE.  Эти файлы должны лежать по пути:
 
../GreenRay/GRDebugger/Debug/Textures/SkyBox/GrandCanyon/

Название конечной папки может называться и по другому на ваше усмотрение, в нашем
случае она называется GrandCanyon, в ней должны лежать файлы с именами соответствующими сторонам SkyBox-куба это: xneg.png, xpos.png, yneg.png, ypos.png, zneg.png, zpos.png, т.е всего 6 файлов, форматы файлов могут быть и другими такие как Jpg, Bmp и др. Этот набор файлов необходим для формирования так называемой кубической карты "CubeMap" далее эти текстуры накладываются на внутренние грани самого SkyBox-куба, в определённом порядке в результате чего формируется эффект окружения и 3-х мерное представление какого-либо помещения, мира, ландшафта, космоса и планет. Эти текстуры можно получить или сделать в специализированных программах, или они фотографируются специализированным оборудованием и фотокамерами в определённой проекции, наиболее распространённый метод для 
фотографирования это кубические проекции, снимаются в шести взаимно перпендикулярных направлениях (включая верх и низ), и представляются в виде крестообразной развёртки:

user posted image

Примечание! Не забудьте, если у вас папка будет иметь другое имя и путь,
то необходимо этот путь изменить и в коде движка, иначе текстуры загружаться не 
будут, что приведёт к ошибке и закрытию приложения GRE.
Посмотрим на участок кода в модуле GR_Engine.cpp где происходит создание класса SkyBox:

Код

...
  //Create SkyBox Class
  gr_SkyBox = new CGRSkyBox(m_pDevice); //Construct A CGRSkyBox Class  
  gr_SkyBox->CreateBox(100.0f,100.0f,100.0f); //Create Our SkyBox Model With Size WHD
  gr_SkyBox->SetTextures(TEXT("\Textures\\SkyBox\\GrandCanyon\\zneg.png"),
                     TEXT("\Textures\\SkyBox\\GrandCanyon\\xneg.png"),
             TEXT("\Textures\\SkyBox\\GrandCanyon\\zpos.png"),
             TEXT("\Textures\\SkyBox\\GrandCanyon\\xpos.png"),
             TEXT("\Textures\\SkyBox\\GrandCanyon\\yneg.png"),
             TEXT("\Textures\\SkyBox\\GrandCanyon\\ypos.png"));
...


Здесь создаётся класс "Скайбокса", указываются его размеры в данном случае 100, ну
и соответственно пути к нашим CubeMap-текстурам.

Примечание! Текстуры CubeMap для движка или другие дополнительные текстуры SkyBox можно взять отсюда: www.codemonsters.de/home/content.php?show=cubemaps

2.5. Заключение.
Итак в итоге после компиляции проекта должно получиться как на рисунке представленном ниже:

user posted image

Или ещё вот такой вариант загрузки SkyBox:

user posted image

Также рекомендуется проверить как работает наша игровая камера, если всё в порядке и камера подключилась нормально то мы сможем осмотреться вокруг, вверх и вниз, ну а если при движении мыши ничего не происходит значит устройства ввода не работают, либо неправильно были переданы какие-либо параметры, либо не произошла инициализация библиотеки DirectInput. 

В следующих статьях мы будем подключать физический движок - PhysX, загрузим небольшой примитивненький уровень, поработаем над его освещением, и научим нашего игрока не "проваливаться" сквозь стены..

До новых встреч! Keep smile! Пока! smile

_________________________________________________________________________
© Digital Dreams Development Inc., 2009 
(С) GR-Engine Technical Documentation.
при поддержке © Polarity Soft Engine Inc.  
Любая публикация изложенного материала только с разрешения автора.

Это сообщение отредактировал(а) php - 5.9.2014, 07:14
--------------------
Джедаи не пройдут..
PM MAIL   Вверх
arilou
Дата 6.7.2009, 13:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Великий МунаБудвин
****


Профиль
Группа: Экс. модератор
Сообщений: 2646
Регистрация: 15.7.2004
Где: город-герой Минск

Репутация: 6
Всего: 61



Цитата(php @  6.7.2009,  06:53 Найти цитируемый пост)
© Digital Dreams Development Inc., 2009 
(С) GR-Engine Technical Documentation.
при поддержке © Polarity Soft Engine Inc.  
Любая публикация изложенного материала только с разрешения автора.


оффтоп: многовато копирайтов  smile достаточно было написать "Любая публикация изложенного материала только с разрешения автора", имхо.


--------------------
user posted imageuser posted image
PM WWW ICQ   Вверх
php
Дата 6.7.2009, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 159
Регистрация: 20.2.2003

Репутация: 3
Всего: 3



Цитата

многовато копирайтов  smile достаточно было написать "Любая публикация изложенного материала только с разрешения автора", имхо.


 smile Ндаа действительно немного перебор с копирайтами.., ладно в следующий раз вообще их
вписывать не буду, этих достаточно будет.. 
--------------------
Джедаи не пройдут..
PM MAIL   Вверх
nogoody
Дата 15.7.2009, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 72
Регистрация: 12.9.2007
Где: Смоленск

Репутация: нет
Всего: нет



Попробовал пример, единственное ругался на dmusici.h, пришлось закоментить
А так все супер, очень жду продолжения, автору спасибо  smile 

PM MAIL   Вверх
ShellRaiser
Дата 16.7.2009, 15:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


еще чуть и закоммичу
*


Профиль
Группа: Участник
Сообщений: 156
Регистрация: 20.7.2007
Где: Белaрусь, Гродно

Репутация: 1
Всего: 1



Цитата(ISergeyN @ 22.4.2009,  11:02)
Вот это странный код
Код

  if (m_pDirect3D==NULL)//if (!m_pDirect3D)
  {
    if (m_pDirect3D != NULL) //это зачем ? эсли словие ни когда не сработает!
             m_pDirect3D->Release(); //
    MessageBoxA(NULL,"GR_Engine.cpp: Failed To Create Direct3D Interface..",
    "GreenRay Engine Error",MB_SYSTEMMODAL|MB_ICONERROR);
    m_pResult = E_FAIL;
  }

php, а ведь он как бы прав=)

я бы написал как по твоим описаниям вот так вот:
Код

  if (m_pDirect3D==NULL)//if (!m_pDirect3D)
  {
    //если нет то создаёшь
    MessageBoxA(NULL,"GR_Engine.cpp: Failed To Create Direct3D Interface..",
    "GreenRay Engine Error",MB_SYSTEMMODAL|MB_ICONERROR);
    m_pResult = E_FAIL;
  }
  else
  {
       m_pDirect3D->Release();//иначе сбрасываешь....
  }

ну ет если логически подумать;)
PM MAIL ICQ Skype   Вверх
N.M.Guard
Дата 18.7.2009, 13:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 19.1.2008

Репутация: нет
Всего: нет



php спасибо большое за статью!!! С удовольствием жду продолжения !!!

P.S. 
Для удобства обсуждения можно каждое продолжение в отдельную тему писать!!! smile

Это сообщение отредактировал(а) N.M.Guard - 18.7.2009, 13:48
PM MAIL ICQ   Вверх
pirat77
  Дата 26.7.2009, 09:15 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 10.11.2008

Репутация: нет
Всего: нет



Так как только ещё учусь C++,обратил внимание на этот урок (за что его создателю спасибо) ,но вот почему то возникла такая проблема при debug'е user posted image и таких 6 окошек с ошибкой к каждой текстуре, но из папки debug всё прекрасно запускается и работает. Как решить данную неувязку?  smile 

Это сообщение отредактировал(а) pirat77 - 26.7.2009, 09:32
PM MAIL   Вверх
php
Дата 27.7.2009, 08:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 159
Регистрация: 20.2.2003

Репутация: 3
Всего: 3



pirat77  Данная ошибка показывается самим движком GRE, чтобы удобнее было устранять и узнавать где когда и почему произошла ошибка, эта ошибка, что произошла в 
вашем случае может выводиться по двум причинам: из-за физического отсутствия папки с текстурами на диске или неверно прописанного пути в теле программы, и если текстура не найдена или не загружается, то GRE выводит подобную ошибку, но судя по вашему ответу папка с текстурами у вас всё же существует, в вашем случае можно поступить двумя способами:

1. Скопировать папку Textures в папку где лежит файл проекта .sln по умолчанию он должен лежать в папке GRDebugger, но только учтите, что скоро в движке будут реализовываться модели - сами файлы моделей тоже будут лежать в папке Debug и вам придётся постоянно их "дублировать" если захотите запустить движок в режиме отладки, что на мой взгляд не совсем удобно..

2. Как можно увидеть в движке путь к папке с текстурами указан частично: 
"\Textures\\SkyBox\\Arch\\zneg.png", что из этого следует - он обработает этот путь только из 
текущей папки проекта или откуда был запущен exe-шник самого движка, но можно указать 
путь явным образом, к примеру:
"C:\\GreenRay\\GRDebugger\\Debug\\Textures\\SkyBox\\Arch\\zneg.png", но тут 
опять могут возникнуть проблемы, если вы к примеру принесёте движок к другу и запустите он у него работать не будет если путь будет отличаться от выше приведённого или располагаться в другой папке или диске...

Цитата

Попробовал пример, единственное ругался на dmusici.h, пришлось закоментить


Хм странно, вообще это DirectMusic Interface, нужен будет позже когда будет подключаться
возможность проигрывания файлов mp3 в GRE, и обычно находится а разделе Include DirectX SDK, проверьте может неверно прописаны пути к папке Include или некорректно установлен Сам DX SDK, если не поможет могу выложить этот файл сюда..

Цитата

Для удобства обсуждения можно каждое продолжение в отдельную тему писать!!!


Ок так и сделаем в следущий раз.. smile 


Это сообщение отредактировал(а) php - 27.7.2009, 08:29
--------------------
Джедаи не пройдут..
PM MAIL   Вверх
stuqs
Дата 27.7.2009, 12:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 26.7.2009

Репутация: нет
Всего: нет



Статья интересная спору нет. Но она изложена все же для понимающих людей, кто разбирается в функциях DirectX, что зачем идет и тд. Очень хочется понимать  весь код - поэтому большая просьба выложить название каких-нибудь книг, самоучителей по DirectX на C++ где можно будет разобраться с самого начала. ( а то вставлять чужой код и получать работающие программы интересно, но намного интереснее писать свой код) Гугл в помощь просьба не давать, находил много книг, но устаревших с не актуальной информацией(нет уже таких библиотек или приемы уже не используются теперь такие).
Заранее благодарю.
PM MAIL   Вверх
ISergeyN
Дата 27.7.2009, 12:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 11.10.2008
Где: Україна

Репутация: нет
Всего: 2



stuqs, а стандартная документация чем плоха?
PM MAIL Skype   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Программирование игр, графики и искуственного интеллекта"
Rickert

НА ЗЛОБУ ДНЯ: Дорогие посетители, прошу обратить внимание что новые темы касающиеся новых вопросов создаются кнопкой "Новая тема" а не "Ответить"! Любые оффтопиковые вопросы, заданные в текущих тематических темах будут удалены а их авторы, при рецедиве, забанены.

  • Литературу, связанную с программированием графики, обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы связанные с программированием графики и мультимедии на языках С++ и Delphi
  • Вопросы по реализации алгоритмов рассматриваются здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rickert.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Программирование игр, графики и искусственного интеллекта | Следующая тема »


 




[ Время генерации скрипта: 0.1469 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.