Here is my shader program:
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 vertexNormal_modelspace;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
uniform mat3 blNormalMatrix;
uniform vec3 lightPos;
out vec4 forFragColor;
const vec3 diffuseColor = vec3(0.55, 0.09, 0.09);
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * diffuseColor;
// all following gemetric computations are performed in the
// camera coordinate system (aka eye coordinates)
vec3 vertexNormal_cameraspace = (V*M*vec4(vertexNormal_modelspace,0)).xyz;
vec4 vertexPosition_cameraspace4 = V*M* vec4(vertexPosition_modelspace,1);
vec3 vertexPosition_cameraspace = vec3(vertexPosition_cameraspace4).xyz;
vec3 lightDir = normalize(lightPos - vertexPosition_cameraspace);
float lambertian = clamp(dot(lightDir,vertexNormal_cameraspace), 0.0,1.0);
forFragColor = vec4(lambertian*diffuseColor , 1.0);
}
My problem is that this "worked" in the older opengl profile, didn't even have the version number, I think it was around Opengl 2.1 or so, the key change was that I originally had normal = gl_normalMatrix * gl_normal and things worked.
However that was based on my professor's code which I've updated to the 3.3+ core profile and after maybe fixing the deprecated functions I am now left with this:
https://drive.google.com/file/d/0B6oLZ_d7S-U7cVpkUXpVXzdaZEk/edit?usp=sharing is a link to the video of my program's behavior.
The light source should be a point light at (0,0,3) or so that shouldn't move; but its not following a particularly logical behaviorial pattern, I can't make sense of it.
I tried passing the inverse transpose of the model matrix and using them as a replacement normalMatrix but it wrecked my normals. So I don't know.
This was my normalMatrix:
glm::mat3 MyNormalMatrix = glm::mat3(glm::transpose(glm::inverse(ModelMatrix)));
Edit: Here is my Display code:
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
// Use our shader
glUseProgram(programID);
// Get our transformations iff we move the camera around.
glm::mat4 MyModelMatrix = ModelMatrix * thisTran * ThisRot;
MVP = ProjectionMatrix * ViewMatrix * MyModelMatrix;
glm::mat4 ModelView = ViewMatrix * MyModelMatrix;
glm::mat3 MyNormalMatrix = glm::mat3(glm::transpose(glm::inverse(ModelView)));
glm::vec3 newLightPos = lightPos;
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &MyModelMatrix[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glUniformMatrix4fv(BlNormalMatrix,1,GL_FALSE, &MyNormalMatrix[0][0]);
glUniformMatrix4fv(BlRotations, 1, GL_FALSE, &ThisRot[0][0]);
glUniform3f(BlCamera, cameraLoc.x, cameraLoc.y, cameraLoc.z);
glUniform3f(lPosition, newLightPos.x,newLightPos.y,newLightPos.z);
// VBO buffer: vertices
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2rd attribute buffer : normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
1, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// draw object using opengl 3.3 shit
glDrawArrays(GL_TRIANGLES, 0, vertices.size() );
The problem ultimately turned out to be an issue with the Model Loader provided by my Professor, was somehow incompatible with modern opengl and would only "mostly" work in that it was clearly missing the left/right normals or they had invalid values. Solved with using an implementation of Assimp.
The code, with assimp linked is like this:
void blInitResWAssimp() {
cout << "blInitResWAssimp" << endl;
blCreateModelViewProjectionMatrix();
//loads object
bool res = loadAssImp("Resources/RCSS-subdiv.obj", indices, indexed_vertices, indexed_uvs, indexed_normals);
//bool res = loadAssImp("Resources/cheb.obj", indices, indexed_vertices, indexed_uvs, indexed_normals);
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Load it into a VBO
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);
// Normal buffer
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);
// Generate a buffer for the indices as well
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);
//ModelMatrix = ModelMatrix * glm::translate(glm::mat4(1.0f), glm::vec3(-0.5, -0.5, 0));
}
Assimp stuff
bool loadAssImp(
const char * path,
std::vector<unsigned short> & indices,
std::vector<glm::vec3> & vertices,
std::vector<glm::vec2> & uvs,
std::vector<glm::vec3> & normals
){
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, 0/*aiProcess_JoinIdenticalVertices | aiProcess_SortByPType*/);
if (!scene) {
fprintf(stderr, importer.GetErrorString());
getchar();
return false;
}
const aiMesh* mesh = scene->mMeshes[0]; // In this simple example code we always use the 1rst mesh (in OBJ files there is often only one anyway)
const aiMaterial* material = scene->mMaterials[0];
// Fill vertices positions
vertices.reserve(mesh->mNumVertices);
for (unsigned int i = 0; i<mesh->mNumVertices; i++){
aiVector3D pos = mesh->mVertices[i];
vertices.push_back(glm::vec3(pos.x, pos.y, pos.z));
}
// Fill vertices texture coordinates
/*
uvs.reserve(mesh->mNumVertices);
for (unsigned int i = 0; i<mesh->mNumVertices; i++){
aiVector3D UVW = mesh->mTextureCoords[0][i]; // Assume only 1 set of UV coords; AssImp supports 8 UV sets.
uvs.push_back(glm::vec2(UVW.x, UVW.y));
}*/
// Fill vertices normals
normals.reserve(mesh->mNumVertices);
for (unsigned int i = 0; i<mesh->mNumVertices; i++){
aiVector3D n = mesh->mNormals[i];
//aiVector3D n = mesh->mVertices[i];
normals.push_back(glm::vec3(n.x, n.y, n.z));
}
// Fill face ind5ices
indices.reserve(3 * mesh->mNumFaces);
for (unsigned int i = 0; i<mesh->mNumFaces; i++){
// Assume the model has only triangles.
indices.push_back(mesh->mFaces[i].mIndices[0]);
indices.push_back(mesh->mFaces[i].mIndices[1]);
indices.push_back(mesh->mFaces[i].mIndices[2]);
}
// The "scene" pointer will be deleted automatically by "importer"
}
Related
I am using Assimp to load models to render in OpenGL but am running into an issue where chunks/pieces of a mesh don't render.
Example:
What model is supposed to look like:
What I end up rendering:
As you can see, some of the model is rendering properly, but not all.
I have verified multiple times that the meshes being loaded from assimp are loading the correct vertices and indices into my "Mesh" class. Here is my code for loading a model:
This function will recursively call itself for all child nodes and load each mesh inside the node. Each mesh will then be transformed into my own "Mesh" class by creating a vector of vertices and faces.
void Model::LoadAssimpNode(aiNode* node, const aiScene* scene)
{
// Process assimp meshes
for (unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
this->meshes.push_back(this->LoadAssimpMesh(mesh, scene));
}
// Recursivley processes child nodes
for (unsigned int i = 0; i < node->mNumChildren; i++)
{
this->LoadAssimpNode(node->mChildren[i], scene);
}
}
Mesh Model::LoadAssimpMesh(aiMesh* mesh, const aiScene* scene)
{
std::vector<sVertex> vertices;
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
sVertex vertex;
vertex.x = mesh->mVertices[i].x;
vertex.y = mesh->mVertices[i].y;
vertex.z = mesh->mVertices[i].z;
vertex.nx = mesh->mNormals[i].x;
vertex.ny = mesh->mNormals[i].y;
vertex.nz = mesh->mNormals[i].z;
if (mesh->mTextureCoords[0])
{
vertex.u0 = mesh->mTextureCoords[0][i].x;
vertex.v0 = mesh->mTextureCoords[0][i].y;
}
vertices.push_back(vertex);
}
std::vector<sTriangle> faces;
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
sTriangle face;
aiFace assimpFace = mesh->mFaces[i];
if (assimpFace.mNumIndices != 3)
{
std::cout << "Face is not a triangle!" << std::endl;
}
for (unsigned int j = 0; j < assimpFace.mNumIndices; j++)
{
face.vertIndex[j] = assimpFace.mIndices[j];
}
faces.push_back(face);
}
std::vector<Texture> textures;
if (mesh->mMaterialIndex >= 0)
{
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
// Sampler names should adhere to the following convention:
// Diffuse: texure_diffuseN
// Specular: texture_specularN
// Normal: texture_normalN
// Where N = texture numbers
for (Texture texture : this->LoadAssimpMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse"))
{
this->loadedTextures.insert(std::make_pair(texture.path.C_Str(), texture));
textures.push_back(texture);
}
for (Texture texture : this->LoadAssimpMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular"))
{
this->loadedTextures.insert(std::make_pair(texture.path.C_Str(), texture));
textures.push_back(texture);
}
}
return Mesh(vertices, faces, textures);
}
The sVertex and sTriangle structs are defined as:
struct sVertex
{
float x, y, z;
float nx, ny, nz;
float u0, v0;
};
struct sTriangle
{
unsigned int vertIndex[3];
};
Now that the model is effectively loaded from assimp, we now call the SetupMesh() function which sets up the meshes' respective VAO, VBO and EBO:
void Mesh::SetupMesh()
{
// Generate IDs for our VAO, VBO and EBO
glGenVertexArrays(1, &this->VAO);
glGenBuffers(1, &this->VBO);
glGenBuffers(1, &this->EBO);
glBindVertexArray(this->VAO);
// Now ANY state that is related to vertex or index buffer
// and vertex attribute layout, is stored in the 'state'
// of the VAO...
// Tell open GL where to look for for vertex data
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(sVertex), &this->vertices[0], GL_STATIC_DRAW);
// Tell open GL where our index buffer begins (AKA: where to look for faces)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->faces.size() * sizeof(sTriangle), &this->faces[0], GL_STATIC_DRAW);
// Set the vertex attributes for this shader
// Layout information can be found in the vertex shader, currently:
// 0 = position
// 1 = normals
// 2 = texture coordinates
glEnableVertexAttribArray(0); // position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(sVertex), (void*) offsetof(sVertex, x));
glEnableVertexAttribArray(1); // normal
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(sVertex), (void*) offsetof(sVertex, nx));
glEnableVertexAttribArray(2); // textureCoordinates
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(sVertex), (void*)offsetof(sVertex, u0));
// Now that all the parts are set up, unbind buffers
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
}
Once this is all setup, I will now call the Draw method for each mesh to render in my render loop:
void Mesh::Draw(const CompiledShader& shader)
{
glm::mat4 matModel = glm::mat4(1.0f);
glm::mat4 matTranslate = glm::translate(glm::mat4(1.0f), this->positionXYZ); // Translation matrix
glm::mat4 rotateX = glm::rotate(glm::mat4(1.0f), this->orientationXYZ.x, glm::vec3(1.0f, 0.0f, 0.0f)); // X axis rotation
glm::mat4 rotateY = glm::rotate(glm::mat4(1.0f), this->orientationXYZ.y, glm::vec3(0.0f, 1.0f, 0.0f)); // Y axis rotation
glm::mat4 rotateZ = glm::rotate(glm::mat4(1.0f), this->orientationXYZ.z, glm::vec3(0.0f, 0.0f, 1.0f)); // Z axis rotation
glm::mat4 matScale = glm::scale(glm::mat4(1.0f), glm::vec3(this->scale, this->scale, this->scale)); // Scale the mesh
glm::mat4 matInvTransposeModel = glm::inverse(glm::transpose(matModel));
// Apply all the transformations to our matrix
matModel = matModel * matTranslate;
matModel = matModel * rotateZ;
matModel = matModel * rotateY;
matModel = matModel * rotateX;
matModel = matModel * matScale;
glUseProgram(shader.ID);
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "matModel"), 1, GL_FALSE, glm::value_ptr(matModel)); // Tell shader the model matrix (AKA: Position orientation and scale)
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "matModelInverseTranspose"), 1, GL_FALSE, glm::value_ptr(matInvTransposeModel));
// Draw the mesh
glBindVertexArray(this->VAO);
glDrawElements(GL_TRIANGLES, this->faces.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
My shaders are very simple where the color of a pixel is equal to the vertex's normal:
Vertex Shader:
#version 420
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 textureCoordinates;
uniform mat4 matModel;
uniform mat4 matView;
uniform mat4 matProjection;
uniform mat4 matModelInverseTranspose; // For normal calculation
out vec4 fVertWorldLocation;
out vec4 fNormal;
out vec2 TextureCoordinates;
void main()
{
mat4 MVP = matProjection * matView * matModel;
gl_Position = MVP * vec4(position, 1.0f);
TextureCoordinates = textureCoordinates;
// The location of the vertex in "world" space (not screen space)
fVertWorldLocation = matModel * vec4(position, 1.0f);
// Calculate the normal based on any rotation we've applied.
// This inverse transpose removes scaling and tranlation (movement)
// from the matrix.
fNormal = matModelInverseTranspose * vec4(normal, 1.0f);
};
Fragment Shader:
#version 420
in vec2 TextureCoordinates;
in vec4 fNormal;
out vec4 Color;
uniform sampler2D texture_diffuse;
void main()
{
//Color = vec4(texture(texture_diffuse, TextureCoordinates));
//Color = vec4(TextureCoordinates, 1.0f, 1.0f);
Color = fNormal;
}
Sorry for the insane length of this post, but I feel that all of it was necessary to get my point across.
If anyone could point out what I am doing wrong here it would be greatly appreciated! I feel like I need an extra pair of eyes here because I have read my code over countless times and can't seem to come up with anything.
Made a stupid mistake, I was under the impression that the "count" argument in the glDrawElements() function wanted the number of faces NOT the number of indices.
The problem was fixed by changing my glDrawElements call from:
glDrawElements(GL_TRIANGLES, this->faces.size(), GL_UNSIGNED_INT, 0);
To this:
glDrawElements(GL_TRIANGLES, this->faces.size() * 3, GL_UNSIGNED_INT, 0);
I'm using SIFT algorithm and I want to draw lines between keypoints in differents image. I made it, but actually, all my lines have the same color so it's unreadable.
What I want to achieve is to set a random color to each line, but 1 and only 1 color to a line.
I have to use shaders to do that, and so I send LINES and POINTS (that is the color) to the same shader, and I don't know what's wrong in my code (I have a crash when trying to execute my code. EDIT : It is not that something is wrong in my code (well, obviously yes...) but the error cause a crash, like if I had a segmentation fault. So I think my errors is due to a wrong place allocation for my color array (because it worked without this array))
my code :
std::vector<GLfloat> points;
std::vector<glm::vec3> colors;
GLuint VAO, VBO[2];
void setupLines() {
glGenVertexArrays(1, &VAO);
glGenBuffers(2, &VBO[0]);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, points.size() * sizeof(GLfloat), &points[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), &colors[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
void draw() {
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glDrawArrays(GL_LINES, 0, points.size());
//The error occurs here, it seems...
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glDrawArrays(GL_POINTS, 0, colors.size());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
//for each points, we create the same colors 2by 2 so lines (that are 2 points) have the same colors
void addColor() {
for (int i = 0; i < points.size()/2; ++i) {
float a = rand() / (float)RAND_MAX;
float b = rand() / (float)RAND_MAX;
float c = rand() / (float)RAND_MAX;
colors.push_back(glm::vec3(a, b, c));
colors.push_back(glm::vec3(a, b, c));
}
}
and my vertex Shader :
#version 330 core
layout (location = 0) in vec2 aTexCoord;
layout (location = 1) in vec3 color;
out vec2 TexCoord;
out vec3 Col;
void main()
{
TexCoord = vec2(aTexCoord.xy);
Col = color;
}
and then I use Col in fragment shader to color.
Is it how I have to do this?
You have to set the current position gl_Position in the vertex shader.
The vertex coordinate has to be an attribute:
in vec3 aVertCoord;
and you have to assigne the coordinate to gl_Position:
gl_Position = vec4(aVertCoord.xyz, 1.0);
Note, for 2D coordinates it is should be something like:
in vec2 aVertCoord;
void main()
{
.....
gl_Position = vec4(aVertCoord.xy, 0.0, 1.0);
}
In final you have 2 vertex attributes. The vertex coordinates and the color. You do not need any texture coordinates, because you draw lines (GL_LINES). But I guess what you call aTexCoord is the vertex position, so you have to do it like this:
#version 330 core
layout (location = 0) in vec2 aTexCoord;
layout (location = 1) in vec3 color;
out vec3 TexCoord;
out vec3 Col;
void main()
{
gl_Position = vec4(aTexCoord.xy, 0.0, 1.0);
TexCoord = aTexCoord.xy;
Col = color;
}
The vertex array object VAO stores the states of the generic vertex attributes (glVertexAttribPointer, glEnableVertexAttribArray). The vertex attribute state may refer to a vertex array buffer. You have to bind the vertex array object VAO only, when you draw the object (lines):
void draw() {
glBindVertexArray(VAO);
int numberOfPoints = points.size() / 2; // Number of points, not the number of floats
glDrawArrays(GL_LINES, 0, numberOfPoints );
glBindVertexArray(0);
}
Note, it sufficient to call glDrawArrays one time.
Further, the 1st paramter of glVertexAttribPointer is the attribute index:
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), &colors[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1, // <---------------------------- attribute index
3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
Since you need one color per vertex coordinate, but you want every line to be drawn in a single color, you have to do it like this:
void addColor()
{
int numberOfPoints = points.size() / 2;
for (int i = 0; i < numberOfPoints/2; ++i)
{
glm::vec3 col(
rand() / (float)RAND_MAX,
rand() / (float)RAND_MAX,
rand() / (float)RAND_MAX);
colors.push_back(col);
colors.push_back(col);
}
}
There must be something wrong with how I'm implementing my VAOs and VBOs because my shader isn't getting any of the buffer data I'm allocating to it. It could be something to do with the location of the variables. I tried printing out the location value from glGetUniformLocation (my loc variable), and it printed out 4294967295 for every location value. I would think there's a different location for each of them. I also tried using the location (location = ...) values from the vertex shader and that didn't work either. Any extra insight would be greatly appreciated.
Here is my rendering code:
// load shaders and textures to the current context
glUseProgram(cloudShader);
glActiveTexture(cloudTexture);
glBindTexture(GL_TEXTURE_2D, cloudTexture);
glEnable(GL_POINTS);
glDisable(GL_DEPTH_TEST);
glPointSize(10.0f);
// initial velocity and start time buffer
GLuint vbo[3];
// texture position buffer
GLuint textPosBuf;
glGenBuffers(3, vbo);
//glGenBuffers(1, &textPosBuf);
// gen vao object
GLuint vao[3];
glGenVertexArrays(3, vao);
// define uniforms
glUniform4f(glGetUniformLocation(cloudShader, "color1"), color1.r, color1.g, color1.b, color1.a);
glUniform4f(glGetUniformLocation(cloudShader, "color2"), color2.r, color2.g, color2.b, color2.a);
glUniform3f(glGetUniformLocation(cloudShader, "Accel"), accel.x, accel.y, accel.z);
glUniform1f(glGetUniformLocation(cloudShader, "color1Wght"), color1Wght);
glUniform1f(glGetUniformLocation(cloudShader, "Time"), time);
glUniformMatrix4fv(glGetUniformLocation(cloudShader, "MVP"), 1, GL_FALSE, value_ptr(mat4(GL_PROJECTION_MATRIX) * mat4(GL_MODELVIEW_MATRIX)));
glUniform1i(glGetUniformLocation(cloudShader, "ParticleTex"), cloudTexture);
GLfloat *data = new GLfloat[nParticles * 3];
// I then set data ...
// bind vertex buffer data
// initial velocity data
glBindVertexArray(vao[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, nParticles * 3 * sizeof(GLfloat), reinterpret_cast<void*>(data), GL_DYNAMIC_DRAW);
// VertexInitVel attrib array pointer setup
GLuint loc = glGetUniformLocation(cloudShader, "VertexInitVel");
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
glEnableVertexAttribArray(loc);
// start time data
data = new GLfloat[nParticles];
// I then set the data...
// load start time buffer data
glBufferData(GL_ARRAY_BUFFER, nParticles * sizeof(GLfloat),
reinterpret_cast<void*>(data), GL_DYNAMIC_DRAW);
// InitStartTime attrib array pointer setup
loc = glGetUniformLocation(cloudShader, "StartTime");
glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, NULL, NULL);
glEnableVertexAttribArray(loc);
// buffer texture position data
data = new GLfloat[nParticles * 2];
// I then set the data...
glBindVertexArray(vao[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferSubData(GL_ARRAY_BUFFER, nParticles * sizeof(GLfloat),
nParticles * 2 * sizeof(GLfloat), reinterpret_cast<void*>(data));
loc = glGetUniformLocation(cloudShader, "texCoordIn");
cout << loc << endl;
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, NULL,
reinterpret_cast<void*>(nParticles * sizeof(GLfloat)));
glEnableVertexAttribArray(loc);
// buffer particle position data
data = new GLfloat[nParticles * 3];
// data gets set...
glBindVertexArray(vao[2]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, nParticles * 3 * sizeof(GLfloat), reinterpret_cast<void*>(data), GL_DYNAMIC_DRAW);
loc = glGetUniformLocation(cloudShader, "VertexStartPos");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
glDrawArrays(GL_POINTS, 0, nParticles);
// cleanup
....
Here is my vertex shader:
#version 450
// information to pass to the fragment shader
out vec2 texCoord; // texture coordinate to pass to fragment shader
out vec4 color1Pass;
out vec4 color2Pass;
out float color1WghtPass;
// Initial velocity and start time
layout (location = 0) in vec3 VertexInitVel;
layout (location = 1) in float StartTime;
layout (location = 2) in vec3 VertexStartPos; // where particle "respawns"
layout (location = 3) in vec2 texCoordIn;
// various values
uniform vec4 color1;
uniform vec4 color2;
uniform float color1Wght; // how strongly color1 is weighted
uniform float Time; // Animation time
uniform mat4 MVP;
uniform vec3 Accel; // Particle acceleration
out float Transp; // Transparency of the particle
const float ParticleLifetime = 10.0f; // Max particle lifetime
void main()
{
// Assume the initial position is as defined by Vertex Start Pos.
// vec3 pos = VertexStartPos;
vec3 pos = vec3(0.0);
Transp = 0.0;
// Particle doesn't exist until the start time
if( Time > StartTime ) {
float t = Time - StartTime;
// particle is born
if( t < ParticleLifetime ) {
pos = VertexInitVel * t + Accel * t * t;
Transp = 1.0 - t / ParticleLifetime;
}
}
color1Pass = color1;
color2Pass = color2;
color1WghtPass = color1Wght;
gl_Position = MVP * vec4(pos, 1.0);
}
I'm trying to use glDrawElements to draw a model loaded from assimp, geometry displays fine but textures dont show up on the model, i just get a black version of the model i've loaded.
Load Model Function
ModelInfo LoadModel(const std::string& modelPath){
printf( "Loading model: %s\n", modelPath.c_str());
//verify that file exists first
std::ifstream fin(modelPath.c_str());
if(!fin.fail()){
fin.close();
}else{
throw std::runtime_error("could not open file" + modelPath);
}
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile( modelPath,
aiProcessPreset_TargetRealtime_Fast |
//aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_GenSmoothNormals |
aiProcess_FlipUVs
//aiProcess_JoinIdenticalVertices |
//aiProcess_SortByPType);
);
if(!scene){
throw std::runtime_error(importer.GetErrorString());
}
printf("imported %s\n",modelPath.c_str());
fflush(stdout);
std::vector<unsigned int> indices;
std::vector<float> vertices;
std::vector<float> uvs;
std::vector<float> normals;
aiMesh* mesh = scene->mMeshes[0];
int numOfFaces = mesh->mNumFaces;
int numOfIndices = numOfFaces * 3;
indices.resize(numOfIndices);
for (unsigned int i =0; i < mesh->mNumFaces; ++i){
const aiFace &face = mesh->mFaces[i];
assert(face.mNumIndices == 3);
indices[i * 3 + 0] = face.mIndices[0];
indices[i * 3 + 1] = face.mIndices[1];
indices[i * 3 + 2] = face.mIndices[2];
}
int numOfVertices = mesh->mNumVertices;
vertices.resize(numOfVertices * 3);
normals.resize(numOfVertices * 3);
uvs.resize(numOfVertices * 2);
for( unsigned int i = 0; i < mesh->mNumVertices; ++i){
if(mesh->HasPositions()){
vertices[i * 3 + 0] = mesh->mVertices[i].x;
vertices[i * 3 + 1] = mesh->mVertices[i].y;
vertices[i * 3 + 2] = mesh->mVertices[i].z;
//printf("[ %f, %f, %f]\n",vertices[i*3+0],vertices[i*3+1],vertices[i*3+2]);
}
if( mesh->HasNormals()){
normals[i * 3 + 0] = mesh->mNormals[i].x;
normals[i * 3 + 1] = mesh->mNormals[i].x;
normals[i * 3 + 2] = mesh->mNormals[i].x;
}
if(mesh->HasTextureCoords(0)){
uvs[i * 2 + 0] = mesh->mTextureCoords[0][i].x;
uvs[i * 2 + 1] = mesh->mTextureCoords[0][i].y;
printf("[ %f, %f]\n",uvs[i*2+0],uvs[i*2+1]);
}
}
//create voa
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//create element buffer
GLuint elementBuffer;
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
//create vertex buffer
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(aiVector3D), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
printf("vertices.size is %lu\n", vertices.size());
printf("uvs.size is %lu\n", uvs.size());
GLuint uvBuffer;
glGenBuffers(1, &uvBuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(aiVector2D), &uvs[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0);
GLuint normalBuffer;
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(aiVector3D), &normals[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
ModelInfo retval;
retval.vao = vao;
retval.index = elementBuffer;
retval.vertex = vertexBuffer;
retval.uv = uvBuffer;
retval.normal = normalBuffer;
retval.count = numOfIndices;
return retval;
}
Short overview of Load Model, loads the model with assimp, then loads the data from the first mesh in the assimp scene into vectors, then creates a vao, vbos for geometry, texture coordinates, normals, and indexes. Data is then loaded into the buffers from the vectors and vertex attributes are set. Once all is loaded a struct containing several GLuints is created to return data.
Render Model function
void render_model(ModelInfo info){
cleanup();
//set program
glUseProgram(modelprogram);
//set uniforms
glm::mat4 view = camera.matrix();
glUniformMatrix4fv(modelcamera, 1, GL_FALSE, &view[0][0]);
glm::mat4 model = glm::mat4();
model = glm::rotate(model, degree, glm::vec3(0,1,1));
glUniformMatrix4fv(modelmodel, 1, GL_FALSE, &model[0][0]);
glBindVertexArray(info.vao);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(modeltext, texture);
glDrawElements(GL_TRIANGLES, info.count, GL_UNSIGNED_INT, (void*)0);
}
Brief overview of render model. Set the shader program to handle rendering the model, get matrix for the camera, pass it to the shader, generate a matrix for the model, make it spin, pass it to the shader. Bind the vao of the model to be rendered. Bind a previously loaded text, which is also used on other geometry in the program where it shows up no problem, pass it to the shader. all is set, call glDrawElements starting from the first position in the index buffer of the current vao. Once drawing is complete do clean up to unbind any buffers and arrays
the shaders i'm using for this are very basic
vertex shader
#version 140
uniform mat4 camera;
uniform mat4 model;
in vec3 position;
in vec2 uv;
out vec2 fragUV;
void main(){
//pass variables on to fragment shader
fragUV = uv;
//vertex to draw
gl_Position = camera * model * vec4(position,1);
}
fragment shader
#version 140
uniform sampler2D modeltext;
in vec2 fragUV;
out vec4 finalColor;
void main(){
finalColor = texture(modeltext, fragUV);
}
All uniforms are loaded correctly with a function that verifies that something was actually loaded, the texture is used and works else where in the program. The model has texture coordinates. The geometry is loading and rendering no problem
You are passing the wrong value to the sampler uniform.
glBindTexture (GL_TEXTURE_2D, texture);
glUniform1i (modeltext, texture);
Sampler uniforms do not take the name (ID) of a texture object, they take the index of the Texture Image Unit that you bound your texture to. In this example, you appear to be using the default Texture Image Unit: GL_TEXTURE0, so the value that your sampler uniform should use is 0.
Because a sampler2D actually expects the Texture Image Unit and not the name of a texture, you never have to change this uniform when you change the bound texture. GLSL will always sample whatever texture is bound to the corresponding Texture Image Unit (assuming they have compatible types / states).
This means that generally you set sampler uniforms once when you initialize your GLSL program and never touch it again. In newer versions of GLSL (4.20) you can even hard-code the Texture Image Unit that a sampler uses in the shader itself, but since you are using GLSL 1.40 you do not have this option unless the extension: GL_ARB_shading_language_420pack is supported.
Consider the following code, which correctly demonstrates how to use sampler uniforms:
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture);
glUniform1i (modeltext, 0);
I have included the redundant call to glActiveTexture (...) merely to demonstrate how the uniform sampler and active texture unit are related... you do not pass the constant GL_TEXTURE0 to a sampler, instead you use the integer index. GL_TEXTURE0 is the default active texture unit.
I'm currently trying to set up a GPU skinning (with glsl) but it's not working the way I would :) Actually it's not working at all. My mesh disappear when I try this glsl code :
layout(location = 0) in vec3 vertexPos;
layout(location = 1) in vec2 vertexUv;
layout(location = 2) in vec3 vertexNor;
layout(location = 5) in ivec4 joints_influences;
layout(location = 6) in vec4 weights_influences;
uniform mat4 ViewProj, View, Proj, Model;
out vec3 vertexPosEye;
out vec3 vertexNorEye;
const int MAX_INFLUENCES = 4;
const int MAX_BONES = 50;
uniform mat4 animation_matrices[MAX_BONES];
uniform mat4 inv_bind_matrices[MAX_BONES];
void main()
{
vertexPosEye = (View * Model * vec4(vertexPos, 1)).xyz; // Position
vertexNorEye = (View * Model * vec4(vertexNor, 0)).xyz; // Normal matrix
vec4 final_v = vec4(0, 0, 0, 0);
for (int i = 0; i < MAX_INFLUENCES; i++)
{
vec4 v = vec4(vertexPos, 1)
* inv_bind_matrices[joints_influences[i]]
* animation_matrices[joints_influences[i]]
* weights_influences[i];
final_v += v;
}
gl_Position = ViewProj * Model * final_v;
}
when I try this :
gl_Position = ViewProj * Model * vertexPos;
My mesh is back :) but no animations anymore of course...
Here's my application (c++) code when I set VBO attributes :
// Vertex position
glGenBuffers(1, &buffer[0]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ARRAY_BUFFER, vertices.pos.size() * sizeof(bVector3), &vertices.pos[0], GL_STATIC_DRAW);
// Ibid for uv, normals, tangents and bitangents.
// Skinning : joints index
glGenBuffers(1, &buffer[5]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[5]);
glBufferData(GL_ARRAY_BUFFER, vertices.joints.size() * sizeof(SkinningJoints), &vertices.joints[0], GL_STATIC_DRAW);
// Skinning : weights
glGenBuffers(1, &buffer[6]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[6]);
glBufferData(GL_ARRAY_BUFFER, vertices.weights.size() * sizeof(SkinningWeights), &vertices.weights[0], GL_STATIC_DRAW);
// Indices
glGenBuffers(1, &buffer[7]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[7]);
glBufferData(GL_ARRAY_BUFFER, vertices.indices.size() * sizeof(bUshort), &vertices.indices[0], GL_STATIC_DRAW);
In the main loop :
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(0));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(for uv, normals, tangents and bitangents)...
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(5));
glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(6);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(6));
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->GetBuffer(7));
glDrawElements(GL_TRIANGLES, m->vertices.indices.size(), GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
Here is my RenderingVertices struct (after Barr's recomendations):
struct RenderingVertices
{
// std::vector<Vec3>
vVec3 pos, nor, tang, btan;
vVec2 uv;
vUshort indices;
vector<SkinningJoints> joints;
vector<SkinningWeights> weights;
};
And here is my SkinningJoints struct :
struct SkinningJoints
{
int j[MAX_BONES_PER_VERT];
SkinningJoints(Vertex::Weights weights[MAX_BONES_PER_VERT])
{
for (bUint i = 0; i < MAX_BONES_PER_VERT; i++)
j[i] = weights[i].jid;
}
};
My SkinningWeights struct is almost the same, with an array of float instead of int.
Now when I try to debug the joints index, weights values and final vertex as colors, here is what I get :
// Shader
color_debug = joints_influences;
http://www.images-host.fr/view.php?img=00021800pop.jpg
color_debug = weights_influences;
http://www.images-host.fr/view.php?img=00021800pop2.jpg
Another interesting thing, when I try this :
vec4 pop = vec4(vertexPos, 1) * animation_matrices[1] * inv_bind_matrices[1] * 1.0;
gl_Position = ViewProj * Model * pop;
My all mesh is actually rotating, which means that my uniform animation_matrices is good.
Anyone can see what i'm doing wrong here ?
I finally got it working. For those who may be interested, here is what I was doing wrong :
When I send joints indices array to Glsl, instead of doing this:
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(5));
glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, 0, BUFFER_OFFSET(0));
I needed to do this:
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, m->GetBuffer(5));
glVertexAttribIPointer(5, 4, GL_INT, 0, BUFFER_OFFSET(0));
You have to look closely to find the difference. Instead of calling glVertexAttribPointer(), I needed to call glVertexAttribIPointer() because joints indices are int.
Hope this will help someone someday.
Did you try debugging your skinning attributes? Output the vertex weight as colors so that you can confirm you have meaningful values? If everything is black you'll know where to look.
From a quick glance at your RenderingVertices I can spot a first problem. You are passing a Vector of pointers to GL which I don't think is what you want to do.
Most of the time you will limit skinning influences to 4 joint/weight pairs per vertex. So you can get away with a simple array (ie. SkinningJoints joints[4];).