I am trying to load 2 different meshes (a taurus and a monkey head) in my program. Both using the same load_mesh
function.
I used load_mesh
for the taurus in the init
function. The vertice data for this mesh was stored in g_pMeshVertices
. It looked like this.
Then I loaded a second one and it looked like this (below). The second mesh (monkey head) successfully appeared but half of the previous mesh disappeared.
What I did was I used the load_mesh
function again but for the "monkey head" inside init
. The vertices for the new mesh was also stored in g_pMeshVertices
. However, I created a new VBO and VAO to store the new vertices of g_pMeshVertices
but it seems to be affecting my previous mesh. Can someone tell me why?
Here is my code
#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);
}
Vertex shader
#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;
}
Fragment shader
#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;
}
The function load_mesh
reads data from a file and allocate dynamic memory and stores the read data in the following global variables:
Vertex* g_pMeshVertices = NULL;
GLint g_numberOfVertices = 0;
GLint* g_pMeshIndices = NULL;
GLint g_numberOfFaces = 0;
If you use the function load_mesh
a second time the data of the first using are overwritten. Apart from this, the allocated memory for g_pMeshVertices
and g_pMeshIndices
is not freed, what causes a memory leak.
In your code this does not cause any problem, since you immediately create an array buffer and an element array buffer where you bind the data, with the exception of g_numberOfFaces
which you need for drawing the mesh.
g_numberOfFaces
is to low for the whole cow mesh, because you first read the cow mesh and you 2nd read the monky mesh, and the monky mesh has less than indices, than the cow mesh (g_numberOfFaces
is overwirtten when reading the monky mesh).
I recommend to create a class
for the mesh data with a methode load_mesh
:
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 )
};
This allows you to instantiate a separate object for each mesh
CMesh monkey;
CMesh cow;
monkey.load_mesh("models/WusonOBJ.obj");
cow.load_mesh("models/suzanne.obj");
Apart from this, you should think about using a std::vector
instead of the dynamically allocated arrays:
#include <vector>
std::vector<Vertex> m_pMeshVertices;
std::vector<GLint> m_pMeshIndices;
Of course you can use an arrays instead:
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};
If you do so, you should add a new input parameter to the function load_mesh
which indicates the index of the mesh which is read.
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" );