obj 在 OpenGl 中无法正确移动的问题
Problems with obj not moving properly in OpenGl
这样,每个输出一个obj文件效果很好
但是如果我试图表示同时围绕中心太阳旋转的这两个 obj,则会出现错误。
一开始看起来还不错,后来纹理就消失了。结果window被强制关机
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// World Transfrom
glPushMatrix();
glLoadIdentity();
//glTranslatef (0.0f, 0.0f, -300.0f);
///////////////////Drawing//////////////////////////////////////////////////////
// Figure0 Draw
glPushMatrix();
glLoadIdentity();
glColor3f(1.0f, 0.0f, 0.0f);
glutSolidSphere(10, 15, 15);
glPopMatrix();
// Figure1 Draw
glPushMatrix();
glLoadIdentity();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glRotatef(0.0f, 0.0f, 1.0f, 0.0f);
glRotatef(Sphere1_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(70.0f, 0.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
_mesh = new Mesh("obj\Earth_2K.obj", "obj\Diffuse_2K_Earth.png");
_mesh->drawSolid(_smoothing);
glPopMatrix();
// Figure2 Draw
glPushMatrix();
glLoadIdentity();
glRotatef(-45.0f, 0.0f, 0.0f, 1.0f);
glRotatef(Sphere2_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(60.0f, 0.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
_mesh = new Mesh("obj\Moon 2K.obj", "obj\Diffuse_2K_Moon.png");
_mesh->drawSolid(_smoothing);
glPopMatrix();
////////////////////////////////////////////////////////////////////////////////
glPopMatrix();
glutSwapBuffers();
}
这段代码是一个输出和移动obj的函数。那边的_mesh
有一个class对象让我加载obj文件。 DrawSolid
是一种平滑方法的表达。我认为 glPushMatrix
和 glPopMatrix
在该代码中的用法是错误的,但我不知道如何修复它。为什么会这样?
附加说明
此代码为Mesh class
class Mesh
{
public:
vector<Face*> _faces;
vector<Vertex*> _vertices;
Vec3<double> _minBound;
Vec3<double> _maxBound;
vector<Texture*> _textureCoords;
GLuint _textureIndex;
public:
Mesh();
Mesh(char* obj, char* texture) {
open(obj);
loadTexture(texture, _textureIndex);
}
Mesh(char* obj) {
open(obj);
}
~Mesh();
public:
void makeList(void);
void open(char* file);
void loadTexture(char* file, GLuint& texture_index);
void computeNormal(void);
void moveToCenter(double scale = 1.0);
public:
void drawWire(void);
void drawPoint(void);
void drawSolid(bool smoothing);
};
创建 Mesh class 对象时,它会读取 obj 文件和纹理文件。
void Mesh::open(char* file)
{
FILE* fp;
char buffer[100] = { 0 };
Vec3<double> pos;
int index[4], tex[4], empty[4];
int id = 0;
_minBound.Set(1000000.0);
_maxBound.Set(-1000000.0);
fopen_s(&fp, file, "r");
while (fscanf(fp, "%s %lf %lf %lf", buffer, &pos[0], &pos[1], &pos[2]) != EOF)
{
// v 0.2 0.3 0.1
// vt
if (buffer[0] == 'v' && buffer[1] == NULL) {
for (int i = 0; i < 3; i++) {
if (_minBound[i] > pos[i]) _minBound[i] = pos[i];
if (_maxBound[i] < pos[i]) _maxBound[i] = pos[i];
}
_vertices.push_back(new Vertex(id, pos));
}
}
// read texture coordinate of vertics
id = 0;
fseek(fp, 0, SEEK_SET);
while (fscanf(fp, "%s %lf %lf", &buffer, &pos[0], &pos[1]) != EOF) {
if (!strcmp(buffer, "vt")) {
_textureCoords.push_back(new Texture(pos[0], 1.0 - pos[1], 0.0));
}
}
// read faces
id = 0;
fseek(fp, 0, SEEK_SET);
while (fscanf(fp, "%s %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &buffer, &index[0], &tex[0], &empty[0], &index[1], &tex[1], &empty[1], &index[2], &tex[2], &empty[2], &index[3], &tex[3], &empty[3]) != EOF) {
if (buffer[0] == 'f' && buffer[1] == NULL) {
auto v0 = _vertices[index[0] - 1];
auto v1 = _vertices[index[1] - 1];
auto v2 = _vertices[index[2] - 1];
_faces.push_back(new Face(id++, v0, v1, v2, _vertices[index[3] - 1], tex[0] - 1, tex[1] - 1, tex[2] - 1, tex[3] - 1));
//_faces.push_back(new Face(index++, _vertices[v_index[0] - 1], _vertices[v_index[1] - 1], _vertices[v_index[2] - 1]);
}
}
fclose(fp);
moveToCenter(10.0);
makeList();
computeNormal();
}
这段代码是Mesh的Open函数class。此代码从 obj 文件中读取顶点值、纹素值和面值。然后将其传递给每个 class 对象并存储在 class 向量列表中并进行归一化。
void Mesh::drawSolid(bool smoothing) {
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _textureIndex);
glEnable(GL_LIGHTING);
glEnable(GL_SMOOTH)
for (auto f : _faces) {
// get texture coord
glBegin(GL_POLYGON);
if(!smoothing)
glNormal3f(f->_normal.x(), f->_normal.y(), f->_normal.z());
_textureCoords[f->_texelPos[0]];
for (int i = 0; i < 4; i++) {
auto t = _textureCoords[f->_texelPos[i]];
auto v = f->_vertices[i];
glTexCoord2f((GLfloat)t->x(), (GLfloat)t->y());
glNormal3f(v->_normal.x(), v->_normal.y(), v->_normal.z());
}
glEnd();
}
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
在这里,我平滑了归一化值。
在此代码中,_texelPos 是每个面的纹素值数组。
其他问题
void Mesh::loadTexture(char* file, GLuint& texture_index) {
glGenTextures(1, &texture_index);
FILE* fp;
fopen_s(&fp, file, "rb");
if (!fp) {
printf("ERROR : No %s.\n fail to bind %d\n", file, texture_index);
}
int width, height, channel;
unsigned char *image = stbi_load_from_file(fp, &width, &height, &channel, 4);
fclose(fp);
glBindTexture(GL_TEXTURE_2D, texture_index);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE);
}
这是负责设置纹理的代码。
这里,glGenTextures(1, &texture_index);
如果我这样写代码,是否可以在main cpp
的RenderScene
函数中写glBindTexture(GL_TEXTURE_2D, _textureIndex);
?喜欢下面的代码吗?
// Figure1 Draw
glPushMatrix();
glLoadIdentity();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glRotatef(0.0f, 0.0f, 1.0f, 0.0f);
glRotatef(Sphere1_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(70.0f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, 1);
_mesh1->drawSolid(_smoothing);
glPopMatrix();
您是否在每一帧中创建网格并加载纹理?可能您没有释放资源和 运行 内存不足。一次加载网格和纹理,但每帧绘制它们
在渲染循环之前创建一次网格:
_mesh1 = new Mesh("obj\Earth_2K.obj", "obj\Diffuse_2K_Earth.png");
_mesh2 = new Mesh("obj\Moon 2K.obj", "obj\Diffuse_2K_Moon.png");
但是在RenderScene
中绘制网格:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// [...]
_mesh1->drawSolid(_smoothing);
// [...]
_mesh2->drawSolid(_smoothing);
// [...]
}
这样,每个输出一个obj文件效果很好
但是如果我试图表示同时围绕中心太阳旋转的这两个 obj,则会出现错误。
一开始看起来还不错,后来纹理就消失了。结果window被强制关机
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// World Transfrom
glPushMatrix();
glLoadIdentity();
//glTranslatef (0.0f, 0.0f, -300.0f);
///////////////////Drawing//////////////////////////////////////////////////////
// Figure0 Draw
glPushMatrix();
glLoadIdentity();
glColor3f(1.0f, 0.0f, 0.0f);
glutSolidSphere(10, 15, 15);
glPopMatrix();
// Figure1 Draw
glPushMatrix();
glLoadIdentity();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glRotatef(0.0f, 0.0f, 1.0f, 0.0f);
glRotatef(Sphere1_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(70.0f, 0.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
_mesh = new Mesh("obj\Earth_2K.obj", "obj\Diffuse_2K_Earth.png");
_mesh->drawSolid(_smoothing);
glPopMatrix();
// Figure2 Draw
glPushMatrix();
glLoadIdentity();
glRotatef(-45.0f, 0.0f, 0.0f, 1.0f);
glRotatef(Sphere2_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(60.0f, 0.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
_mesh = new Mesh("obj\Moon 2K.obj", "obj\Diffuse_2K_Moon.png");
_mesh->drawSolid(_smoothing);
glPopMatrix();
////////////////////////////////////////////////////////////////////////////////
glPopMatrix();
glutSwapBuffers();
}
这段代码是一个输出和移动obj的函数。那边的_mesh
有一个class对象让我加载obj文件。 DrawSolid
是一种平滑方法的表达。我认为 glPushMatrix
和 glPopMatrix
在该代码中的用法是错误的,但我不知道如何修复它。为什么会这样?
附加说明
此代码为Mesh class
class Mesh
{
public:
vector<Face*> _faces;
vector<Vertex*> _vertices;
Vec3<double> _minBound;
Vec3<double> _maxBound;
vector<Texture*> _textureCoords;
GLuint _textureIndex;
public:
Mesh();
Mesh(char* obj, char* texture) {
open(obj);
loadTexture(texture, _textureIndex);
}
Mesh(char* obj) {
open(obj);
}
~Mesh();
public:
void makeList(void);
void open(char* file);
void loadTexture(char* file, GLuint& texture_index);
void computeNormal(void);
void moveToCenter(double scale = 1.0);
public:
void drawWire(void);
void drawPoint(void);
void drawSolid(bool smoothing);
};
创建 Mesh class 对象时,它会读取 obj 文件和纹理文件。
void Mesh::open(char* file)
{
FILE* fp;
char buffer[100] = { 0 };
Vec3<double> pos;
int index[4], tex[4], empty[4];
int id = 0;
_minBound.Set(1000000.0);
_maxBound.Set(-1000000.0);
fopen_s(&fp, file, "r");
while (fscanf(fp, "%s %lf %lf %lf", buffer, &pos[0], &pos[1], &pos[2]) != EOF)
{
// v 0.2 0.3 0.1
// vt
if (buffer[0] == 'v' && buffer[1] == NULL) {
for (int i = 0; i < 3; i++) {
if (_minBound[i] > pos[i]) _minBound[i] = pos[i];
if (_maxBound[i] < pos[i]) _maxBound[i] = pos[i];
}
_vertices.push_back(new Vertex(id, pos));
}
}
// read texture coordinate of vertics
id = 0;
fseek(fp, 0, SEEK_SET);
while (fscanf(fp, "%s %lf %lf", &buffer, &pos[0], &pos[1]) != EOF) {
if (!strcmp(buffer, "vt")) {
_textureCoords.push_back(new Texture(pos[0], 1.0 - pos[1], 0.0));
}
}
// read faces
id = 0;
fseek(fp, 0, SEEK_SET);
while (fscanf(fp, "%s %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &buffer, &index[0], &tex[0], &empty[0], &index[1], &tex[1], &empty[1], &index[2], &tex[2], &empty[2], &index[3], &tex[3], &empty[3]) != EOF) {
if (buffer[0] == 'f' && buffer[1] == NULL) {
auto v0 = _vertices[index[0] - 1];
auto v1 = _vertices[index[1] - 1];
auto v2 = _vertices[index[2] - 1];
_faces.push_back(new Face(id++, v0, v1, v2, _vertices[index[3] - 1], tex[0] - 1, tex[1] - 1, tex[2] - 1, tex[3] - 1));
//_faces.push_back(new Face(index++, _vertices[v_index[0] - 1], _vertices[v_index[1] - 1], _vertices[v_index[2] - 1]);
}
}
fclose(fp);
moveToCenter(10.0);
makeList();
computeNormal();
}
这段代码是Mesh的Open函数class。此代码从 obj 文件中读取顶点值、纹素值和面值。然后将其传递给每个 class 对象并存储在 class 向量列表中并进行归一化。
void Mesh::drawSolid(bool smoothing) {
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _textureIndex);
glEnable(GL_LIGHTING);
glEnable(GL_SMOOTH)
for (auto f : _faces) {
// get texture coord
glBegin(GL_POLYGON);
if(!smoothing)
glNormal3f(f->_normal.x(), f->_normal.y(), f->_normal.z());
_textureCoords[f->_texelPos[0]];
for (int i = 0; i < 4; i++) {
auto t = _textureCoords[f->_texelPos[i]];
auto v = f->_vertices[i];
glTexCoord2f((GLfloat)t->x(), (GLfloat)t->y());
glNormal3f(v->_normal.x(), v->_normal.y(), v->_normal.z());
}
glEnd();
}
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
在这里,我平滑了归一化值。 在此代码中,_texelPos 是每个面的纹素值数组。
其他问题
void Mesh::loadTexture(char* file, GLuint& texture_index) {
glGenTextures(1, &texture_index);
FILE* fp;
fopen_s(&fp, file, "rb");
if (!fp) {
printf("ERROR : No %s.\n fail to bind %d\n", file, texture_index);
}
int width, height, channel;
unsigned char *image = stbi_load_from_file(fp, &width, &height, &channel, 4);
fclose(fp);
glBindTexture(GL_TEXTURE_2D, texture_index);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE);
}
这是负责设置纹理的代码。
这里,glGenTextures(1, &texture_index);
如果我这样写代码,是否可以在main cpp
的RenderScene
函数中写glBindTexture(GL_TEXTURE_2D, _textureIndex);
?喜欢下面的代码吗?
// Figure1 Draw
glPushMatrix();
glLoadIdentity();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glRotatef(0.0f, 0.0f, 1.0f, 0.0f);
glRotatef(Sphere1_degree, 0.0f, 1.0f, 0.0f);
glTranslatef(70.0f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, 1);
_mesh1->drawSolid(_smoothing);
glPopMatrix();
您是否在每一帧中创建网格并加载纹理?可能您没有释放资源和 运行 内存不足。一次加载网格和纹理,但每帧绘制它们
在渲染循环之前创建一次网格:
_mesh1 = new Mesh("obj\Earth_2K.obj", "obj\Diffuse_2K_Earth.png");
_mesh2 = new Mesh("obj\Moon 2K.obj", "obj\Diffuse_2K_Moon.png");
但是在RenderScene
中绘制网格:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// [...]
_mesh1->drawSolid(_smoothing);
// [...]
_mesh2->drawSolid(_smoothing);
// [...]
}