Войти
ПрограммированиеФорумГрафика

Мешем единым. ID3DXMesh + ID3DXMesh + ... + n [РЕШЕНО]

Страницы: 1 2 Следующая »
#0
1:46, 8 окт. 2013

Здравствуйте.
Недавно открыл для себя такую особенность DirectX/Видеокарты что скорость отрисовки гасит больше всего даже не количество треугольников в сцене, а количество
сеток (точнее колич. вызывов ID3DXMesh::DrawSubset за один кадр). Кому то вероятно смешно, но для меня это было открытием. На картинке первое приближение того что хочу реализовать.
12000 треугольников | Мешем единым. ID3DXMesh + ID3DXMesh + ... + n [РЕШЕНО]
Это сцена из редактора, ~12000 треугольников всего 69 объектов(сеток). Всё это добро экспортировано в один "*.x" файл и при рендере - пробуксовки. Приложение работает с максимальной скоростью FPS не ограничиваю. Затем в редакторе взял да и обьединил все сетки в одну - результат поразил скоростью.
В сетке получилось 12 подгруп == 12 материалов, получается ID3DXMesh::DrawSubset(0...11).
Если не трудно ответьте как послать на отрисовку несколько сеток за один раз?

Читал Ф.Луна про частицы и пока додумался до такой схемы:
1. Получить вершинные буферы всех сеток и считать данные вершин.
2. Создать новый вершинный буфер достаточного размера.
3. Записать данные вершин из [1] в новый буфер.
4. device->DrawPrimitive(...).
Да не тут то было...
Сейчас борюсь с индексным буфером. Как?! Например есть квадрат(в верш. буф.), записываю в вершинный буфер новые вершины(новый квадрат) позиция которых по х смещена допустим на 20.0f от вершин первого квадрата. Теперь в буфере два квадрата на растоянии друг от друга. Но как поступать с индексами? Просто увеличение индексов новых вершин на единицу не даёт результата.


#1
1:53, 8 окт. 2013

Жаберштуцер
12к поликов - это фигня - там не чему тормозить.
11 дравколов - тоже фигня.

Советую юзать профайлер для точного определения места "где тормозит". Я юзаю CodeAnalyst - пока доволен.

Жаберштуцер
> Но как поступать с индексами? Просто увеличение индексов новых вершин на
> единицу не даёт результата.
Естественно. Индексов для одного квадрата должно быть 6. Для двух - 12.

Ванга mode : может ты что-то грузишь каждый кадр? Текстуры или модели?

#2
7:46, 8 окт. 2013

Жаберштуцер
> Просто увеличение индексов новых вершин на единицу не даёт результата.
На количество уже записанных вершин надо
Индекс - это номер вершины в последовательности вершин, лежащих в вершинном буфере. В индексном буфере лежат индексы вершин так, что три идущие подряд индекса используются directx-ом для получения пор. номеров вершин в вершинном буфере и вывода треугольника. В индексном буфере могут лежать одинаковые числа, так как одна и таже вершина может учавствовать в создании нескольких треугольников.
Допустим у тебя меш в 8 вершин и 12 треугольников (куб). Записав вершины в вершинный буфер, получишь:
0  1  2  3  4  5  6  7
v0 v1 v2 v3 v4 v5 v6 v7
Записываем индексы:
0,1,2,  3,4,5  6,7,8  9,10,11,  12,13,14,  15,16,17,  18,19,20,  21,22,23,  24,25,26,  27,28,29,  30,31,32,  33,34,35  <-пор. номера индексов в индекс. буфере
0 1 2  0 2 3  1 5 2  2 5 6      2 6 3      3 6 7        7 6 5        7 5 4        4 5 0      0 5 1        0 3 7        0 7 4        <-значения индексов (пор. ном. вершин в вер.буфере)
Получается, чтобы добавить еще один меш куба, вершины нужно записать, начиная с 8-й позиции (8 * размер вершины в байтах).
Значения индексов пишутся, начиная с 36 позиции (36 * размер индекса в байтах), а значения индексов рассчитываются по формуле:
новые значения = старые значения + 8.

