- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我已经编写了一个 C++ Obj 文件加载器,但我无法正常工作。问题是在解析一个简单的 obj 文件时,如下所示:
# Blender v2.62 (sub 0) OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn 1.000000 -0.000000 0.000000
vn 1.000000 0.000000 0.000001
vn -0.000000 1.000000 0.000000
vn 0.000000 -1.000000 0.000000
usemtl Material
s off
f 5//1 1//1 4//1
f 5//1 4//1 8//1
f 3//2 7//2 8//2
f 3//2 8//2 4//2
f 2//3 6//3 3//3
f 6//3 7//3 3//3
f 1//4 5//4 2//4
f 5//5 6//5 2//5
f 5//6 8//6 6//6
f 8//6 7//6 6//6
f 1//7 2//7 3//7
f 1//7 3//7 4//7
我无法理解将法线传递给 OpenGL 的正确方法。我总是得到这样的结果:
ObjLoader.h
#include <Eigen/Core>
class ObjLoader
{
public:
ObjLoader();
bool load(const std::string &filename);
void draw();
private:
bool loadFace(const std::string &line,int lineNumber);
std::vector< Eigen::Vector3d> verticesCoord,verticesNormals;
std::vector< Eigen::Vector2d> textureCoords;
std::vector<GLuint> vertexIndices,normalIndices,textureIndices;
Eigen::Vector3d calculateNormal( const Eigen::Vector3d &coord1, const Eigen::Vector3d &coord2, const Eigen::Vector3d &coord3 );
std::string mtlFile;
unsigned int nVerticesPerFace;
};
ObjLoader.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <Eigen/Core>
#include "ObjLoader.h"
using namespace std;
using namespace Eigen;
ObjLoader::ObjLoader()
{
}
bool ObjLoader::load(const string &filename)
{
ifstream is(filename.c_str());
if (is.is_open())
{
cerr << "File " + filename + " loaded successfully" << endl;
}
std::vector<Vector3d> temporaryNormals; // a vector to contain the normals as they are read from the obj
string line;
unsigned int lineNumber=0;
while ( getline(is,line) )
{
lineNumber++;
if ( line.empty() || line.at(0)=='#' )
continue;
if ( line.substr(0,6)=="mtllib")
{
this->mtlFile = line.substr(7,line.size()-1);
cerr << "MTLIB support file= " << mtlFile << endl;
}
stringstream stream(line);
char identifier ;
stream >> std::skipws >> identifier;
char specifier;
stream >> specifier;
if (specifier != 't' && specifier != 'n' && specifier!='p' )
{
stream.seekg(0);
specifier=0;
}
switch ( identifier )
{
case 'v': //is a vertex specification
{
switch ( specifier ) // if there is a space then is a simple vertex coordinates
{
case 0:
{
char tmp; stream >> tmp;
Eigen::Vector3d vertex(0.0,0.0,0.0);
stream >> vertex[0] >> vertex[1] >> vertex[2];
this->verticesCoord.push_back(vertex);
}
break;
case 't':
{
Eigen::Vector2d textures(0,0);
stream >> textures[0] >> textures[1];
this->textureCoords.push_back(textures);
}
break;
case 'n':
{
Eigen::Vector3d vertexNormal(0,0,0);
stream >> vertexNormal[0] >> vertexNormal[1] >> vertexNormal[2];
temporaryNormals.push_back(vertexNormal);
}
break;
}
}
break;
case 'f': // is a face specification
{
this->loadFace(line,lineNumber);
}
break;
}
}
// Rearrange the normals
verticesNormals.resize(temporaryNormals.size(),Vector3d(1,1,1));
for(unsigned int i=0;i<vertexIndices.size();i++)
{
GLuint nI = normalIndices.at(i);
GLuint vI = vertexIndices.at(i);
if(nI!=vI)
{
this->verticesNormals.at(vI) = temporaryNormals.at(nI);
std::cerr<< "Normal index doesn't match vertex index: " << vertexIndices[i] << " " << normalIndices[i] << std::endl;
}
else
{
this->verticesNormals.at(vI) = temporaryNormals.at(vI);
}
cerr << "Vertices=" << this->verticesCoord.size() << endl;
cerr << "Normals=" << this->verticesNormals.size() << endl;
cerr << "Textures=" << this->textureCoords.size() << endl;
cerr << "NVertices per face= " << this->nVerticesPerFace << endl;
cerr << "Faces= " << this->vertexIndices.size()/nVerticesPerFace << endl;
return 0;
}
}
bool BothAreSpaces(char lhs, char rhs)
{
return (lhs == rhs) && (lhs == ' ');
}
bool ObjLoader::loadFace(const string &_line, int lineNumber)
{
std::string line = _line;
std::string::iterator new_end = std::unique(line.begin(), line.end(), BothAreSpaces);
line.erase(new_end, line.end());
stringstream stream(line),countVerticesStream(line);
string val;
stream >> val;
if (val!="f")
{
string lineString= static_cast<ostringstream*>( &(ostringstream() << lineNumber) )->str();
throw std::logic_error("Error loading face at line " + lineString);
}
// Count the number of vertices per face by counting the /
int nVertices = 0;
while ( countVerticesStream.good() )
{
if (countVerticesStream.get()==' ' && countVerticesStream.good())
nVertices++;
}
if ( nVerticesPerFace !=0 && nVerticesPerFace != nVertices )
{
string lineString= static_cast<ostringstream*>( &(ostringstream() << lineNumber) )->str();
throw std::logic_error("Can't support non uniform faces definitions. You must use the same number of vertices for every faces. Check line "+lineString);
}
this->nVerticesPerFace = nVertices;
GLuint indexPosition = 0, indexTexture = 0, indexNormal = 0;
// Compute the normal
Vector3d faceVertices[nVerticesPerFace];
for ( unsigned int iFace = 0; iFace < nVerticesPerFace; iFace++ )
{
stream >> indexPosition;
faceVertices[iFace] = verticesCoord.at(indexPosition-1);
if( '/' == stream.peek() )
{
stream.ignore();
if( '/' != stream.peek() )
{
stream >> indexTexture;
}
if( '/' == stream.peek() )
{
stream.ignore();
// Optional vertex normal
stream >> indexNormal;
}
}
this->vertexIndices.push_back(indexPosition-1); // that's because Obj format starts counting from 1
this->textureIndices.push_back(indexTexture-1); // that's because Obj format starts counting from 1
this->normalIndices.push_back(indexNormal-1); // that's because Obj format starts counting from 1
}
}
void ObjLoader::draw()
{
double *pVerticesCoords = &this->verticesCoord.at(0)[0];
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3,GL_DOUBLE, 0,pVerticesCoords);
glDrawArrays(GL_POINTS, 0, this->verticesCoord.size());
glDisableClientState(GL_VERTEX_ARRAY);
GLint coordsPerVertex=3;
GLint stride=0; // Our coords are tightly packed into their arrays so we set this to 0
//double *pVerticesCoords = &this->verticesCoord.at(0)[0];
double *pNormalCoords = &this->verticesNormals.at(0)[0];
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_DOUBLE, 0, pNormalCoords); // Normal pointer to normal array
glVertexPointer(coordsPerVertex,GL_DOUBLE, stride,pVerticesCoords);
switch ( nVerticesPerFace )
{
case 3:
glDrawElements(GL_TRIANGLES, vertexIndices.size(), GL_UNSIGNED_INT, this->vertexIndices.data());
break;
case 4:
glDrawElements(GL_QUADS, vertexIndices.size(), GL_UNSIGNED_INT, this->vertexIndices.data());
break;
default:
glDrawElements(GL_POLYGON, vertexIndices.size(), GL_UNSIGNED_INT, this->vertexIndices.data());
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
我应该如何重新组织法线以使它们反射(reflect)相同的顶点顺序?
最佳答案
你的问题出在数据结构上。至少在加载 OBJ 时你需要将你的脸加载到类似的东西中:
struct Vertex
{
unsigned int vertex;
unsigned int normal;
unsigned int texturecoord;
};
struct Face
{
// not dynamic, but you get the idea.
Vertex vertexes[N];
};
然后如果你想要一个匹配顶点的法线数组(可能还有纹理坐标),你需要创建一个匹配的新数组。 OBJ 格式针对存储而非渲染进行了优化。
这个两步过程的额外好处是,您可以通过将每个非三角形夹板成三角形来消除对同质面的限制。
关于c++ - 使用 Wavefront Obj 了解法线指标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16296301/
所以昨天我写了 WaveFront .obj 3D 模型加载器,它现在工作正常(虽然不支持所有内容)所以我写了简单的测试来在屏幕上绘制任何 3D 模型,在我为场景添加照明之前一切正常.光出现了,但法线
我的代码(用 C++ 编码)在处理更新模型法线的 for 循环中存在瓶颈。我用来测试的模型有大约 ~2.2k 个顶点(指示),工作正常并且在 60 fps 限制下工作,但法线与指示器(~12k)一样多
我无法将法线和 u,v 对发送到我的着色器。如果我删除法线,一切都会按预期进行。 编辑看起来 v_normal 正在接收用于 v_coord 的值。我仍然不知道。/编辑 这是我的顶点: struct
我正在寻找一种方法来获取矩形的所有顶点,该矩形的中心、法线、长度和高度我都知道。我的数学有点弱所以请帮助我。编辑:飞机在 3D 空间中。 最佳答案 通过从中心点的 x/y 位置减去/加上宽度/高度的一
是否可以从片段着色器内访问表面法线(与片段平面相关的法线)?或者也许这可以在顶点着色器中完成? 当我们沿着着色器管道走下去时,相关几何体的所有知识是否都会丢失,或者是否有一些巧妙的方法可以在片段着色器
我无法使用 VBO 正确渲染法线。下面是我正在使用的代码,顶点是一个包含顶点的数组,法线是一个包含法线的数组: //Create the buffers and such GLuint VBOID;
我已经有了这个不再那么小的基于图 block 的游戏,这是我的第一个真正的 OpenGL 项目。我想将每个图 block 渲染为 3D 对象。因此,首先我创建了一些对象,例如立方体和球体,为它们提供了
我正在尝试添加一个垂直于我单击的面的框(称为“标记”)。 为此,单击时,我会转换一条射线,如果它击中某些物体,我会获取法线的交点值并将它们传输到“标记”作为其旋转值。在问这个问题之前,我阅读了这个答案
这与另一个问题(那里的图像)中描述的问题有关: Opengl shader problems - weird light reflection artifacts 我有一个 .obj 导入器,它创建一
我正在尝试制作一个在 OpenGL 2.1 和 Qt5 中渲染的简单 map 。但我在非常基本的问题上失败了。我在这里展示的是表面法线。 我有 4 个由单个三角形几何体组成的对象。一个简单的几何图形是
我正在开发一个类似 JavaScript/Canvas 3D FPS 的引擎,迫切需要一个法线向量(如果您愿意,也可以是观察向量)来进行近平面和远平面裁剪。我有 x 轴和 y 轴旋转 Angular
我正在编写用于在我的 DirectX 应用程序中存储、加载和渲染静态网格的类。 我知道 Box 模型可以使用 8 个顶点,但通常它使用 24 或 36 个(因为一个“空间中的顶点”实际上是 3 个具有
我无法使 phong 着色看起来正确。我很确定我的 OpenGL 调用或我加载法线的方式有问题,但我想这可能是其他问题,因为 3D 图形和 Assimp 对我来说都还很陌生。尝试加载 .obj/.mt
我是一名优秀的程序员,十分优秀!