OpenGL - 添加第二个网格后第一个网格消失

OpenGL - First mesh disappeared after second mesh was added

我正在尝试在我的程序中加载 2 个不同的网格(一个金牛座和一个猴头)。两者使用相同的 load_mesh 函数。

我在init函数中对金牛座使用了load_mesh。此网格的顶点数据存储在 g_pMeshVertices 中。看起来像这样。

然后我加载了第二个,它看起来像这样(下图)。第二个网格(猴头)成功出现,但前一个网格的一半消失了。 我所做的是再次使用 load_mesh 函数,但是 init 中的 "monkey head"。新网格的顶点也存储在 g_pMeshVertices 中。但是,我创建了一个新的 VBO 和 VAO 来存储 g_pMeshVertices 的新顶点,但它似乎影响了我以前的网格。谁能告诉我为什么?

这是我的代码

#define MAX_CUBES 6
#define MAX_PLANES 6

// struct for lighting properties
struct LightProperties
{
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    float shininess;
    vec3 attenuation;
    float cutoffAngle;
    vec3 direction;
};

// struct for material properties
struct MaterialProperties
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
};

LightProperties g_lightProperties;
MaterialProperties g_materialProperties;

// struct for vertex attributes
struct Vertex
{
    GLfloat position[3];
    GLfloat normal[3];
};

// Wall Vertices
Vertex g_vertices_plane[] = {
    -5.0f, -1.0f, 5.0f, // position
    0.0f, 1.0f, 0.0f,   // normal
    5.0f, -1.0f, 5.0f,  // position
    0.0f, 1.0f, 0.0f,   // normal
    -5.0f, -1.0f, -5.0f,// position
    0.0f, 1.0f, 0.0f,   // normal
    -5.0f, -1.0f, -5.0f,// position
    0.0f, 1.0f, 0.0f,   // normal
    5.0f, -1.0f, 5.0f,  // position
    0.0f, 1.0f, 0.0f,   // normal
    5.0f, -1.0f, -5.0f, // position
    0.0f, 1.0f, 0.0f,   // normal
};

Vertex g_vertices_cube[] = {
    // vertex 1
    -0.5f, 0.5f, 0.5f,  // position
    1.0f, 1.0f, 1.0f,   // normal
    // vertex 2
    -0.5f, -0.5f, 0.5f, // position
    1.0f, 1.0f, 1.0f,   // normal
    // vertex 3
    0.5f, 0.5f, 0.5f,   // position
    1.0f, 1.0f, 1.0f,   // normal
    // vertex 4
    0.5f, -0.5f, 0.5f,  // position
    1.0f, 1.0f, 1.0f,   // normal
    // vertex 5
    -0.5f, 0.5f, -0.5f, // position
    1.0f, 1.0f, 1.0f,   // normal
    // vertex 6
    -0.5f, -0.5f, -0.5f,// position
    1.0f, 1.0f, 1.0f,   // normal
    // vertex 7
    0.5f, 0.5f, -0.5f,  // position
    1.0f, 1.0f, 1.0f,   // normal
    // vertex 8
    0.5f, -0.5f, -0.5f, // position
    1.0f, 1.0f, 1.0f,   // normal
};

GLuint g_indices_cube[] = {
    0, 1, 2,    // triangle 1
    2, 1, 3,    // triangle 2
    4, 5, 0,    // triangle 3
    0, 5, 1,    // ...
    2, 3, 6,
    6, 3, 7,
    4, 0, 6,
    6, 0, 2,
    1, 5, 3,
    3, 5, 7,
    5, 4, 7,
    7, 4, 6,    // triangle 12
};

// Meshes
Vertex* g_pMeshVertices = NULL; // pointer to mesh vertices
GLint g_numberOfVertices = 0;   // number of vertices in the mesh
GLint* g_pMeshIndices = NULL;   // pointer to mesh indices
GLint g_numberOfFaces = 0;      // number of faces in the mesh

/*
    g_VBO[0] - Planes ie. walls, ceiling
    g_VBO[1] - Cubes ie. table, stools
    g_VBO[2] - Meshes (Taurus)
*/
GLuint g_IBO[3];                // index buffer object identifier
GLuint g_VBO[4];                // vertex buffer object identifier
GLuint g_VAO[4];                // vertex array object identifier
GLuint g_shaderProgramID = 0;   // shader program identifier

