Уроки Коммент.

Создание игр » Новости » Создание игры. Графический движок.

Создание игры. Графический движок.

Создание игры. Графический движок.Вообще, тема создания собственного графического движка для игры достаточно больная и давно заезженная. Я решил включить её в уроки на моём блоге, т.к. многие всё равно, так или иначе, возьмутся делать собственный графический движок. Кроме того, это блог в том числе по программированию графики, потому лишним не будет. Ну и, конечно, создание игры, особенно достаточно простой, нередко подразумевает и создание граф. движка, т.к. простой движок создать достаточно не сложно, а времени сэкономить он может кучу.

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

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

  • Что бы весь код инициализации графики был скрыт в самом движке.
  • Что бы движок загружал для нас текстуры и шейдеры
  • Если вдруг произошёл LostDevice (например, такое бывает при запуске скринсейвера или блогкировке компа), что бы движок сам восстанавливал все нужные данные (например, текстуры).
  • Мы хотим одной функцией завершать всю работу с графикой и выгружать все ресурсы

Пока этого хватит.

Итого получается, текстура:

class CTexture
{
	// класс Graphics будет иметь доступ к protected-членам
	friend class Graphics;
 
private:
	//! файл текстуры
	std::wstring m_strTexSrc;
	//! это сама текстура
	LPDIRECT3DTEXTURE9 m_pTex;
 
protected:
	// доступ только для класса Graphics
	CTexture(void);
	~CTexture(void);
	void SetTexture(LPDIRECT3DTEXTURE9 pTex);
	void SetSrc(const std::wstring& src);
	LPDIRECT3DTEXTURE9 GetTexture() const;
public:
	std::wstring GetSrc() const;
};
 
typedef CTexture* CTexturePtr; // тип указателей на текстуру

Шейдеры:

class CShader
{
	friend class Graphics;
 
private:
	//! Это пиксельный шейдер?
	bool m_bIsPS;
	//! Здесь ошибки омпиляции
	LPD3DXBUFFER m_pErrors;
	//! Здесь скопилированый шейдер
	LPD3DXBUFFER m_pShaderBuff;
	//! Таблица констант шейдера
	LPD3DXCONSTANTTABLE m_pConstTable;
	//! вертексный и писельный шейдер. экономим память
	union
	{
		LPDIRECT3DPIXELSHADER9 m_pPixelShader;
		LPDIRECT3DVERTEXSHADER9 m_pVertexShader;
 
	} m_pShader;
 
	//! Девайс, в котором создан шейдер
	LPDIRECT3DDEVICE9 m_pShaderDevice;
 
protected:
	//! Функция загрузки и компиляции шейдера
	HRESULT Load( const std::string& strFileName,
		const std::string& strFuncName, const std::string& profile);
	HRESULT Release();
	//! Получение пиксельного шейдера
	LPDIRECT3DPIXELSHADER9 GetPixelShader();
	//! Поулчение вертексного шейдера
	LPDIRECT3DVERTEXSHADER9 GetVertexShader();
	//! Получение буфера скомпилированого шейдера 
	//! нужно для создания HW-шейдера
	LPD3DXBUFFER GetCompileBuffer();
	//! Установка HW-шейдера (пиксельного)
	void SetHardwareShader(LPDIRECT3DDEVICE9 pDev, 
		LPDIRECT3DPIXELSHADER9 pHWShader);
	//! Установка HW-шейдера (вертексного)
	void SetHardwareShader(LPDIRECT3DDEVICE9 pDev, 
		LPDIRECT3DVERTEXSHADER9 pHWShader);
	CShader(void);
	~CShader(void);
 
public:
	bool IsPS(); // это пиксельный шейдер?
	bool IsVS(); // или это вертексный шейдер?
	//! Функция задания матрицы
	HRESULT SetFloat(D3DXHANDLE hConstant, CONST FLOAT Value);
	HRESULT SetVector(D3DXHANDLE hConstant, CONST D3DXVECTOR4* pVec4);
	HRESULT SetMatrix(D3DXHANDLE hConstant, CONST D3DXMATRIX* pMatrix);
};
 
typedef CShader* CShaderPtr; // тип указателей на текстуру

Кода, вроде, немало, но, мне кажется, всё должно быть понятно из комментариев. Мы вынесли текстуры и шейдеры в отдельные классы, что бы полностью скрыть их реализацию от пользователя движка – так в дальнейшем будет проще программировать. Кроме того, мы сможем не думать о таких вещах, как загружена ли уже нужная нам текстура, что делать при LostDevice и так далее. В общем, просто удобство и, следовательно, скорость программига в будущем.

Теперь сам графический движок:

