gpt4 book ai didi

c++ - 如何根据 Wavefront (.obj) 文件中给定的纹理索引对纹理位置进行排序?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:27:45 28 4
gpt4 key购买 nike

我目前正在尝试为 OpenGL 项目制作 Wavefront (.obj) 文件加载器。我目前使用的方法是逐行分离 vector (std::vectors) 中的顶点位置、纹理位置和法线位置,我将它们的索引(顶点、纹理和法线索引)存储在三个单独的位置 vector (来自文件的“f”行,对于每张脸)。

我无法根据纹理索引对充满纹理坐标的 vector 进行排序。我能够在正确的位置渲染顶点,因为我的“加载器”类需要索引,但我无法弄清楚如何以任何方式对纹理坐标进行排序,因此纹理在某些三角形上看起来偏移为结果。

带有偏移纹理的立方体图像:

img

纹理图像 (.png),它应该如何出现在每个面上:

img

编辑:这是 .obj 文件和 .mtl 文件的链接。 Google Drive.

这是我的 OBJLoader.cpp 文件:

    rawObj.open(filePath); // Open file

while (!rawObj.eof()) {
getline(rawObj, line); // Read line

// Read values from each line
// starting with a 'v' for
// the vertex positions with
// a custom function (gets the word in a line
// at position i)

if (strWord(line, 1) == "v") {
for (int i = 2; i <= 4; i++) {
std::string temp;
temp = strWord(line, i);
vertexStrings.push_back(temp);
}

// Same for texture positions

} else if (strWord(line, 1) == "vt") {
for (int i = 2; i <= 3; i++) {
std::string temp;
temp = strWord(line, i);
textureStrings.push_back(temp);
}

// Same for normal positions

} else if (strWord(line, 1) == "vn") { // normals
for (int i = 2; i <= 4; i++) {
std::string temp;
temp = strWord(line, i);
normalStrings.push_back(temp);
}

// Separate each of the three vertices and then separate
// each vertex into its vertex index, texture index and
// normal index

} else if (strWord(line, 1) == "f") { // faces (indices)
std::string temp;

for (int i = 2; i <= 4; i++) {
temp = strWord(line, i);
chunks.push_back(temp);

k = std::stoi(strFaces(temp, 1));
vertexIndices.push_back(k-1);

l = std::stoi(strFaces(temp, 2));
textureIndices.push_back(l-1);

m = std::stoi(strFaces(temp, 3));
normalIndices.push_back(m-1);

}

}
}

// Convert from string to float

for (auto &s : vertexStrings) {
std::stringstream parser(s);
float x = 0;

parser >> x;

vertices.push_back(x);
}

for (auto &s : textureStrings) {
std::stringstream parser(s);
float x = 0;

parser >> x;

texCoords.push_back(x);
}

// Y coords are from top left instead of bottom left
for (int i = 0; i < texCoords.size(); i++) {
if (i % 2 != 0)
texCoords[i] = 1 - texCoords[i];
}

// Passes vertex positions, vertex indices and texture coordinates
// to loader class
return loader.loadToVao(vertices, vertexIndices, texCoords);
}

我试过在循环中插入来自 texCoords[textureIndices[i]] 的值 (vector.insert),但这没有用,使输出更糟。我尝试了一个简单的:

tempVec[i] = texCoords[textureIndices[i]] 

在 for 循环中,但这也不起作用。

我检查了整个项目并确定排序是问题的原因,因为当我为立方体插入硬编码值时,它工作得很好并且纹理根本没有偏移。 (OpenGL 命令/图像加载器正常工作。)

最后,是否有另一种方法可以根据 textureIndices 对 texCoords 进行排序?

最佳答案

如果顶点坐标和纹理坐标有不同的索引,那么顶点位置一定是“重复的”。
顶点坐标及其属性(如纹理坐标)形成一个元组。每个顶点坐标必须有自己的纹理坐标和属性。您可以将 3D 顶点坐标和 2D 纹理坐标视为单个 5D 坐标。
See Rendering meshes with multiple indices .

假设您有一个像这样的 .obj 文件:

v -1 -1 -1
v 1 -1 -1
v -1 1 -1
v 1 1 -1
v -1 -1 1
v 1 -1 1
v -1 1 1
v 1 1 1

vt 0 0
vt 0 1
vt 1 0
vt 1 1

vn -1 0 0
vn 0 -1 0
vn 0 0 -1
vn 1 0 0
vn 0 1 0
vn 0 0 1