// locations in shader
GLuint g_MVP_Index;
GLuint g_M_Index = 0;
GLuint g_viewPointIndex = 0;
GLuint g_lightPositionIndex = 0;
GLuint g_lightAmbientIndex = 0;
GLuint g_lightDiffuseIndex = 0;
GLuint g_lightSpecularIndex = 0;
GLuint g_lightShininessIndex = 0;
GLuint g_lightAttenuationIndex = 0;
GLuint g_lightCutoffAngleIndex = 0;
GLuint g_lightDirectionIndex = 0;
GLuint g_materialAmbientIndex = 0;
GLuint g_materialDiffuseIndex = 0;
GLuint g_materialSpecularIndex = 0;

glm::mat4 g_modelMatrix_plane[MAX_PLANES];  // object's model matrix (4 walls + 1 ceiling + 1 floor)
glm::mat4 g_modelMatrix_cube[MAX_CUBES];// cube for table
glm::mat4 g_modelMatrix_mesh[2];        // for meshes
glm::mat4 g_viewMatrix;             // view matrix
glm::mat4 g_projectionMatrix;       // projection matrix
glm::vec3 g_viewPoint;              // view point

Camera g_camera;            // camera

GLuint g_windowWidth = 1600;        // window dimensions
GLuint g_windowHeight = 1000;
bool g_wireFrame = false;       // wireframe on or off

bool load_mesh(const char* fileName)
{
    // load file with assimp 
    const aiScene* pScene = aiImportFile(fileName, aiProcess_Triangulate
        | aiProcess_GenSmoothNormals | aiProcess_JoinIdenticalVertices);

    // check whether scene was loaded
    if (!pScene)
    {
        cout << "Could not load mesh." << endl;
        return false;
    }

    // get pointer to mesh 0
    const aiMesh* pMesh = pScene->mMeshes[0];

    // store number of mesh vertices
    g_numberOfVertices = pMesh->mNumVertices;

    // if mesh contains vertex coordinates
    if (pMesh->HasPositions())
    {
        // allocate memory for vertices
        g_pMeshVertices = new Vertex[pMesh->mNumVertices];

        // read vertex coordinates and store in the array
        for (int i = 0; i < pMesh->mNumVertices; i++)
        {
            const aiVector3D* pVertexPos = &(pMesh->mVertices[i]);

            g_pMeshVertices[i].position[0] = (GLfloat)pVertexPos->x;
            g_pMeshVertices[i].position[1] = (GLfloat)pVertexPos->y;
            g_pMeshVertices[i].position[2] = (GLfloat)pVertexPos->z;
        }
    }

    // if mesh contains normals
    if (pMesh->HasNormals())
    {
        // read normals and store in the array
        for (int i = 0; i < pMesh->mNumVertices; i++)
        {
            const aiVector3D* pVertexNormal = &(pMesh->mNormals[i]);

            g_pMeshVertices[i].normal[0] = (GLfloat)pVertexNormal->x;
            g_pMeshVertices[i].normal[1] = (GLfloat)pVertexNormal->y;
            g_pMeshVertices[i].normal[2] = (GLfloat)pVertexNormal->z;
        }
    }

    // if mesh contains faces
    if (pMesh->HasFaces())
    {
        // store number of mesh faces
        g_numberOfFaces = pMesh->mNumFaces;

        // allocate memory for vertices
        g_pMeshIndices = new GLint[pMesh->mNumFaces * 3];

        // read normals and store in the array
        for (int i = 0; i < pMesh->mNumFaces; i++)
        {
            const aiFace* pFace = &(pMesh->mFaces[i]);

            g_pMeshIndices[i * 3] = (GLint)pFace->mIndices[0];
            g_pMeshIndices[i * 3 + 1] = (GLint)pFace->mIndices[1];
            g_pMeshIndices[i * 3 + 2] = (GLint)pFace->mIndices[2];
        }
    }

    // release the scene
    aiReleaseImport(pScene);

    return true;
}