class Graphics : public singleton<Graphics>
{
	friend class singleton<Graphics>;
private:
	LPDIRECT3D9 m_pD3D;
	LPDIRECT3DDEVICE9 m_pd3dDevice;
 
	// структкура с параметрами девайса
	D3DPRESENT_PARAMETERS m_d3dpp;
 
	typedef std::vector<CTexturePtr> vecTextures;
	vecTextures m_vecTextures;
 
	typedef std::vector<CShaderPtr> vecShaders;
	vecShaders m_vecShaders;
 
protected:
	Graphics(void);
	~Graphics(void);
	LPDIRECT3DDEVICE9 GetDevice();
 
public:
	bool Init(HWND hRenderWnd, int width, int height);
	void Cleanup();
	HRESULT Reset();
	bool StartRender();
 
	HRESULT SetFVF(DWORD FVF);
	HRESULT SetPixelShader(CShaderPtr shader);
	HRESULT SetVertexShader(CShaderPtr shader);
	HRESULT SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
	HRESULT SetSamplerState(DWORD Sampler, 
		D3DSAMPLERSTATETYPE Type, DWORD Value);
	HRESULT SetTexture(DWORD stage, CTexturePtr pTex);
	HRESULT DPUP( D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, 
		CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
	//! Функция отрисовки спрайта в заданных координатах\
	и с заданными размерами
	HRESULT DrawSprite(CTexturePtr pTex, D3DXVECTOR2 pos, D3DXVECTOR2 size);
 
	bool EndRender();
	CTexturePtr LoadTexture(const std::wstring& szFileName);
	CShaderPtr LoadShader( const std::string& strFileName, 
		const std::string& strFuncName, const std::string& profile);
};

Для начала нам этого хватит. Конечно, этот получился очень примитивный движок – в нём нет умных указателей, счётчиков ссылок, нет приоритетов ресурсов, нет многопоточности, нет даже элементарной возможности выгрузить уже не нужную текстуру. Но нам это сейчас и не нужно. В следующих уроках мы будем постепенно наращивать возможности и, со временем, получим достаточно универсальный и удобный движок. Текущих же возможностей нам вполне хватит для создания несложных игр. А это, согласитесь, уже немало, учитывая, что на всё про всё мы потратили всего полчаса работы…

P/S Исходики к статье будут в следующем уроке, где мы сделаем летающий корабль игрока.

Ещё по этой теме:




Раздел: Новости

12 комментариев на "Создание игры. Графический движок."
  1. Scripter пишет:

    супер :)

  2. Antony пишет:

    Вопрос по коду, в цикле, где обрабатываются windows message и код игры, мы каждый кадр заново устанавливаем все матрицы, рендер стейты и прочее.
    А почему нельзя это выставить один раз перед тем, как войти в цикл?

    1. Вячеслав пишет:

      Antony, вынести это всё можно и вызывать однократно тоже можно. Но:
      1) в реальной боле-мене сложной игре это скорее всего не получится, т.к. там куча изменений стейтов и матриц во время рендера каждого кадра
      2) если таким образом вы надеетесь “прооптимизировать” программу – не стоит, толку (буста) от этого не будет

  3. Даниил пишет:

    А можно написать в какой очереди их читать а то как то непонятно где 1 урок, а где 2

    1. Вячеслав пишет:

      Читать просто от старых уроков к новым. Справа в меню есть так же “Уроки DirectX” и “Уроки создания игр” – там последовательность чтения указана.

  4. Даниил пишет:

    спасибо ещё 1 вопросик wstring это какой файл подключать?

  5. Danil пишет:

    опечатка в комментарии

    class CShader
    {
    friend class Graphics;

    private:
    //! Это пиксельный шейдер?
    bool m_bIsPS;
    //! Здесь ошибки омпиляции
    LPD3DXBUFFER m_pErrors;

  6. Виктор пишет:

    А в какой проге то работать??
    Ну всмысле куда это все всавлять что бы работало?

  7. николай пишет:

    ДА А ВОТ КУДА ПИСАТЬ КОД ЭТОТ????????????????7

  8. Анатолий пишет:

    Писать код можно в Microsoft Visual Studio, предварительно поставив DirectX SDK, чтобы подцепить нужные заголовочные файлы.
    Посты хороши, но для новичка, как я, тяжеловато! Спасибо за пост…
    Учение – свет, не учение – 0x00000000

    1. Анатолий пишет:

      P.S. почему-то не запускается Tutorial.exe из примера. А так же он отказывается компилироваться. Быть может я упустил какой-то момент? Как из примера, получить скомпилированный исполняемый файл?

  9. TriGlav пишет:

    Немного сложновато для новичка типа меня, но буду пробовать…
    Спасибо за статью!

Оставить комментарий

*

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>