OpenGL-加载顶点数据时glBufferData()上的SegFault

OpenGL - SegFault on glBufferData() while loading vertex data

本文关键字:上的 SegFault glBufferData 加载 顶点 数据 OpenGL-      更新时间:2023-10-16

问题:glBufferData上的分段错误。

关于libs&输入数据:

 3ds file contains a few models.
 GLEW - 1.11.0
 GLFW - 3.0.4
 GLM - 0.9.5.4
 ASSIMP - 3.1.1
 OS - Windows 7 x64 lastest PS
 GPU: nvidia 770

输出:

Wersja OpenGL: 4.4.0
    Kompilacja shadera...
Compiling shader : vert.vs
- Success
Compiling shader : frag.fs
 - Success
        Ustawianie Model - Widok - Projekcja...
Wczytywanie wczeťniej wygenerowanych obiektˇw...
        Ladowanie Mesha nr.0...
Rozmiary - 2 | 108 | 108
a
b
c

这是代码:

网格加载器.cpp

GLfloat **vertexData, **normalData, **colorsData_buffer;
GLushort** indexData;
/** Bufory */
GLuint* vertexBuffer, *colorBuffer, *indexBuffer;

int mesh_size = 0;
unsigned int* count_of_vertex; //Licznik ile vertex-ów na danym meshie jest
int* count_of_index; //Licznik indeksów
unsigned int suma_vertexow = 0; //Suma wszystkich vertexow... normalnie się powinno to inaczej obejść. Ale kij.

const struct aiFace* tmp_face;
int tmp_index = 0;

//[...]
bool mesh_load(const std::string& Filename)
{
    Assimp::Importer Importer;
    const aiScene* pScene = Importer.ReadFile(Filename.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs);
    /** Sprawdzenie czy wczytał scene */
    if (pScene) {
        init_from_scene(pScene);
        return true;
    }
    else
    {
        std::cout << "Wystąpił błąd podczas wczytywania: " << Importer.GetErrorString() << std::endl;
        return false;
    }
}

void pre_reserve_memory(const aiMesh* paiMesh, int cur_poz)
{
    count_of_index[cur_poz] = 0;
    for (unsigned int i = 0; i < paiMesh->mNumFaces; i++) {
        tmp_face = &paiMesh->mFaces[i];
        count_of_index[cur_poz] += tmp_face->mNumIndices;
    }
    indexData[cur_poz] = new GLushort[count_of_index[cur_poz]];
}


void init_from_scene(const aiScene* pScene)
{
    mesh_size = pScene->mNumMeshes;

    //Pre Rezerwacja miejsca
    vertexData = new GLfloat*[mesh_size];
    colorsData_buffer = new GLfloat*[mesh_size];
    normalData = new GLfloat*[mesh_size];
    indexData = new GLushort*[mesh_size];
    //Buffory
    vertexBuffer = new GLuint[mesh_size];
    colorBuffer = new GLuint[mesh_size];
    indexBuffer = new GLuint[mesh_size];
    count_of_vertex = new unsigned int[mesh_size];
    count_of_index = new int[mesh_size];

    for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
    {
        pre_reserve_memory(pScene->mMeshes[i], i);
         // [...]
        przepare_mesh(pScene->mMeshes[i], vertexData[i], colorsData_buffer[i], normalData[i], indexData[i], &count_of_vertex[i]);
    }

}
void przepare_mesh(const aiMesh* paiMesh, GLfloat* vertexData, GLfloat* colorsData_buffer, GLfloat* normalData, GLushort* indexData, unsigned int* count_of_vertex)
{
    int counter;

    vertexData = (GLfloat *)&paiMesh->mVertices;
    colorsData_buffer = (GLfloat *)&paiMesh->mColors;
    normalData = (GLfloat *)&paiMesh->mNormals;
    *count_of_vertex = paiMesh->mNumVertices;

    for (unsigned int i = 0; i < paiMesh->mNumFaces; i++) {
        tmp_face = &paiMesh->mFaces[i];
        for (unsigned int j = 0; j < tmp_face->mNumIndices; j++)
        {
            counter = i + j;
            indexData[counter] = tmp_face->mIndices[j];
        }
    }
}

