在DirectX9/C++中为OBJMesh加载纹理坐标
Loading texture coords for OBJMesh in DirectX9/C++
我正试图让纹理在我的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使用纹理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;
};
不太确定还有什么代码可以在这里显示,但如果我遗漏了什么,或者你们需要看到一些帮助我的东西,请告诉我。
感谢
编辑:如果我使用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;
}
当然,我们可以想象对索引和顶点缓冲区进行后处理以优化性能。将数据打包为比浮点和无符号更小的类型,优化gpu后变换缓存。。。
使用DX10/11,我们可以想象使用Faces矢量作为顶点缓冲区,提供具有输入布局的三个索引(顶点声明新名称),并将位置、法线和纹理坐标作为缓冲区类型的三个着色器资源视图传递给顶点着色器,并直接执行查找。与老式的顶点交错相比,它不应该是次优的,但你应该坚持老式的解决方案。
相关文章:
- 在 OpenGL 中加载纹理C++
- 从文件问题加载纹理 Android NDK 和 OpenGL
- 是什么导致 glTexSubImage1D() - 加载纹理时在此示例中出现GL_INVALID_VALUE错误?
- Directx11 加载纹理
- 如何在单独的线程上加载纹理到主内存并使用它在另一个线程上渲染
- 如何加载纹理Opengl
- DirectX9 C++ - 在窗口最小化时加载纹理
- 渲染时加载纹理 (OpenGL)
- 使用 Openscenegraph 加载纹理时出错
- SDL2和GLFW3:加载纹理;违反访问
- 使用opengl和opencv加载纹理
- 加载纹理无法正常工作的功能
- 仅使用 alpha 值加载纹理
- OpenGL 更改/重新加载纹理
- 在DirectX9/C++中为OBJMesh加载纹理坐标
- OpenGL在没有或有静态设备上下文的情况下加载纹理
- 使用 OpenCV 为 OpenGL 加载纹理
- c++ OpenGL/SDL 2.0加载纹理失败
- 我如何使用FreeImage库加载纹理到OpenGL
- 使用SOILs OGL函数和OpenGL加载纹理