Войти
Уголок tool-программСтатьи

Универсальный способ сборки VertexBuffer'а при экспорте без дублирования вершин

Автор:

Обычная сложность на этапе экспорта/загрузки модели – это сборка правильного вершинного и индексного буфера, потому как, обычно:
количество позиций (вертексов) != количеству нормалей != количеству текстурных координат (а если каналов еще несколько?) и тд.

Этот способ универсален и позволяет собрать правильный Vertex и Index Buffer только из абсолютно уникальных вершин модели.

Недостатком является, его медленная скорость работы на highpoly моделях, потому лучше  выполнять сборку на этапе экспорта или подготовки модели.

////file : indexator.h
#pragma once

#include <vector>
#include <map>
#include <assert.h>
template<class VERTEX>
class CIndexator
{
  typedef std::map<VERTEX, unsigned int> VertSet;
  VertSet m_Vertexs;
  unsigned int m_uiIndex;

public:
  CIndexator():m_uiIndex(0){}
  ~CIndexator(){}

  unsigned int PushVertex(const VERTEX &v);
  unsigned int GetIndex(const VERTEX &v) const;

  void GetVertices(std::vector<VERTEX> &) const;
};

Псевдокод для работы с классом:

//наш вертекс 
struct vertex
{
  enum{ELEMENTS = 8};//8 = 3 позиции + 3 нормали + 2 текст. координаты
  union
  {
    struct 
    {
      float px, py, pz;//позиции 
      float nx, ny, nz;//нормали
      float s, t;//текст. координаты
    };
    float v[ELEMENTS];
  };
/*добавить в него можно что угодно, 
но не забываем про  bool operator < (const vertex &r) const */

/*оператор "bool operator < (const vertex &r) const ", необходим для работы с std::map, 
тут мы сравниваем 2 вертекса, для корректной вставки в дерево*/
  bool operator < (const vertex &r) const 
  {
    for (int i=0; i < vertex::ELEMENTS; ++i)
    {
      if (v[i]!=r.v[i]) //при необходимости, можно добавить EPSILON
        return v[i] < r.v[i];      
    }
    return false;    
  }
};

//////////////////////
vertex GetVertexFromModel(int triangle, int v)
{
  vertex v;
...........................
//заполняем вертекс
  return v;
}

CIndexator<vertex> indexator;

std::vector<unsigned int> myIB;//здесь будет конечный Index Buffer
std::vector<vertex> myVB;//здесь будет конечный Vertex Buffer

for (int t = 0; t < triangles_count; ++t)
{
  for (int v=0; v<3; ++v)
  {
    //получаем вертекс для данного треугольника и его номера вершины
    vertex vert = GetVertexFromModel(t, v);
    unsigned int index = indexator.PushVertex(vert);
    myIB.push_back (index);
  }
}

indexator.GetVertices(myVB);
//уникальный VB готов (myVB)
//индексы для него готовы (myIB)

Продолжение файла indexator.h

//file:indexator.h

template<class VERTEX>
unsigned int CIndexator<VERTEX>::PushVertex(const VERTEX &v)
{
  VertSet::iterator i = m_Vertexs.find(v);
  if (i==m_Vertexs.end())//не нашли вершину
  {
    unsigned int index = m_uiIndex++;
    m_Vertexs[v] = index;
    return index;
  }
  return i->second;
}

template<class VERTEX>
unsigned int CIndexator<VERTEX>::GetIndex(const VERTEX &v) const
{
  VertSet::const_iterator i = m_Vertexs.find(v);
  if (i!=m_Vertexs.end())  
    return i->second;  
  assert(!"can't find vertex!");
  return 0;
}

template<class VERTEX>
void CIndexator<VERTEX>::GetVertices(std::vector<VERTEX> &vSorted) const
{
  vSorted.resize(m_Vertexs.size());
  for (VertSet::const_iterator i=m_Vertexs.begin(); i!=m_Vertexs.end(); ++i)
  {
    unsigned int ind = i->second;
    vSorted[ind] = i->first;
  }
}

9 февраля 2007 (Обновление: 15 фев. 2007)

Комментарии [16]