Вершинный буфер:
Меш1                            Меш2
0  1  2  3  4  5  6  7      8  9  10  11  12  13  14  15
v0 v1 v2 v3 v4 v5 v6 v7    v0 v1  v2  v3  v4  v5  v6  v7


Короче если у тебя уже записано в вершинный буфер Nv вершин и ты записываешь туда еще один меш, то значения каждого его индекса при записи в индексный буфер сложи с Nv. Но вроде, в 9-й версии есть дополнительное поле для смещения в DrawIndexedPrimitive. Это я привел скорее для понимания и это характерно для восьмой версии или если в 9-й ты не будешь пользоваться дополнительным полем для смещения в дипах.
Если что, то копирование 500 000 вершин за цикл  тоже может вызвать тормоза. Я к тому, что можно создать буфер на 8000 вершин к примеру и залить в него вершины нескольких мешей (или нескольких десятков/сотен в зависимости от сложности меша), пересчитать индексы и тоже залить их в индексный буфер (большой). Но сама эта операция копирования тоже жрет немало времени. Лучше делать тесты в любом случае.
Я как то у себя через memcpy копировал просто данные из памяти в память. После 500 000 начинало тормозить. Может я и ошибся где-то.

#3
8:29, 8 окт. 2013

fzr125
> 11 дравколов - тоже фигня.
DrawSubset - это не только DrawIndexedPrimitive, но ещё и куча стейтов.

#4
11:04, 8 окт. 2013

Попробуй заюзать ID3DXMesh::Optimize, может помочь.

Mikle
> DrawSubset - это не только DrawIndexedPrimitive, но ещё и куча стейтов.
Да разве? Насколько я помню - SetStreamSource, SetIndices и потом DP/DIP.

http://msdn.microsoft.com/en-us/library/windows/desktop/bb205736%… vs.85%29.aspx

Автор, пройдись PIXом по своей проге и посмотри где bottleneck.

И вообще, покажи функцию отрисовки. Может ты материал устанавливаешь перед каждым DrawSubset или каждый раз создаешь новый материал. Да мало ли.

#5
11:39, 8 окт. 2013

Shockwave
> Да разве? Насколько я помню - SetStreamSource, SetIndices и потом DP/DIP.
SetStreamSource, SetIndices - уже две добавки. В DX8 ещё было, как минимум, SetVertexShader, в DX9 - не знаю, не пользовался мешами.

Я написал "куча стейтов", а имел ввиду "куча сетов".

#6
16:03, 8 окт. 2013

Я наверное слишком размыто написал в теме. Короче когда у меня одна сетка (вся сцена: дом, деревья и т.д.)  12 подгруп == 12 материалов то всё просто замечательно скорость такая что грех жаловаться =). Но. Но когда сцена состоит из отдельных сеток и функция D3DXLoadMeshFromX объединяет их в одну
то по ходу дела получается  (количество подгруп) == (количество объектов в сцене).

Я нашёл простую альтернативу этим буферам: функция D3DXConcatenateMeshes.
Наткнулся на эти зацепки для размышления
использование
дальнейшее действие
не берите эти темы на веру - это всего лишь зацепки.

А вот готовый продукт, что у меня вышло[всё работает]:

