0

我喜欢将 3ds 模型加载到简单的 opengl 程序中,我所做的就是使用我找到的 2 个链接作为参考:

http://pastebin.com/CZ82VYWThttp://www.donkerdump.nl/node/207我从红皮书立方体示例中获取代码并尝试在 2 之间进行调整,
但我一直在收到未处理的异常0x00000000 glGenBuffer 异常。在 CModel3DS::CreateVBO() 方法中,这是我的代码:

// main.cpp
#include <stdlib.h>
#include "CModel3DS.h"

CModel3DS * monkey;
// Initialize some OpenGL settings
void initializeGL(void)
{
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glShadeModel(GL_SMOOTH);
        
        // Enable lighting and set the position of the light
        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);
        GLfloat pos[] = { 0.0, 4.0, 4.0 };
        glLightfv(GL_LIGHT0, GL_POSITION, pos);
        
        // Generate Vertex Buffer Objects
        monkey->CreateVBO();
}

// Reset viewport and projection matrix after the window was resized
void resizeGL(int width, int height)
{
        // Reset the viewport
        glViewport(0, 0, width, height);
        // Reset the projection and modelview matrix
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        // 10 x 10 x 10 viewing volume
        glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
}

// Do all the OpenGL rendering
void paintGL(void)
{
        glClear(GL_COLOR_BUFFER_BIT);
        
        // Draw our model
        monkey->Draw();
        
        // We don't need to swap the buffers, because QT does that automaticly for us
}

void init(void) 
{
   glClearColor (0.0, 0.0, 0.0, 0.0);
   glShadeModel (GL_FLAT);
   
}

void display(void)
{
   glClear (GL_COLOR_BUFFER_BIT);
   glColor3f (1.0, 1.0, 1.0);
   glLoadIdentity ();           /* clear the matrix */
        /* viewing transformation  */
   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
   glScalef (1.0, 2.0, 1.0);      /* modeling transformation */ 
   //glutWireCube (1.0);
   paintGL();
   glFlush ();
}

void reshape (int w, int h)
{
   glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
   glMatrixMode (GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
        exit(0);
        break;
   }
}




int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   GLenum err = glewInit();
        if (GLEW_OK != err)
        {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
       
        }
        
        try
        {
                monkey = new CModel3DS("monkey.3ds");
                initializeGL();
        }
        catch(std::string error_str)
        {
                std::cerr << "Error: " << error_str << std::endl;
             

                exit(1);
        }
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize (500, 500); 
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   init ();
   glutDisplayFunc(display); 
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMainLoop();
   return 0;
} 

//the CModel3DS.h

#ifndef CMODEL3DS_H
#define CMODEL3DS_H
#include <GL/glew.h>
#include <GL/glut.h>
#include <string>
#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
#include <lib3ds/file.h>
#include <lib3ds/mesh.h> 
// Our 3DS model class
class CModel3DS
{
        public:
                CModel3DS(std:: string filename);
                virtual void Draw() const;
                virtual void CreateVBO();
                virtual ~CModel3DS();
        protected:
                void GetFaces();
                unsigned int m_TotalFaces;
                Lib3dsFile * m_model;
                GLuint m_VertexVBO, m_NormalVBO;
};

and the cpp

#include "CModel3DS.h"





// Load 3DS model
CModel3DS::CModel3DS(std:: string filename)
{
        m_TotalFaces = 0;
        
        m_model = lib3ds_file_load(filename.c_str());
        // If loading the model failed, we throw an exception
        if(!m_model)
        {
                throw strcat("Unable to load ", filename.c_str());
        }
}


// Count the total number of faces this model has
void CModel3DS::GetFaces()
{
        assert(m_model != NULL);

        m_TotalFaces = 0;
        Lib3dsMesh * mesh;
        // Loop through every mesh
        for(mesh = m_model->meshes;mesh != NULL;mesh = mesh->next)
        {
                // Add the number of faces this mesh has to the total faces
                m_TotalFaces += mesh->faces;
        }
}


// Copy vertices and normals to the memory of the GPU
void CModel3DS::CreateVBO()
{
        assert(m_model != NULL);
        
        // Calculate the number of faces we have in total
        GetFaces();
        
        // Allocate memory for our vertices and normals
        Lib3dsVector * vertices = new Lib3dsVector[m_TotalFaces * 3];
        Lib3dsVector * normals = new Lib3dsVector[m_TotalFaces * 3];
        
        Lib3dsMesh * mesh;
        unsigned int FinishedFaces = 0;
        // Loop through all the meshes
        for(mesh = m_model->meshes;mesh != NULL;mesh = mesh->next)
        {
                lib3ds_mesh_calculate_normals(mesh, &normals[FinishedFaces*3]);
                // Loop through every face
                for(unsigned int cur_face = 0; cur_face < mesh->faces;cur_face++)
                {
                        Lib3dsFace * face = &mesh->faceL[cur_face];
                        for(unsigned int i = 0;i < 3;i++)
                        {
                                memcpy(&vertices[FinishedFaces*3 + i], mesh->pointL[face->points[ i ]].pos, sizeof(Lib3dsVector));
                        }
                        FinishedFaces++;
                }
        }
        
        // Generate a Vertex Buffer Object and store it with our vertices
        glGenBuffers(1, &m_VertexVBO);   <<<---------------------------------------------------------------------------------HERE IS MY EXCEPTION 
        glBindBuffer(GL_ARRAY_BUFFER, m_VertexVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Lib3dsVector) * 3 * m_TotalFaces, vertices, GL_STATIC_DRAW);
        
        // Generate another Vertex Buffer Object and store the normals in it
        glGenBuffers(1, &m_NormalVBO);
        glBindBuffer(GL_ARRAY_BUFFER, m_NormalVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Lib3dsVector) * 3 * m_TotalFaces, normals, GL_STATIC_DRAW);
        
        // Clean up our allocated memory
        delete vertices;
        delete normals;
        
        // We no longer need lib3ds
        lib3ds_file_free(m_model);
        m_model = NULL;
}