static void init(GLFWwindow* window)
{
    glEnable(GL_DEPTH_TEST);    // enable depth buffer test

    // create and compile our GLSL program from the shader files
    g_shaderProgramID = loadShaders("PerFragLightingVS.vert", "PerFragLightingFS.frag");

    // find the location of shader variables
    GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
    GLuint normalIndex = glGetAttribLocation(g_shaderProgramID, "aNormal");
    g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");
    g_M_Index = glGetUniformLocation(g_shaderProgramID, "uModelMatrix");
    g_viewPointIndex = glGetUniformLocation(g_shaderProgramID, "uViewPoint");

    g_lightPositionIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.position");
    g_lightAmbientIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.ambient");
    g_lightDiffuseIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.diffuse");
    g_lightSpecularIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.specular");
    g_lightShininessIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.shininess");
    g_lightAttenuationIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.attenuation");
    g_lightCutoffAngleIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.cutoffAngle");
    g_lightDirectionIndex = glGetUniformLocation(g_shaderProgramID, "uLightingProperties.direction");

    g_materialAmbientIndex = glGetUniformLocation(g_shaderProgramID, "uMaterialProperties.ambient");
    g_materialDiffuseIndex = glGetUniformLocation(g_shaderProgramID, "uMaterialProperties.diffuse");
    g_materialSpecularIndex = glGetUniformLocation(g_shaderProgramID, "uMaterialProperties.specular");

    // initialise model matrix to the identity matrix
    for (int i = 0; i < MAX_PLANES; i++) { g_modelMatrix_plane[i] = glm::mat4(1.0f); }
    for (int i = 0; i < MAX_CUBES; i++) { g_modelMatrix_cube[i] = glm::mat4(1.0f); }
    for (int i = 0; i < 2; i++) { g_modelMatrix_mesh[i] = glm::mat4(1.0f); }

...

// Model Matrices - Mesh
    g_modelMatrix_mesh[0] = glm::scale(glm::vec3(0.3f, 0.3f, 0.3f));
    g_modelMatrix_mesh[1] = glm::translate(glm::vec3(0.0f, 1.0f, 0.0f)) * glm::scale(glm::vec3(0.3f, 0.3f, 0.3f));

    // set camera's view matrix
    g_camera.setViewMatrix(glm::vec3(0, 0, 3), glm::vec3(0, 0, 2), glm::vec3(0, 1, 0));

    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    float aspectRatio = static_cast<float>(width) / height;

    // set camera's projection matrix
    g_camera.setProjectionMatrix(glm::perspective(45.0f, aspectRatio, 0.1f, 100.0f));

    // load mesh
    load_mesh("models/WusonOBJ.obj");

// initialise light and material properties
    g_lightProperties.position = glm::vec4(0.0f, 2.0f, 0.0f, 1.0f);
    g_lightProperties.ambient = glm::vec4(0.2f, 0.2f, 0.2f, 1.0f);
    g_lightProperties.diffuse = glm::vec4(0.0f, 0.5f, 1.0f, 1.0f);
    g_lightProperties.specular = glm::vec4(0.0f, 0.5f, 1.0f, 1.0f);
    g_lightProperties.shininess = 10.0f;
    g_lightProperties.attenuation = glm::vec3(1.0f, 0.0f, 0.0f);
    //g_lightProperties.cutoffAngle = 45.0f;
    g_lightProperties.cutoffAngle = 180.0f;
    g_lightProperties.direction = glm::vec3(0.0f, -1.0f, 0.0f);

// Material Properties - Planes
    // Floor
    g_materialProperties.ambient = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
    g_materialProperties.diffuse = glm::vec4(0.2f, 0.7f, 1.0f, 1.0f);
    g_materialProperties.specular = glm::vec4(0.2f, 0.7f, 1.0f, 1.0f);

    // generate identifier for VBOs and copy data to GPU
// Planes
    glGenBuffers(1, &g_VBO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices_plane), g_vertices_plane, GL_STATIC_DRAW);

    // generate identifiers for VAO
    glGenVertexArrays(1, &g_VAO[0]);

    // create VAO and specify VBO data
    glBindVertexArray(g_VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
    glVertexAttribPointer(normalIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)));

    glEnableVertexAttribArray(positionIndex);   // enable vertex attributes
    glEnableVertexAttribArray(normalIndex);

// Cube
    // generate identifier for VBOs and copy data to GPU
    glGenBuffers(1, &g_VBO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices_cube), g_vertices_cube, GL_STATIC_DRAW);

    // generate identifier for IBO and copy data to GPU
    glGenBuffers(1, &g_IBO[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices_cube), g_indices_cube, GL_STATIC_DRAW);

    // generate identifiers for VAO
    glGenVertexArrays(1, &g_VAO[1]);

    // create VAO and specify VBO data
    glBindVertexArray(g_VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[0]);
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
    glVertexAttribPointer(normalIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)));

    glEnableVertexAttribArray(positionIndex);   // enable vertex attributes
    glEnableVertexAttribArray(normalIndex);

