2013-09-02 6 views
0

Я пытаюсь получить текстуры, работающие над моим загрузчиком OBJMesh. До сих пор я изучал некоторые онлайн-учебники о том, как это сделать, и наиболее очевидным примером является пример куба/ящика, который я понял. Но я столкнулся с этой проблемой, когда вершина может использовать/иметь более 1 текстурных коордов.Загрузка текстурных коордов для OBJMesh в DirectX9/C++

Например:

f 711/1/1 712/2/2 709/3/3 
f 711/9/1 704/10/9 712/11/2 

Как вы можете видеть, индекс вершина номер 711 использует текстуры COORDS номер 1 и 9 и индекс вершина номер 712 использует текстуры COORDS номер 2 и 11. Таким образом, мой вопрос заключается в том я могу заставить его работать с несколькими текстурными коордами? Есть ли какой-то буфер, который я могу использовать, например, буфер вершин и буфер индексов?

Я использую индексы для этого и у меня есть следующие объявления вершин:

D3DVERTEXELEMENT9 vertexElement[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, 
             {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, 
             D3DDECL_END()}; 

device->CreateVertexDeclaration(vertexElement, &vertexDec); 

А моя вот моя структура вершины:

struct VERTEX{ 
    D3DXVECTOR3 position; 
    D3DXVECTOR2 uv; 

    D3DCOLOR color; 
}; 

не слишком уверен, что другой код, чтобы показать здесь, но если я отсутствую, или вы, ребята, должны что-то увидеть, чтобы помочь мне, дайте мне знать.

Благодаря

EDIT: было бы лучше, если я использую FVF вместо деклараций вершин?

+0

Нет, вам нужно добавить несколько вершин с одинаковым положением и разными координатами текстуры в буфер вершины. –

+0

@NicoSchertler серьезно не может обойти это? Я действительно не могу поверить, что directX не предлагает что-то, чтобы обойти эту проблему ... – Danny

+0

Нет другого пути. –

ответ

0

С помощью DX9 вам необходимо удалить элементы с разделенными нормальными и текстурными координатами.

Вот пример кода, чтобы сделать это:

#include <array> 
#include <vector> 
#include <utility> 
#include <tuple> 
#include <map> 

struct Vec3f { /* put your beloved implementation here */ }; 
struct Vec2f { /* put your beloved implementation here */ }; 

// imagine your obj loaded as these set of vectors : 

// the vertices separate values 
using Positions = std::vector<Vec3f>; 
using Normals = std::vector<Vec3f>; 
using Texcoords = std::vector<Vec2f>; 

// and faces information 
struct VertexTriplet { 
    int _pos; 
    int _normal; 
    int _texcoord; 
    friend bool operator< (VertexTriplet const & a, VertexTriplet const & b) { 
     return a._pos < b._pos 
       || (a._pos == b._pos && a._normal < b._normal) 
       || (a._pos == b._pos && a._normal == b._normal && a._texcoord < b._texcoord); 
    } 
}; 

using Triangle = std::array<VertexTriplet,3>; 
using Faces = std::vector<Triangle>; 

// imagine your GPU friendly geometry as these two vectors 
using Vertex = std::tuple<Vec3f,Vec3f,Vec2f>; 
using Index = unsigned int; 

using VertexBuffer = std::vector<Vertex>; 
using IndexBuffer = std::vector<Index>; 

using GpuObject = std::pair<VertexBuffer,IndexBuffer>; 
// you can now implement the conversion : 
GpuObject Convert(Positions const & positions, Normals const & normals, Texcoords const & texcoords, Faces const & faces) { 
    GpuObject result; 

    // first, we create unique index for each existing triplet 
    auto & indexBuffer = result.second; 
    indexBuffer.reserve(faces.size() * 3); 

    std::map<VertexTriplet, Index> remap; 
    Index freeIndex = 0; 
    for (auto & triangle : faces) { 
     for (auto & vertex : triangle) { 
      auto it = remap.find(vertex); 
      if (it != remap.end()) { // index already exists 
       indexBuffer.push_back(it->second); 
      } else { // create new index 
       indexBuffer.push_back(freeIndex); 
       remap[vertex] = freeIndex++; 
      } 
     } 
    } 

    // we now have the index buffer, we can fill the vertex buffer 
    // we start by reversing the mapping from triplet to index 
    // so wee can fill the memory with monotonic increasing address 
    std::map< Index, VertexTriplet > reverseRemap; 
    for (auto & pair : remap) { 
     reverseRemap[pair.second] = pair.first; 
    } 

    auto & vertexBuffer = result.first; 
    vertexBuffer.reserve(reverseRemap.size()); 
    for (auto & pair : reverseRemap) { 
     auto & triplet = pair.second; 
     vertexBuffer.push_back(std::make_tuple(positions[triplet.m_pos], normals[triplet.m_normal], texcoords[triplet.m_texcoord])); 
    } 
    return result; 
} 
int main() { 
    // read your obj file into these four vectors 
    Positions positions; 
    Normals normals; 
    Texcoords texcoords; 
    Faces faces; 

    /* read the obj here */ 

    // then convert 
    auto gpuObject = Convert(positions, normals, texcoords, faces); 

    return 0; 
} 

Конечно, мы можем себе представить, постобработку указательного и вершинного буфера для оптимизации производительности. упаковывая данные в меньший тип, чем float и unsigned, оптимизация кеша посттрансформации gpu, ...

С помощью DX10/11 мы можем предположить, что вектор Лица используется как буфер вершин, содержащий три индекса с макетом ввода (объявление вершин новое имя) и передачи позиций, нормалей и texcoords в виде трех шейдерных ресурсов вида буфера в вершинный шейдер и непосредственного выполнения поиска. Он не должен быть настолько субоптимальным по сравнению с чередованием старых школьных вершин, но вы должны придерживаться старого школьного решения.