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

Создание игр » DirectX 9, Featured » Vertex buffer, Index buffer практика

Vertex buffer, Index buffer практика

Vertex buffer Index bufferЧто такое Vertex buffer и Index buffer я рассказал Вам в предыдущей статье. Так же мы рассмотрели в чём преимущества использования Vertex buffer и Index buffer по сравнению с рендерингом обычныых данных, лежащих просто в оперативной памяти. Теперь пришло время на практике разобраться как создавать Vertex buffer, как заполнить его данными, как указать формат этих данных, а так же то, как создать, заполнить и использовать Index buffer для получения наибольшего быстродействия, максимального использования кэша видео-карты, а та же уменьшения количества данных, занимаемых моделью. В принципе, то, что касается уменьшения объёма данных за счёт использования Index buffer, этот вопрос мы с Вами уже рассматривали в уроке Загрузка модели из 3d MAX – в нём мы как раз “оптимизировали” модель за счёт удаления дублирующихся vertex’ов и, тем самым, уменьшили объём памяти, занимаемый моделью. Теперь же давайте на практическом примере рассмотрим как нам сохранить нашу модель в памяти видео-карты и работать с моделью, которая хранится там, а не в обычной оперативной памяти.

Vertex buffer и Index buffer в модели

Добавим Vertex buffer и Index buffer в класс модели, а так же сделаем функции для их получения:

class CMesh
{
	//! вертексы модели
	std::vector<VertPosNormalTc> m_vecVerts;
 
	//! фэйсы. по 3 индекса на каждый Face
	std::vector<WORD> m_vecFaces;
 
	//! Добавляет вертекс в массив и возвращает его индекс
	WORD AddVert(const VertPosNormalTc& vert);
	//! Добавляет вертекс и заносит его индекс в массив индексов
	void AddFaceVert(const VertPosNormalTc& vert);
 
	// index buffer
	LPDIRECT3DINDEXBUFFER9 m_pIB;
	// vertex buffer
	LPDIRECT3DVERTEXBUFFER9 m_pVB;
 
	void Release();
 
protected:
	friend class Graphics;
	LPDIRECT3DINDEXBUFFER9 GetIB() { return m_pIB; }
	LPDIRECT3DVERTEXBUFFER9 GetVB() { return m_pVB; }
 
public:
	const std::vector<VertPosNormalTc>& GetVerts() { return m_vecVerts; }
	const int GetVertsCount() { return int(m_vecVerts.size()); }
	const std::vector<WORD>& GetIdx() { return m_vecFaces; }
	const int GetIdxCount() { return int(m_vecFaces.size()); }
	CMesh(void);
	virtual ~CMesh(void);
	virtual bool Load(const std::string& strFileName);
};

Доработаем функцию загрузки модели, что бы она, при загрузке, создавала Vertex buffer и Index buffer (добавляем в конец функции CMesh::Load ) :

 
	// создаём Vertex Buffer
	m_pVB = Graphics::get().CreateVertexBuffer(
		GetVertsCount()*sizeof(VertPosNormalTc), 
		D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED);
	if (m_pVB==NULL) // если ошибка
		return false;
 
	// создаём Index Buffer
	m_pIB = Graphics::get().CreateIndexBuffer(
		GetIdxCount()*sizeof(WORD), D3DUSAGE_WRITEONLY, 
		D3DFMT_INDEX16, D3DPOOL_MANAGED);
	if (m_pIB==NULL) // если ошибка
	{
		Release();
		return false;
	}
	void* pData;
	if (FAILED(m_pVB->Lock(0, 0, &pData, D3DLOCK_DISCARD)))
	{
		Release();
		return false;
	}
	memcpy(pData, &m_vecVerts[0], GetVertsCount()*sizeof(VertPosNormalTc));
	m_pVB->Unlock();
 
	if (FAILED(m_pIB->Lock(0, 0, &pData, D3DLOCK_DISCARD)))
	{
		Release();
		return false;
	}
	return true;
}

А так же реализуем функцию Release(), которая будет освобождать созданные ранее ресурсы:

void CMesh::Release()
{
	if (m_pVB)
	{
		Graphics::get().Release(m_pVB);
		m_pVB = NULL; 
	}
	if (m_pIB)
	{
		Graphics::get().Release(m_pIB);
		m_pIB = NULL;
	}
}

Для создания и освобождения Vertex buffer и Index buffer нужно будет реализовать дополнительные функции в классе движка:

 
LPDIRECT3DINDEXBUFFER9 Graphics::CreateIndexBuffer(UINT Length, 
	DWORD Usage, D3DFORMAT Format, D3DPOOL Pool)
{
	LPDIRECT3DINDEXBUFFER9 pIB = NULL;
	HRESULT hr = m_pd3dDevice->CreateIndexBuffer(
		Length, Usage, Format, Pool, &pIB, NULL);
	if (FAILED(hr))
		return NULL;
 
	m_vecIB.push_back(pIB);
	return pIB;
}
 