/** TODO: RE-LIGHTING, MOUSE */
void render_scene()
{
    glLinkProgram(program); // jak skompilowalem kod to moge go polaczyc z bibliotekami - linkowanie
    glUseProgram(program); // od tego momentu wszystko co zrobie bedzie uzywac tego programu (tej kombinacji shaderow)
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f); // ustala kolor wyczyszczonego okna
    glEnable(GL_CULL_FACE); // wewnetrzne flagi opengl
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    /** Model - View - Projection */
    glm::mat4 Model = glm::mat4(1.0f); // tworzenie macierzy obiektu
    glm::mat4 View = glm::lookAt(glm::vec3(0.0f, 2.0f, -5.0f), glm::vec3(), glm::vec3(0.0f, 1.0f, 0.0f)); // widoku
    glm::mat4 Projection = glm::perspective(60.0f, 16.0f / 9.0f, 0.1f, 1000.0f); // projekcji
    glm::mat4 MVP; // zmienna na pozniej
    GLuint MVPUniformLoc = glGetUniformLocation(program, "MVP"); // daje wskaznik gdzie MVP znajduje sie w pamieci

    /** Addresy Pamięci */
    GLuint positionAttribLoc = glGetAttribLocation(program, "position"); // wytlumaczenie cpu jak sie dostac do adresu pamieci gpu
    GLuint colorAttribLoc = glGetAttribLocation(program, "color");

    /** tworzenie tablicy przechowujacej vertexy */
    GLuint vertexArrayObject; 
    glGenVertexArrays(1, &vertexArrayObject);
    glBindVertexArray(vertexArrayObject);

    for (int i = 0; i < mesh_size; i++)
    {

        suma_vertexow += count_of_vertex[i];
        glGenBuffers(1, &vertexBuffer[i]);
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
        glBufferData(GL_ARRAY_BUFFER, (sizeof(GLfloat)* count_of_vertex[i]), vertexData[i], GL_STATIC_DRAW); //Problem Area
        if (colorsData_buffer[i] != NULL)
        {
            glGenBuffers(1, &colorBuffer[i]);
            glBindBuffer(GL_ARRAY_BUFFER, colorBuffer[i]);
            glBufferData(GL_ARRAY_BUFFER, (sizeof(GLfloat) * count_of_vertex[i]), colorsData_buffer[i], GL_DYNAMIC_DRAW);
        }


        glGenBuffers(1, &indexBuffer[i]);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer[i]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (sizeof(GLushort)* count_of_index[i]), indexData[i], GL_DYNAMIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);

        glEnableVertexAttribArray(positionAttribLoc); // atrybuty wskazinikow (bufory)
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
        glVertexAttribPointer(
            positionAttribLoc,       // attribute. No particular reason for 0, but must match the layout in the shader.
            3,        // size
            GL_FLOAT,        // type
            NORMALIZED,  // normalized?
            0,      // stride - wierzcholki oznaczajace pozycje sa w tym buforze jeden za drugim (odstep miedzy kolejnymi wierzcholkami)
            (GLvoid*)0      // array buffer offset - w ktorym miejscu bufora zaczyna sie inf o wierzcholkach
            );
        glBindBuffer(GL_ARRAY_BUFFER, NULL);
        if (colorsData_buffer[i] != NULL)
        {
            glEnableVertexAttribArray(colorAttribLoc);
            glBindBuffer(GL_ARRAY_BUFFER, colorBuffer[i]);
            glVertexAttribPointer(
                colorAttribLoc,       // attribute. No particular reason for 0, but must match the layout in the shader.
                3,        // size
                GL_FLOAT,        // type
                NORMALIZED,  // normalized?
                0,      // stride
                (GLvoid*)0      // array buffer offset
                );
        }
        glBindBuffer(GL_ARRAY_BUFFER, NULL);


    }
   //[...]
}

Mesh_Loader->通过assimp.importer从3DS文件加载数据并提取每个网格的索引、颜色、顶点、法线的数据

函数渲染->加载数据关于:数据关于索引,颜色,顶点,法线

但是当它将数据加载到缓冲区"glBufferData"时会引起一些问题SegFault

附加功能.cpp加载着色器的额外功能&鼠标回调

哪里有问题?

我不认为这是OpenGL的问题。代码只是使用未初始化的指针。如果它们被用于任何用途,这可能会导致崩溃。它们恰好被传递给glBufferData()

遍历vertexData的用法,它被声明为指向GLfloat:的指针

GLfloat **vertexData;

然后它被分配:

vertexData = new GLfloat*[mesh_size];

CCD_ 4现在指向指向CCD_ 6的CCD_。请注意,这些指针未初始化。

然后,这些指针作为参数传递给一个函数:

przepare_mesh(..., vertexData[i], ...);

在函数内部,然后将一个值分配给函数参数(我将从原始代码中重命名参数,以避免在解释中混淆名称):

void przepare_mesh(..., GLfloat* vertices, ...)
{
    ...
    vertices = (GLfloat *)&paiMesh->mVertices;

由于指针是按值传递给函数的,因此此赋值只更改参数的本地值,而不会为最初传入的指针设置值。因此,当此函数返回时,vertexData[i]仍将未初始化。

稍后,vertexData[i]被用作glBufferData()的参数,并由于未初始化而导致崩溃。

解决此问题的最简单方法是将函数参数的声明更改为引用:

void przepare_mesh(..., GLfloat*& vertices, ...)

一旦参数是引用,在函数内部为其赋值将更改调用方传入的指针的值。

代码中还有其他相同问题的情况,我只是用第一个来说明这个问题。