f 3/1/1 1/2/1 5/4/1 7/3/1
f 1/1/2 2/2/2 3/4/2 6/3/2
f 3/1/3 4/2/3 2/4/3 1/3/3
f 2/1/4 4/2/4 8/4/4 6/3/4
f 4/1/5 3/2/5 7/4/5 8/3/5
f 5/1/6 6/2/6 8/4/6 7/3/6

从这里你必须找到顶点坐标、纹理纹理坐标和法 vector 索引的所有组合,这些组合用于面部规范:

 0 : 3/1/1 
1 : 1/2/1
2 : 5/4/1
3 : 7/3/1
4 : 1/1/2
5 : 2/2/2
6 : 3/4/2
7 : 6/3/2
8 : ...

然后你必须创建一个对应索引组合数组的顶点坐标、纹理坐标和法 vector 数组。顶点坐标及其属性既可以组合在一个数组中作为数据集,也可以组合成三个具有相同数量属性的数组:

 index   vx vy vz     u v     nx ny nz
0 : -1 1 -1 0 0 -1 0 0
1 : -1 -1 -1 0 1 -1 0 0
2 : -1 -1 1 1 1 -1 0 0
3 : -1 1 1 1 0 -1 0 0
4 : -1 -1 -1 0 0 0 -1 0
5 : 1 -1 -1 0 1 0 -1 0
6 : -1 1 -1 1 1 0 -1 0
7 : 1 -1 1 1 0 0 -1 0
8 : ...

查看非常简单的 c++ 函数,它可以读取 .obj 文件,就像您链接到的那样。该函数读取文件并将数据写入元素 vector 和属性 vector 。

注意,函数可以优化,不关心性能。对于小文件(比如您喜欢的 cube3.obj),这无关紧要,但对于大文件,特别是索引表中的线性搜索,将不得不改进。

我只是想告诉您如何读取 .obj 文件以及如何创建元素和属性 vector ,这些元素和属性 vector 可以直接用于通过 OpenGL 绘制网格。

#include <vector>
#include <array>
#include <string>
#include <fstream>
#include <strstream>
#include <algorithm>

bool load_obj(
const std::string filename,
std::vector<unsigned int> &elements,
std::vector<float> &attributes )
{
std::ifstream obj_stream( filename, std::ios::in );
if( !obj_stream )
return false;

// parse the file, line by line
static const std::string white_space = " \t\n\r";
std::string token, indices, index;
float value;
std::vector<float> v, vt, vn;
std::vector<std::array<unsigned int, 3>> f;
for( std::string line; std::getline( obj_stream, line ); )
{
// find first non whispce characterr in line
size_t start = line.find_first_not_of( white_space );
if ( start == std::string::npos )
continue;

// read the first token
std::istringstream line_stream( line.substr(start) );
line_stream.exceptions( 0 );
line_stream >> token;

// ignore comment lines
if ( token[0] == '#' )
continue;

// read the line
if ( token == "v" ) // read vertex coordinate
{
while ( line_stream >> value )
v.push_back( value );
}
else if ( token == "vt" ) // read normal_vectors
{
while ( line_stream >> value )
vt.push_back( value );
}
else if ( token == "vn" ) // read normal_vectors
{
while ( line_stream >> value )
vn.push_back( value );
}
else if ( token == "f" )
{
// read faces
while( line_stream >> indices )
{
std::array<unsigned int, 3> f3{ 0, 0, 0 };
// parse indices
for ( int j=0; j<3; ++ j )
{
auto slash = indices.find( "/" );
f3[j] = std::stoi(indices.substr(0, slash), nullptr, 10);
if ( slash == std::string::npos )
break;
indices.erase(0, slash + 1);
}

// add index
auto it = std::find( f.begin(), f.end(), f3 );
elements.push_back( (unsigned int)(it - f.begin()) );
if ( it == f.end() )
f.push_back( f3 );
}
}
}

// create array of attributes from the face indices
for ( auto f3 : f )
{
if ( f3[0] > 0 )
{
auto iv = (f3[0] - 1) * 3;
attributes.insert( attributes.end(), v.begin() + iv, v.begin() + iv + 3 );
}

if ( f3[1] > 0 )
{
auto ivt = (f3[1] - 1) * 2;
attributes.insert( attributes.end(), vt.begin() + ivt, vt.begin() + ivt + 2 );
}

if ( f3[2] > 0 )
{
auto ivn = (f3[2] - 1) * 3;
attributes.insert( attributes.end(), vn.begin() + ivn, vn.begin() + ivn + 3 );
}
}

return true;
}

关于c++ - 如何根据 Wavefront (.obj) 文件中给定的纹理索引对纹理位置进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51708275/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com