bool Graphics::Release(LPDIRECT3DINDEXBUFFER9 pIB)
{
	for(size_t i=0; i<m_vecIB.size(); i++)
		if (m_vecIB[i]==pIB)
		{
			// нашли VertexBuffer
			std::swap(m_vecIB[i], *m_vecIB.rbegin());
			pIB->Release();
			m_vecIB.pop_back();
			// удалили его
			return true;
		}
	// мы не нашли такого IndexBuffer
	return false;
}
 
 
LPDIRECT3DVERTEXBUFFER9 Graphics::CreateVertexBuffer(UINT Length,
	DWORD Usage, D3DPOOL Pool)
{
	LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL;
	HRESULT hr = m_pd3dDevice->CreateVertexBuffer(
		Length, Usage, 0, Pool, &pVertexBuffer, NULL);
	if (FAILED(hr))
		return NULL;
 
	m_vecVB.push_back(pVertexBuffer);
	return pVertexBuffer;
}
 
bool Graphics::Release(LPDIRECT3DVERTEXBUFFER9 pVB)
{
	for(size_t i=0; i<m_vecVB.size(); i++)
		if (m_vecVB[i]==pVB)
		{
			// нашли VertexBuffer
			std::swap(m_vecVB[i], *m_vecVB.rbegin());
			pVB->Release();
			m_vecVB.pop_back();
			// удалили его
			return true;
		}
	// мы не нашли такого VertexBuffer
	return false;
}

В хидере движка вектора для хранения буферов объявлены вот так:

std::vector<LPDIRECT3DINDEXBUFFER9> m_vecIB;
std::vector<LPDIRECT3DVERTEXBUFFER9> m_vecVB;

Кроме того, меши теперь загружаются так же через движок:

CMeshPtr Graphics::LoadMesh( const std::string& szFileName )
{
	CMeshPtr pMesh = new CMesh();
	if (!pMesh->Load(szFileName))
	{
		delete pMesh;
		return NULL;
	}
	m_vecMeshes.push_back(pMesh);
	return pMesh;
}

Ну и сделал немного косметических правок, что бы было поудобнее работать с движком. В архивах всё есть, посмотрите сами. В этот раз получилось много кода, но мало слов… Вроде бы, комментариев по коду много, да и сам код не сложный – надеюсь, разобраться для Вас проблемы на составит. Если же составит (да и если нет тоже))) – как обычно, жду ваших комментов!

Проект с исходным кодом движка и игры
Демки нет – она внешне от предыдущей ничем не отличается.

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




Раздел: DirectX 9, Featured · Теги: Direct3D, DirectX, Оптимизация, Создание движка

10 комментариев на "Vertex buffer, Index buffer практика"
  1. Antony пишет:

    Вячеслав, поправьте, пожалуйста, ссылку на архив, что-то не работает она :)

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

      Прошу прощения, исправил.

  2. ArchiDevil пишет:

    А по DirectX 11 буферам будет такая же статья?

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

      По DirectX 11 будет – когда найдётся время сделать уроки по этому самому DirectX 11. В данный момент, к сожалению, со временем некоторая напряжёнка :-)

  3. unnamed пишет:

    Вячеслав заметил что тут нет урока по таймерам

    вот на всякий случай код который я склепал

    .h file

    class Timer
    {
    private:
    DWORD startTime;
    DWORD lastTime;
    DWORD updateInterval;
    DWORD currentTime;
    public:
    Timer(DWORD UpdateInterval):updateInterval(UpdateInterval),startTime(timeGetTime())
    {}
    bool UdateTimer();
    };

    .cpp file

    bool Timer::UdateTimer()
    {
    DWORD differentTime = currentTime – lastTime;
    if(differentTime >= updateInterval)
    {
    lastTime = currentTime;
    return true;
    }else
    {
    currentTime = timeGetTime();
    return false;
    }
    return false;
    }

    использовать легко при создании указываешь время обновления и в нужном месте вызываешь UpdateTimer и проверяешь прошёл тот или иной отрезок времени

  4. unnamed пишет:

    работает пока что у меня норм

  5. unnamed пишет:

    и хочеца бы урок по выводу текста(ну когда будет время напишите пожалуйста)

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

      Ок, сделаю такой урок. Спасибо за подсказку.

      1. unnamed пишет:

        ага а то dx учу месяц и по френку луну как то трудновато

  6. Владимир пишет:

    Я не понимаю в твоём примере какую роль играет vector массив вершин и индексов , ты так и не показал как именно удалить нужный мне буфер из контекста устройства, когда ты делаешь pIB->Release(); ты чистишь вообще все буферы. В реальности со сценой где есть разные 3d объекты, ты и я будем создавать буферы для каждого объекта и помещать их в контекст,
    hr = d3d_Устройство->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );
    d3d_cont->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
    так вот мой вопрос как удалять этот буфер для определенного набора точек из контекста, вопрос по DX 11 , но сути не меняет это.

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

*

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