// Meshes
    // Taurus Mesh
    // generate identifier for VBOs and copy data to GPU
    glGenBuffers(1, &g_VBO[2]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*g_numberOfVertices, g_pMeshVertices, GL_STATIC_DRAW);

    // generate identifier for IBO and copy data to GPU
    glGenBuffers(1, &g_IBO[1]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 3 * g_numberOfFaces, g_pMeshIndices, GL_STATIC_DRAW);

    // generate identifiers for VAO
    glGenVertexArrays(1, &g_VAO[2]);

    // create VAO and specify VBO data
    glBindVertexArray(g_VAO[2]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[1]);
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
    glVertexAttribPointer(normalIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)));

    glEnableVertexAttribArray(positionIndex);   // enable vertex attributes
    glEnableVertexAttribArray(normalIndex);

    // Suzanne Mesh
    load_mesh("models/suzanne.obj");

    // generate identifier for VBOs and copy data to GPU
    glGenBuffers(1, &g_VBO[3]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[3]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*g_numberOfVertices, g_pMeshVertices, GL_STATIC_DRAW);

    // generate identifier for IBO and copy data to GPU
    glGenBuffers(1, &g_IBO[2]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[2]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 3 * g_numberOfFaces, g_pMeshIndices, GL_STATIC_DRAW);

    // generate identifiers for VAO
    glGenVertexArrays(1, &g_VAO[3]);

    // create VAO and specify VBO data
    glBindVertexArray(g_VAO[3]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[3]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[2]);
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
    glVertexAttribPointer(normalIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)));

    glEnableVertexAttribArray(positionIndex);   // enable vertex attributes
    glEnableVertexAttribArray(normalIndex);
}

// function used to render the scene
static void render_scene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear colour buffer and depth buffer

    glUseProgram(g_shaderProgramID);    // use the shaders associated with the shader program

    glBindVertexArray(g_VAO[0]);        // make VAO active

// Material Properties - Planes
    glUniform4fv(g_materialAmbientIndex, 1, &g_materialProperties.ambient[0]);
    glUniform4fv(g_materialDiffuseIndex, 1, &g_materialProperties.diffuse[0]);
    glUniform4fv(g_materialSpecularIndex, 1, &g_materialProperties.specular[0]);

    glUniform4fv(g_lightPositionIndex, 1, &g_lightProperties.position[0]);
    glUniform4fv(g_lightAmbientIndex, 1, &g_lightProperties.ambient[0]);
    glUniform4fv(g_lightDiffuseIndex, 1, &g_lightProperties.diffuse[0]);
    glUniform4fv(g_lightSpecularIndex, 1, &g_lightProperties.specular[0]);
    glUniform1fv(g_lightShininessIndex, 1, &g_lightProperties.shininess);
    glUniform3fv(g_lightAttenuationIndex, 1, &g_lightProperties.attenuation[0]);
    glUniform1fv(g_lightCutoffAngleIndex, 1, &g_lightProperties.cutoffAngle);
    glUniform3fv(g_lightDirectionIndex, 1, &g_lightProperties.direction[0]);

    // set uniform shader variables
    glm::mat4 MVP = glm::mat4(1.0f);

...

// Draw Cubes
    // Table top + 4 Table legs
    for (int i = 0; i < (MAX_CUBES - 1); i++)
    {
        MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix_cube[i];
        glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
        glUniformMatrix4fv(g_M_Index, 1, GL_FALSE, &g_modelMatrix_cube[i][0][0]);
        glUniform3fv(g_viewPointIndex, 1, &g_viewPoint[0]);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type
    }

    // Chair (Right)
    for (int i = 0; i < MAX_CUBES; i++)
    {
        MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() 
            * glm::translate(glm::vec3(1.5f, -0.2f, 0.0f)) * glm::scale(glm::vec3(0.7f, 0.7f, 0.7f)) * g_modelMatrix_cube[i];
        glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
        glUniformMatrix4fv(g_M_Index, 1, GL_FALSE, &g_modelMatrix_cube[i][0][0]);
        glUniform3fv(g_viewPointIndex, 1, &g_viewPoint[0]);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type
    }
    // Chair (Left)
    for (int i = 0; i < MAX_CUBES; i++)
    {
        MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix()
            * glm::rotate(glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f))
            * glm::translate(glm::vec3(1.5f, -0.2f, 0.0f)) * glm::scale(glm::vec3(0.7f, 0.7f, 0.7f)) * g_modelMatrix_cube[i];
        glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
        glUniformMatrix4fv(g_M_Index, 1, GL_FALSE, &g_modelMatrix_cube[i][0][0]);
        glUniform3fv(g_viewPointIndex, 1, &g_viewPoint[0]);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type
    }

    glBindVertexArray(g_VAO[2]);        // make VAO active

