directx — загрузка текстурных координат для OBJMesh в DirectX9 / Stack Overflow

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

Например:

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

Как вы можете видеть, индексная вершина номер 711 использует координаты текстуры № 1 и 9, а индексная вершина номер 712 использует текстурные координаты № 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;
};

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

Спасибо

РЕДАКТИРОВАТЬ: было бы лучше, если бы я использовал FVF вместо объявлений вершин?

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 мы можем представить себе использование вектора Faces в качестве буфера вершин, обеспечивающего три индекса с входным макетом (новое имя объявления вершины) и передавая позиции, нормали и текстовые координаты как представление трех ресурсов шейдера типа буфера в вершинный шейдер и выполняем поиск напрямую. Он не должен быть настолько неоптимальным по сравнению с чередованием вершин старой школы, но вы должны придерживаться решения старой школы.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]