Разделенный на сегменты буфер вершин
Рисунок 14.1. Разделенный на сегменты буфер вершин
Теперь создайте глобальную переменную i= 0 для отслеживания того, с каким сегментом мы работаем.
Для каждого кадра:
Обновите все частицы.
Пока не будут визуализированы все живые частицы:
Если буфер вершин не заполнен, то:
Блокируем сегмент i с флагом D3DLOCK_NOOVERWRITE.
Копируем 500 частиц в сегмент i.
Если буфер вершин заполнен, то:
Возвращаемся к началу буфера вершин: i = 0.
Блокируем сегмент i с флагом D3DLOCK_DISCARD.
Копируем 500 частиц в сегмент i.
Визуализируем сегмент i.
Переходим к следующему сегменту: i++
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
Данный подход более эффективен. Во-первых, мы сокращаем размер необходимого нам буфера вершин. Во-вторых, теперь центральный процессор и видеокарта работают в унисон; то есть мы копируем небольшую партию частиц в буфер вершин (работа центрального процессора), а затем мы визуализируем эту партию частиц (работа видеокарты). Затем мы копируем в буфер вершин следующую партию частиц и рисуем ее. Это продолжается до тех пор, пока не будут визуализированы все частицы. Как видите, видеокарта больше не простаивает, ожидая пока не будет заполнен весь буфер вершин.
Теперь мы обратим наше внимание на реализацию этой схемы визуализации. Чтобы облегчить визуализацию системы частиц с помощью данной схемы мы будем использовать следующие члены данных класса PSystem:
_vbSize — Количество частиц, которые одновременно могут храниться в нашем буфере вершин. Это значение не зависит от количества частиц в конкретной системе частиц.
_vbOffset — Переменная хранит смещение в буфере вершин (измеряемое в частицах, а не в байтах), начиная с которого мы должны выполнять копирование очередной партии частиц. Например, если первая партия частиц заняла элементы буфера вершин с номерами от 0 до 499, то копирование следующей партии должно начинаться со смещения 500.
_vbBatchSize — Количество частиц в партии.
Теперь мы представим вам код метода визуализации:
void PSystem::render() { if(!_particles.empty()) { // Установка режимов визуализации preRender(); _device->SetTexture(0, _tex); _device->SetFVF(Particle::FVF); _device->SetStreamSource(0, _vb, 0, sizeof(Particle));
// Если мы достигли конца буфера вершин, // возвращаемся к его началу if(_vbOffset >= _vbSize) _vbOffset = 0;
Particle* v = 0;
_vb->Lock( _vbOffset * sizeof(Particle), _vbBatchSize * sizeof(Particle), (void**)&v, _vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
DWORD numParticlesInBatch = 0;
// // Пока все частицы не будут визуализированы // std::list<Attribute>::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { if(i->_isAlive) { // // Копируем партию живых частиц в // очередной сегмент буфера вершин // v->_position = i->_position; v->_color = (D3DCOLOR)i->_color; v++; // следующий элемент;
numParticlesInBatch++; // увеличиваем счетчик партий
// партия полная? if(numParticlesInBatch == _vbBatchSize) { // // Рисуем последнюю партию частиц, которая // была скопирована в буфер вершин. // _vb->Unlock(); _device->DrawPrimitive( D3DPT_POINTLIST, _vbOffset, _vbBatchSize); // // Пока партия рисуется, начинаем заполнять // следующую партию частиц. // // Увеличиваем смещение к началу следующей партии
_vbOffset += _vbBatchSize;
// Проверяем не вышли ли мы за пределы буфера вершин. // Если да, то возвращаемся к началу буфера. if(_vbOffset >= _vbSize) _vbOffset = 0;
_vb->Lock( _vbOffset * sizeof(Particle), _vbBatchSize * sizeof(Particle), (void**)&v, _vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
numParticlesInBatch = 0; // обнуляем количество частиц в партии }//конец инструкции if }//конец инструкции if }//конец инструкции for
_vb->Unlock();
// Возможно, ПОСЛЕДНЯЯ партия частиц начала заполняться, // но не была визуализирована, потому что условие // (numParticlesInBatch == _vbBatchSize) не было выполнено. // Сейчас мы нарисуем эту последнюю частично заполненную партию частиц if( numParticlesInBatch ) { _device->DrawPrimitive( D3DPT_POINTLIST, _vbOffset, numParticlesInBatch); }
// Следующий блок _vbOffset += _vbBatchSize;
postRender(); }//конец инструкции if }// конец метода render()