// Draw Meshes
    // Taurus
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix_mesh[0];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glUniformMatrix4fv(g_M_Index, 1, GL_FALSE, &g_modelMatrix_mesh[0][0][0]);
    glUniform3fv(g_viewPointIndex, 1, &g_viewPoint[0]);
    glDrawElements(GL_TRIANGLES, g_numberOfFaces * 3, GL_UNSIGNED_INT, 0);  // display the vertices based on their indices and primitive type

    glBindVertexArray(g_VAO[3]);        // make VAO active

    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix_mesh[1];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glUniformMatrix4fv(g_M_Index, 1, GL_FALSE, &g_modelMatrix_mesh[1][0][0]);
    glUniform3fv(g_viewPointIndex, 1, &g_viewPoint[0]);
    glDrawElements(GL_TRIANGLES, g_numberOfFaces * 3, GL_UNSIGNED_INT, 0);  // display the vertices based on their indices and primitive type

    glFlush();  // flush the pipeline
}

int main(void)
{
    ...

    // create spotlight entries
    TwAddVarRW(TweakBar, "Cutoff", TW_TYPE_FLOAT, &g_lightProperties.cutoffAngle, " group='Spotlight' min=-180.0 max=180.0 step=1.0 ");
    TwAddVarRW(TweakBar, "Direction: x", TW_TYPE_FLOAT, &g_lightProperties.direction[0], " group='Spotlight' min=-1.0 max=1.0 step=0.1");
    TwAddVarRW(TweakBar, "Direction: y", TW_TYPE_FLOAT, &g_lightProperties.direction[1], " group='Spotlight' min=-1.0 max=1.0 step=0.1");
    TwAddVarRW(TweakBar, "Direction: z", TW_TYPE_FLOAT, &g_lightProperties.direction[2], " group='Spotlight' min=-1.0 max=1.0 step=0.1");

    // initialise rendering states
    init(window);

    // the rendering loop
    while (!glfwWindowShouldClose(window))
    {
        g_camera.update(window);    // update camera

        if (g_wireFrame)
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

        render_scene();     // render the scene

        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

        TwDraw();           // draw tweak bar(s)

        glfwSwapBuffers(window);    // swap buffers
        glfwPollEvents();           // poll for events
    }

...

    exit(EXIT_SUCCESS);
}

顶点着色器

#version 330 core

// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aNormal;

// uniform input data
uniform mat4 uModelViewProjectionMatrix;
uniform mat4 uModelMatrix;

// output data (will be interpolated for each fragment)
out vec3 vNormal;
out vec3 vPosition;

void main()
{
    // set vertex position
    gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);

    // world space
    vPosition = (uModelMatrix * vec4(aPosition, 1.0)).xyz;
    vNormal = (uModelMatrix * vec4(aNormal, 0.0)).xyz;
}

片段着色器

#version 330 core

// interpolated values from the vertex shaders
in vec3 vNormal;
in vec3 vPosition;

// uniform input data
struct LightProperties
{
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    float shininess;
    vec3 attenuation;
    float cutoffAngle;
    vec3 direction;
};

struct MaterialProperties
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
};

uniform LightProperties uLightingProperties;
uniform MaterialProperties uMaterialProperties;
uniform vec3 uViewPoint;

// output data
out vec3 fColor;

