Assimp 错误的纹理数组
Assimp wrong texture array
我实际上正在编写一个烘焙法线贴图的工具。
所以我有一个功能,必须采用 3D 对象,并将每个顶点的法向量投影到纹理上。
我目前正在使用 Assimp 库导入 .obj 模型,我以前从未遇到过这个问题...
这是导入网格的函数:
std::vector<Object3D> Loader::load(const char* file){
Assimp::Importer importer ;
const aiScene *modelScene = importer.ReadFile(file , aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices
| aiProcess_FlipUVs) ;
if(modelScene != nullptr)
{
std::vector<Object3D> objects;
for(int i = 0 ; i < modelScene->mNumMeshes ; i++){
const aiMesh* mesh = modelScene->mMeshes[i] ;
Object3D object ;
assert(mesh->HasTextureCoords(0) ) ;
for(int f = 0 ; f < mesh->mNumVertices ; f++){
const aiVector3D* vert = &(mesh->mVertices[f]) ;
const aiVector3D* norm = &(mesh->mNormals[f]) ;
const aiVector3D* tex = &(mesh->mTextureCoords[0][f]) ;
object.vertices.push_back(vert->x);
object.vertices.push_back(vert->y);
object.vertices.push_back(vert->z);
object.uv.push_back(tex->x) ;
object.uv.push_back(tex->y) ;
object.normals.push_back(norm->x) ;
object.normals.push_back(norm->y) ;
object.normals.push_back(norm->z) ;
}
for(int ind = 0 ; ind < mesh->mNumFaces ; ind++){
assert(mesh->mFaces[ind].mNumIndices==3) ;
object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[0]));
object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[1]));
object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[2]));
}
std::cout << "object loaded : " << mesh->mName.C_Str()<< "\n" ;
objects.push_back(object) ;
}
return objects ;
}
else
{
std::cout << "Problem loading scene" << std::endl ;
return std::vector<Object3D>() ;
}
}
它将一个场景分割成多个网格,returns它们的顶点、UV、法线和索引。
然后,我将其发送到此函数:
SDL_Surface* ImageManager::project_uv_normals(Object3D object , int width , int height){
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
Uint32 rmask = 0xFF000000 ;
Uint32 gmask = 0x00FF0000 ;
Uint32 bmask = 0x0000FF00 ;
Uint32 amask = 0x000000FF ;
#else
Uint32 amask = 0xFF000000 ;
Uint32 bmask = 0x00FF0000 ;
Uint32 gmask = 0x0000FF00 ;
Uint32 rmask = 0x000000FF ;
#endif
SDL_Surface* surf = SDL_CreateRGBSurface(0 , width , height , 24 , rmask , gmask , bmask , amask) ;
assert(surf != nullptr) ;
for(unsigned int i = 0 ; i < object.indices.size() ; i+=3) {
auto index = object.indices;
Point2D P1 = { object.uv[index[i]] , object.uv[index[i] + 1 ] } ;
Point2D P2 = { object.uv[index[i + 1]] , object.uv[index[i + 1] + 1 ] } ;
Point2D P3 = { object.uv[index[i + 2]] , object.uv[index[i + 2] + 1 ] } ;
P1.print();
P2.print();
P3.print();
std::cout << index[i] << " " << index[i+1] << " "<< index[i+2] << "\n" ;
Vect3D N1 = { object.normals[index[i]] , object.normals[index[i] + 1 ] , object.normals[index[i] + 2] } ;
Vect3D N2 = { object.normals[index[i + 1]] , object.normals[index[i + 1] + 1 ] , object.normals[index[i + 1 ] + 2] } ;
Vect3D N3 = { object.normals[index[i + 2 ]] , object.normals[index[i + 2] + 1 ] , object.normals[index[i + 2 ] + 2 ] } ;
P1.x *= width ;
P1.y *= height ;
P2.x *= width ;
P2.y *= height ;
P3.x *= width ;
P3.y *= height ;
set_pixel_color(surf , P1.x , P1.y , 0xFFFFFFFF) ;
set_pixel_color(surf , P2.x , P2.y , 0xFFFFFFFF) ;
set_pixel_color(surf , P3.x , P3.y , 0xFFFFFFFF) ;
auto bounding_coords = [](float x , float y , float z , bool min) {
if( min ) {
if( x <= y )
return x <= z ? x : z ;
else
return y <= z ? y : z ;
}
else {
if( x >= y )
return x >= z ? x : z ;
else
return y >= z ? y : z ;
}
};
auto x_max = static_cast<int>(bounding_coords( P1.x , P2.x , P3.x , false));
auto x_min = static_cast<int>(bounding_coords( P1.x , P2.x , P3.x , true ));
auto y_max = static_cast<int>(bounding_coords( P1.y , P2.y , P3.y , false));
auto y_min = static_cast<int>(bounding_coords( P1.y , P2.y , P3.y , true));
auto barycentric_lerp = [] (Point2D P1 , Point2D P2 , Point2D P3 , Point2D I){
auto W1 = ( (P2.y - P3.y ) * (I.x - P3.x ) + ( P3.x - P2.x) * (I.y - P3.y) ) / ( (P2.y - P3.y ) * (P1.x - P3.x ) + (P3.x - P2.x ) * (P1.y - P3.y ) ) ;
auto W2 = ( (P3.y - P1.y) * (I.x - P3.x) + (P1.x - P3.x) * ( I.y - P3.y ) ) / ( (P2.y - P3.y ) * (P1.x - P3.x) + ( P3.x - P2.x) * (P1.y - P3.y ) ) ;
auto W3 = 1 - W1 - W2 ;
Vect3D v = {W1 , W2 , W3} ;
return v ;
};
for(int x = x_min ; x <= x_max ; x++){
for(int y = y_min ; y <= y_max ; y++){
Point2D I = {static_cast<float>(x) ,static_cast<float> (y)} ;
Vect3D C = barycentric_lerp(P1 , P2 , P3 , I) ;
if(C.x >= 0 && C.y >= 0 && C.z >= 0){
Vect3D normal = { N1.x * C.x + N2.x * C.y + N3.x * C.z ,
N1.y * C.x + N2.y * C.y + N3.y * C.z ,
N1.z * C.x + N2.z * C.y + N3.z * C.z };
RGB rgb = RGB( static_cast<int>(normal.x * 255) , static_cast<int>(normal.y * 255) , static_cast<int>(normal.z * 255) , 0 ) ;
uint32_t val = rgb.rgb_to_int() ;
set_pixel_color(surf , x , y , val) ;
}
}
}
}
return surf ;
}
它应该采用 UVs 和 indices ,并将 UV 点投影到纹理上并在每个点之间插入法线。
所以我尝试做的是通过对 x 组件执行 UVarray[indexarray[n-1]] 来引用第 n 个顶点的 UV,
和 UVarray[indexarray[n-1]+1] 作为 y 分量。
这里的问题是它不起作用。
例如,在一个由两个三角形组成的简单平面上,这里是我得到的:
所以我应该得到的是模型的精确 UV 投影,如下所示:
最后,我 运行 gdb 下的程序,我发现顶点数组被正确加载,索引也被正确加载......但 UVs 没有:
我在最后 3 行打印了这些数组的值。
这里的 .obj 文件有这些简单的数据:
o Plane
v 1.000000 -0.000000 1.000000
v -1.000000 0.000000 -1.000000
v -1.000000 -0.000000 1.000000
v 1.000000 0.000000 -1.000000
vt 0.089179 0.089179
vt 0.910821 0.910821
vt 0.089179 0.910821
vt 0.910821 0.089179
vn 0.0000 1.0000 0.0000
usemtl None
s 1
f 1/1/1 2/2/1 3/3/1
f 1/1/1 4/4/1 2/2/1
索引保持相同的顺序,但不引用相同的 UV 坐标。
我希望这是我的错误,而不是 Assimp 的错误,你们知道那里发生了什么吗?
谢谢。
问题已解决。错误很简单,索引没有正确指向面部,因为我忘记包括填充。
我实际上正在编写一个烘焙法线贴图的工具。 所以我有一个功能,必须采用 3D 对象,并将每个顶点的法向量投影到纹理上。
我目前正在使用 Assimp 库导入 .obj 模型,我以前从未遇到过这个问题...
这是导入网格的函数:
std::vector<Object3D> Loader::load(const char* file){
Assimp::Importer importer ;
const aiScene *modelScene = importer.ReadFile(file , aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices
| aiProcess_FlipUVs) ;
if(modelScene != nullptr)
{
std::vector<Object3D> objects;
for(int i = 0 ; i < modelScene->mNumMeshes ; i++){
const aiMesh* mesh = modelScene->mMeshes[i] ;
Object3D object ;
assert(mesh->HasTextureCoords(0) ) ;
for(int f = 0 ; f < mesh->mNumVertices ; f++){
const aiVector3D* vert = &(mesh->mVertices[f]) ;
const aiVector3D* norm = &(mesh->mNormals[f]) ;
const aiVector3D* tex = &(mesh->mTextureCoords[0][f]) ;
object.vertices.push_back(vert->x);
object.vertices.push_back(vert->y);
object.vertices.push_back(vert->z);
object.uv.push_back(tex->x) ;
object.uv.push_back(tex->y) ;
object.normals.push_back(norm->x) ;
object.normals.push_back(norm->y) ;
object.normals.push_back(norm->z) ;
}
for(int ind = 0 ; ind < mesh->mNumFaces ; ind++){
assert(mesh->mFaces[ind].mNumIndices==3) ;
object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[0]));
object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[1]));
object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[2]));
}
std::cout << "object loaded : " << mesh->mName.C_Str()<< "\n" ;
objects.push_back(object) ;
}
return objects ;
}
else
{
std::cout << "Problem loading scene" << std::endl ;
return std::vector<Object3D>() ;
}
}
它将一个场景分割成多个网格,returns它们的顶点、UV、法线和索引。
然后,我将其发送到此函数:
SDL_Surface* ImageManager::project_uv_normals(Object3D object , int width , int height){
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
Uint32 rmask = 0xFF000000 ;
Uint32 gmask = 0x00FF0000 ;
Uint32 bmask = 0x0000FF00 ;
Uint32 amask = 0x000000FF ;
#else
Uint32 amask = 0xFF000000 ;
Uint32 bmask = 0x00FF0000 ;
Uint32 gmask = 0x0000FF00 ;
Uint32 rmask = 0x000000FF ;
#endif
SDL_Surface* surf = SDL_CreateRGBSurface(0 , width , height , 24 , rmask , gmask , bmask , amask) ;
assert(surf != nullptr) ;
for(unsigned int i = 0 ; i < object.indices.size() ; i+=3) {
auto index = object.indices;
Point2D P1 = { object.uv[index[i]] , object.uv[index[i] + 1 ] } ;
Point2D P2 = { object.uv[index[i + 1]] , object.uv[index[i + 1] + 1 ] } ;
Point2D P3 = { object.uv[index[i + 2]] , object.uv[index[i + 2] + 1 ] } ;
P1.print();
P2.print();
P3.print();
std::cout << index[i] << " " << index[i+1] << " "<< index[i+2] << "\n" ;
Vect3D N1 = { object.normals[index[i]] , object.normals[index[i] + 1 ] , object.normals[index[i] + 2] } ;
Vect3D N2 = { object.normals[index[i + 1]] , object.normals[index[i + 1] + 1 ] , object.normals[index[i + 1 ] + 2] } ;
Vect3D N3 = { object.normals[index[i + 2 ]] , object.normals[index[i + 2] + 1 ] , object.normals[index[i + 2 ] + 2 ] } ;
P1.x *= width ;
P1.y *= height ;
P2.x *= width ;
P2.y *= height ;
P3.x *= width ;
P3.y *= height ;
set_pixel_color(surf , P1.x , P1.y , 0xFFFFFFFF) ;
set_pixel_color(surf , P2.x , P2.y , 0xFFFFFFFF) ;
set_pixel_color(surf , P3.x , P3.y , 0xFFFFFFFF) ;
auto bounding_coords = [](float x , float y , float z , bool min) {
if( min ) {
if( x <= y )
return x <= z ? x : z ;
else
return y <= z ? y : z ;
}
else {
if( x >= y )
return x >= z ? x : z ;
else
return y >= z ? y : z ;
}
};
auto x_max = static_cast<int>(bounding_coords( P1.x , P2.x , P3.x , false));
auto x_min = static_cast<int>(bounding_coords( P1.x , P2.x , P3.x , true ));
auto y_max = static_cast<int>(bounding_coords( P1.y , P2.y , P3.y , false));
auto y_min = static_cast<int>(bounding_coords( P1.y , P2.y , P3.y , true));
auto barycentric_lerp = [] (Point2D P1 , Point2D P2 , Point2D P3 , Point2D I){
auto W1 = ( (P2.y - P3.y ) * (I.x - P3.x ) + ( P3.x - P2.x) * (I.y - P3.y) ) / ( (P2.y - P3.y ) * (P1.x - P3.x ) + (P3.x - P2.x ) * (P1.y - P3.y ) ) ;
auto W2 = ( (P3.y - P1.y) * (I.x - P3.x) + (P1.x - P3.x) * ( I.y - P3.y ) ) / ( (P2.y - P3.y ) * (P1.x - P3.x) + ( P3.x - P2.x) * (P1.y - P3.y ) ) ;
auto W3 = 1 - W1 - W2 ;
Vect3D v = {W1 , W2 , W3} ;
return v ;
};
for(int x = x_min ; x <= x_max ; x++){
for(int y = y_min ; y <= y_max ; y++){
Point2D I = {static_cast<float>(x) ,static_cast<float> (y)} ;
Vect3D C = barycentric_lerp(P1 , P2 , P3 , I) ;
if(C.x >= 0 && C.y >= 0 && C.z >= 0){
Vect3D normal = { N1.x * C.x + N2.x * C.y + N3.x * C.z ,
N1.y * C.x + N2.y * C.y + N3.y * C.z ,
N1.z * C.x + N2.z * C.y + N3.z * C.z };
RGB rgb = RGB( static_cast<int>(normal.x * 255) , static_cast<int>(normal.y * 255) , static_cast<int>(normal.z * 255) , 0 ) ;
uint32_t val = rgb.rgb_to_int() ;
set_pixel_color(surf , x , y , val) ;
}
}
}
}
return surf ;
}
它应该采用 UVs 和 indices ,并将 UV 点投影到纹理上并在每个点之间插入法线。
所以我尝试做的是通过对 x 组件执行 UVarray[indexarray[n-1]] 来引用第 n 个顶点的 UV,
和 UVarray[indexarray[n-1]+1] 作为 y 分量。
这里的问题是它不起作用。
例如,在一个由两个三角形组成的简单平面上,这里是我得到的:
所以我应该得到的是模型的精确 UV 投影,如下所示:
最后,我 运行 gdb 下的程序,我发现顶点数组被正确加载,索引也被正确加载......但 UVs 没有:
我在最后 3 行打印了这些数组的值。
这里的 .obj 文件有这些简单的数据:
o Plane
v 1.000000 -0.000000 1.000000
v -1.000000 0.000000 -1.000000
v -1.000000 -0.000000 1.000000
v 1.000000 0.000000 -1.000000
vt 0.089179 0.089179
vt 0.910821 0.910821
vt 0.089179 0.910821
vt 0.910821 0.089179
vn 0.0000 1.0000 0.0000
usemtl None
s 1
f 1/1/1 2/2/1 3/3/1
f 1/1/1 4/4/1 2/2/1
索引保持相同的顺序,但不引用相同的 UV 坐标。
我希望这是我的错误,而不是 Assimp 的错误,你们知道那里发生了什么吗? 谢谢。
问题已解决。错误很简单,索引没有正确指向面部,因为我忘记包括填充。