// Обьединение сеток в одну
void CreateMeshMesh(ID3DXMesh*& out, ID3DXMesh* in1, ID3DXMesh* in2)
{
  
  DWORD countFaces = in1->GetNumFaces() + in2->GetNumFaces();
  DWORD countVerices = in1->GetNumVertices() + in2->GetNumVertices();
  DWORD FLV = in1->GetFVF();
  //D3DVERTEXELEMENT9  decl[MAX_FVF_DECL_SIZE];
  //D3DXDeclaratorFromFVF(FLV, decl);

  ID3DXMesh* massIn[2] = {in1, in2};

  D3DXCreateMeshFVF(countFaces, countVerices, D3DXMESH_DYNAMIC | D3DXMESH_WRITEONLY, FLV, dx::GetDevice(), &out);
  D3DXConcatenateMeshes(massIn, 2, D3DXMESH_SYSTEMMEM, NULL, NULL, NULL, dx::GetDevice(), &out);
}
А вот у меня вышло наподобии частиц только сетки[всё работает]:
// Размножение сетки, финал: единая сетка.
ID3DXMesh* CreateMultiMesh(ID3DXMesh* base, D3DXVECTOR3* pos, UINT countPos)
{
  // Тут просто
  D3DXMATRIX *meshMassPos = new D3DXMATRIX[countPos];
  for(UINT i = 0; i < countPos; i++)
  {
    D3DXMatrixIdentity(&meshMassPos[i]);
    D3DXMatrixTranslation(&meshMassPos[i], pos[i].x, pos[i].y, pos[i].z);
  }

  // Ближе к делу
  DWORD countFaces = base->GetNumFaces() * countPos;
  DWORD countVerices = base->GetNumVertices() * countPos;
  DWORD FLV = base->GetFVF();
  ID3DXMesh* out = NULL;
  D3DXCreateMeshFVF(countFaces, countVerices, D3DXMESH_DYNAMIC | D3DXMESH_WRITEONLY, FLV, dx::GetDevice(), &out);
  
  // Ещё ближе
  ID3DXMesh** massMesh = new ID3DXMesh*[countPos];
  for(UINT n = 0; n < countPos; n++)
    massMesh[n] = base;
  D3DXConcatenateMeshes(massMesh, countPos, D3DXMESH_SYSTEMMEM, meshMassPos, NULL, NULL, dx::GetDevice(), &out);
  delete massMesh;
  delete meshMassPos;

  // [Вот она, вот она рыба моей мечты Я-Я-Я-Я-ЗЬ!!!]
  // Здесь происходит обьединение подгруп полигонов в одну
  // Результат - единая сетка. DrawSubset(N) отменяется - теперь только DrawSubset(0).
  CreateBigMesh(out);
  return out;
}

// Обьединение всех подгруп полигонов в одну
void CreateBigMesh(ID3DXMesh*& in_out)
{
  DWORD countPoligon = in_out->GetNumFaces();
  DWORD *mass_IDpoligon = NULL;
  
  in_out->LockAttributeBuffer(D3DLOCK_DISCARD, &mass_IDpoligon);
  for(DWORD n = 0; n < countPoligon; n++) mass_IDpoligon[n] = 0;
  in_out->UnlockAttributeBuffer();
}

Вот думаю, если слово Create в названии этих функций заменю на Draw и добавлю соответствующий код... Как бы боком мне это не вышло.
В любом случае я ещё раз перечитаю что вы мне ответили и попытаюсь добить всё таки первый вариант решения проблемы.
Кстати спасибо что не прошли стороной мою тему.

#7
16:11, 8 окт. 2013

Жаберштуцер
D3DX - шлак. Сожги эту гадость из огнемета.

#8
16:32, 8 окт. 2013

-Eugene-
> D3DX - шлак. Сожги эту гадость из огнемета.
Как шлак? Почему шлак? Наверное потому что приносишь своё приложение к другу запускаешь а оно тебе БАЦ! на "Библиотека d3dx9_43.dll не найдена". =)

#9
16:53, 8 окт. 2013

Жаберштуцер
Это лишь одна из причин.
1. Эта библиотека настолько шлак, что даже сам МС выкинул ее из последующих ДХ-ов, больше или меньше
2. Стремные интерфейы - я не хочу, чтобы у меня из разных мест кода торчали щупальца ID3DX-классов.
Математика - самая адская часть. Это просто невообразимо уродливо.
3. Мутная логика работы - никогда не знаешь, какую хрень оно творит внутри

