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_pMeshVertices
和g_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" );
我正在尝试在我的程序中加载 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_pMeshVertices
和g_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" );