C++ 在DirectX9/C+中加载对象网格的纹理坐标+;

C++ 在DirectX9/C+中加载对象网格的纹理坐标+;,c++,directx,texture-mapping,directx-9,C++,Directx,Texture Mapping,Directx 9,我正试图让纹理在我的OBJMesh加载程序上工作。到目前为止,我已经看过一些关于如何做到这一点的在线教程,最明显的例子是我理解的立方体/长方体示例。但我遇到了一个问题,一个顶点可能使用/拥有多个纹理坐标 例如: 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。所以我的问题是如何让它与多个纹理坐标一起工作?是否有某种缓冲区可以使用,比如顶点缓

我正试图让纹理在我的OBJMesh加载程序上工作。到目前为止,我已经看过一些关于如何做到这一点的在线教程,最明显的例子是我理解的立方体/长方体示例。但我遇到了一个问题,一个顶点可能使用/拥有多个纹理坐标

例如:

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而不是顶点声明会更好吗?

对于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;
}
#包括
#包括
#包括
#包括
#包括
struct Vec3f{/*将您喜爱的实现放在这里*/};
struct Vec2f{/*将您喜爱的实现放在这里*/};
//假设您的obj加载为以下向量集:
//顶点将值分开
使用Positions=std::vector;
使用法线=标准::向量;
使用Texcoords=std::vector;
//和面对的信息
结构VertexTriplet{
国际位置;
int_正常;
国际特克斯库尔德大学;
friend布尔运算符<(VertexTriplet常量和a,VertexTriplet常量和b){
返回a.。_位置秒);
}else{//创建新索引
indexBuffer.push_back(自由索引);
重新映射[顶点]=freeIndex++;
}
}
}
//我们现在有了索引缓冲区,我们可以填充顶点缓冲区
//我们首先反转从三元组到索引的映射
//所以wee可以用单调递增的地址填充内存
std::mapreverseRemap;
用于(自动配对:重新映射(&P){
reverseRemap[pair.second]=pair.first;
}
auto&vertexBuffer=result.first;
reserve(reverseRemap.size());
用于(自动配对:反向映射(&P){
自动和三元组=pair.second;
vertexBuffer.push_back(std::make_tuple(位置[triplet.m_pos],法线[triplet.m_normal],texcoords[triplet.m_texcoord]);
}
返回结果;
}
int main(){
//将obj文件读入这四个向量
职位;
法线法线;
特克斯库德;
脸;
/*在这里阅读obj*/
//然后转换
自动gpuObject=转换(位置、法线、纹理坐标、面);
返回0;
}
当然,我们可以想象对索引和顶点缓冲区进行后处理以优化性能。将数据打包为比浮点和无符号更小的类型,优化gpu转换后缓存


使用DX10/11,我们可以想象使用面向量作为顶点缓冲区,为输入布局(顶点声明新名称)提供三个索引,并将位置、法线和texcoords作为缓冲区类型的三着色器资源视图传递给顶点着色器,并直接执行查找。与旧式顶点交错相比,它不应该是次优的,但您应该坚持旧式解决方案。

不,您需要将多个具有相同位置和不同纹理坐标的顶点添加到顶点缓冲区。@NicoSchertler真的没有办法解决这个问题吗?我真的不敢相信directX没有提供解决这个问题的方法……真的没有其他方法。