void main()
{
    // calculate vectors for lighting
    vec3 N = normalize(vNormal);
    vec3 L;
    float attenuation = 1.0f;

    // calculate the attenuation based on distance
    L = (uLightingProperties.position).xyz - vPosition;
    float distance = length(L);
    L = normalize(L);
    attenuation = 1/(uLightingProperties.attenuation.x 
        + uLightingProperties.attenuation.y * distance 
        + uLightingProperties.attenuation.z * distance * distance);

    vec3 V = normalize(uViewPoint - vPosition);
    vec3 R = reflect(-L, N);

    // the direction of the spotlight
    vec3 direction = normalize(uLightingProperties.direction);
    // the angle between the vector from the light to the fragment’s position and the spotlight’s direction
    float angle = degrees(acos(dot(-L, direction)));

    vec3 colour = vec3(0.0f, 0.0f, 0.0f);

    // only compute if angle is less than the cutoff angle
    if(angle <= uLightingProperties.cutoffAngle)
    {
        // calculate Phong lighting
        vec4 ambient  = uLightingProperties.ambient * uMaterialProperties.ambient;
        vec4 diffuse  = uLightingProperties.diffuse * uMaterialProperties.diffuse * max(dot(L, N), 0.0);
        vec4 specular = vec4(0.0f, 0.0f, 0.0f, 1.0f);

        if(dot(L, N) > 0.0f)
        {
            specular = uLightingProperties.specular * uMaterialProperties.specular 
                * pow(max(dot(V, R), 0.0), uLightingProperties.shininess);
        }

        colour = (attenuation * (diffuse + specular)).rgb + ambient.rgb;
        // fade the spotlight's intensity linearly with angle
        colour *= 1.0f - angle/uLightingProperties.cutoffAngle;
    }

    // set output color
    fColor = colour;    
}

在函数 static void render_scene() 中有两个具有相同数量索引的绘图调用,即 g_numberOfFaces * 3。猴子和金牛座的索引量很可能不同。

这可能不是唯一的错误。我的猜测是,这在某种程度上与索引有关,或者猴子覆盖了以前模型的一些数据。

我建议您制作 a minimal example 以便其他人更容易阅读您的代码。此外,您没有显示顶点着色器。

函数load_mesh从文件中读取数据并分配动态内存并将读取的数据存储在以下全局变量中:

Vertex* g_pMeshVertices = NULL;
GLint   g_numberOfVertices = 0;
GLint*  g_pMeshIndices = NULL;
GLint   g_numberOfFaces = 0;

如果您第二次使用函数load_mesh,第一次使用的数据将被覆盖。除此之外,为g_pMeshVerticesg_pMeshIndices分配的内存没有释放,导致内存泄漏的原因。

在您的代码中,这不会导致任何问题,因为您立即创建了一个数组缓冲区和一个绑定数据的元素数组缓冲区,但绘制网格所需的 g_numberOfFaces 除外。 g_numberOfFaces 对于整个 cow 网格来说太低了,因为你首先阅读了 cow 网格,然后你第二次阅读了 monky 网格,并且 monky 网格比 cow 网格(g_numberOfFaces 被覆盖在阅读 monky 网格时)。

我建议使用方法 load_mesh:

为网格数据创建一个 class
class CMesh
{
public:

    Vertex* m_pMeshVertices = nullptr;
    GLint   m_numberOfVertices = 0;
    GLint*  m_pMeshIndices = nullptr;
    GLint   m_numberOfFaces = 0;

    CMesh(void) {}
    virtual ~CMesh()
    {
      delete m_pMeshVertices;
      delete m_pMeshIndices;
    }

    bool load_mesh( const char* fileName )
};  

这允许您为每个网格实例化一个单独的对象

CMesh monkey;
CMesh cow;

monkey.load_mesh("models/WusonOBJ.obj");
cow.load_mesh("models/suzanne.obj");

除此之外,您应该考虑使用 std::vector 而不是动态分配的数组:

#include <vector>

std::vector<Vertex> m_pMeshVertices;
std::vector<GLint>  m_pMeshIndices;

答案的扩展

当然你可以改用数组:

const int c_noOfMesh = 2;
Vertex* g_pMeshVertices[c_noOfMesh]    = {nullptr}; 
GLint   g_numberOfVertices[c_noOfMesh] = {0};
GLint*  g_pMeshIndices[c_noOfMesh]     = {nullptr};   
GLint   g_numberOfFaces[c_noOfMesh]    = {0};

如果这样做,您应该向函数添加一个新的输入参数load_mesh,它指示读取的网格的索引。

bool load_mesh( int iMesh, const char* fileName )
{
    .....
    g_pMeshVertices[iMesh] = .....;
    g_numberOfVertices[iMesh] = .....;
    g_pMeshIndices[iMesh] = .....;
    g_numberOfFaces[iMesh] = .....;
    .....
}

load_mesh( 0, "models/WusonOBJ.obj" );
load_mesh( 1, "models/suzanne.obj" );