// Render the model using Vertex Buffer Objects
void CModel3DS:: Draw() const
{
        assert(m_TotalFaces != 0);
        
        // Enable vertex and normal arrays
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);
        
        // Bind the vbo with the normals
        glBindBuffer(GL_ARRAY_BUFFER, m_NormalVBO);
        // The pointer for the normals is NULL which means that OpenGL will use the currently bound vbo
        glNormalPointer(GL_FLOAT, 0, NULL);
        
        glBindBuffer(GL_ARRAY_BUFFER, m_VertexVBO);
        glVertexPointer(3, GL_FLOAT, 0, NULL);
        
        // Render the triangles
        glDrawArrays(GL_TRIANGLES, 0, m_TotalFaces * 3);
        
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_NORMAL_ARRAY);
}


// Destructor
CModel3DS::~CModel3DS()
{
        glDeleteBuffers(1, &m_VertexVBO);
        glDeleteBuffers(1, &m_NormalVBO);
        
        if(m_model != NULL)
        {
                lib3ds_file_free(m_model);
        }
}
#endif

在挖掘和搜索它之后更新 好,在创建窗口之后,glew 的 init 需要最后出现。但现在我有另一个问题。我没有看到模型。我修复了代码,它应该是这样的:

#include <stdlib.h>
#include "CModel3DS.h"

CModel3DS * monkey;
// Initialize some OpenGL settings
void initializeGL(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);
    
    // Enable lighting and set the position of the light
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    GLfloat pos[] = { 0.0, 4.0, 4.0 };
    glLightfv(GL_LIGHT0, GL_POSITION, pos);
    
    // Generate Vertex Buffer Objects
    monkey->CreateVBO();
}

// Reset viewport and projection matrix after the window was resized
void resizeGL(int width, int height)
{
    // Reset the viewport
    glViewport(0, 0, width, height);
    // Reset the projection and modelview matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    // 10 x 10 x 10 viewing volume
    glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

// Do all the OpenGL rendering
void paintGL(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    
    // Draw our model
    monkey->Draw();
    
    // We don't need to swap the buffers, because QT does that automaticly for us
}

void init(void) 
{
   glClearColor (0.0, 0.0, 0.0, 0.0);
   glShadeModel (GL_FLAT);
   
}

void display(void)
{
   glClear (GL_COLOR_BUFFER_BIT);
   glColor3f (1.0, 1.0, 1.0);
   glLoadIdentity ();             /* clear the matrix */
           /* viewing transformation  */
   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
   glScalef (1.0, 2.0, 1.0);      /* modeling transformation */ 
   //glutWireCube (1.0);
  
   glFlush ();
}

void reshape (int w, int h)
{
   glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
   glMatrixMode (GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}




int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize (500, 500); 
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   init ();
   glutDisplayFunc(display); 
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMainLoop();
   GLenum err = glewInit();
    if (GLEW_OK != err)
    {
      /* Problem: glewInit failed, something is seriously wrong. */
      fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
       
    }
    
    try
    {
        monkey = new CModel3DS("monkey.3ds");
        initializeGL();
        paintGL();
    }
    catch(std::string error_str)
    {
        std::cerr << "Error: " << error_str << std::endl;
         

        exit(1);
    }
   return 0;
} 

更新 2
我发现为什么只显示窗口,因为 glutMainLoop(); 从未执行过 glew 代码;但是当我把 glutMainLoop(); 在 glewInit() 之后;作为代码中的最后一行,我仍然得到缓冲区的旧异常错误。所以我还需要做什么......

4

2 回答 2

2

使用 GLEW 您需要检查扩展是否实际可用。如果不支持glGenBuffers或任何其他不支持的扩展函数是空指针,则需要仔细检查。请参阅 GLEW 文档如何正确检查扩展的可用性:

检查扩展

从 GLEW 1.1.0 开始,您可以通过查询 GLEW_{extension_name} 形式的全局定义变量来了解您的平台上是否有特定的扩展:

if (GLEW_ARB_vertex_program)
{
  /* It is safe to use the ARB_vertex_program extension here. */
  glGenProgramsARB(...);
}
于 2011-06-21T12:46:46.197 回答
1

glGenBufferswglGetProcAddress需要使用glXGetProcAddress依赖于操作系统的函数来检索函数指针。您似乎使用GLEW。你能在函数glewInit之前调用吗?glutMainLoop您还应该对此进行测试glGenBuffers!=NULL

于 2011-06-21T12:47:37.670 回答