#10
17:21, 8 окт. 2013

-Eugene-
> Математика - самая адская часть. Это просто невообразимо уродливо.

Знал бы ты как использовали её в зашипленных ...

#11
17:29, 8 окт. 2013

innuendo
Вгде?

#12
17:55, 8 окт. 2013

-Eugene-
> Вгде?

Военная тайна :) Но такие есть

#13
18:36, 8 окт. 2013

Жаберштуцер
> думаю, если слово Create в названии этих функций заменю на Draw и добавлю соответствующий код...
Вот это основная причина тормозов. Судя по всему, у ТС загрузка идет каждый кадр. Где код, собственно, рисования?

#14
19:56, 8 окт. 2013

}:+()___ [Smile]
Да что ж это такое, ёмаё да я что не в своём уме что ли загружать что-то в такой ответственный момент как рисование.
Привожу старый так сказать канонический  код отрисовки сетки, при котором были тормоза порядка 3 кадра в секунду:

  void DrawMesh(ID3DXMesh* m)
  {
    DWORD i = 0;
    DWORD siz = allMesh.size();
    for(; i < siz; i++)
      if(allMesh[i].mesh == m)
        break;
    for(DWORD j = 0; j < allMesh[i].numMat; j++)
    {
      dx::pDevice->SetMaterial(&allMesh[i].mat[j]);
      m->DrawSubset(j);
    }
  }
allMesh это глобальный std::vector структуры "Сетки"
struct structMesh
{
  ID3DXMesh* mesh;
  DWORD numMat;
  D3DMATERIAL9* mat;
  structMesh(){mesh = NULL; mat = NULL; numMat = 0;}
  ~structMesh() { if(mat){delete mat; mat = NULL;} }
  structMesh(const structMesh& s)
  {
    mesh  = NULL;
    numMat  = 0;
    mat    = NULL;

    if(&s != this)
    {
      mesh = s.mesh;
      numMat = s.numMat;
      mat = new D3DMATERIAL9[numMat];
      CopyMemory(mat, s.mat, sizeof(D3DMATERIAL9) * numMat);
    }
  }
};

std::vector<structMesh> allMesh;

Без конструктора копий здесь ну просто не обойтись. DrawMesh и allMesh находятся в дежурной библиотеки которая всегда наподхвате когда есть
настроение поработать с графикой но не хочется каждый раз создавать ни окно, ни оно =) А сразу получить готовенький LPDIRECT3DDEVICE9 и простой
наборчик часто применяемых штучек.

Рисование это главная функция:

int Pr()
{
  static float cameraPOS_X = 0.0f;
  static float cameraPOS_Z = -2500.0f;
  static float cameraPOS_Y = 600.0f;
  static float cameraROT_Y = 0.0f;
  if( ::GetAsyncKeyState(VK_LEFT) ) cameraROT_Y -= 3.0f;
  if( ::GetAsyncKeyState(VK_RIGHT) ) cameraROT_Y += 3.0f;

  cameraPOS_Z += 1.0f;

  dx::RotationCamera(0.0f, cameraROT_Y, 0.0f);
  dx::PositionCamera(cameraPOS_X, cameraPOS_Y, cameraPOS_Z);


  dx::GetDevice()->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0);
  dx::GetDevice()->BeginScene();

  // Здесь прорисовка
  
  dx::DrawMesh(scene);
  dx::DrawMesh(scene);

  dx::GetDevice()->EndScene();
  dx::GetDevice()->Present(NULL, NULL, NULL, NULL);

  // Выход
  if( ::GetAsyncKeyState(VK_ESCAPE) ) return 0;
  return 1;
}
Всё по стандартной схеме. Блин вы недопоняли в чём причина тормозов то была.

Страницы: 1 2 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.