C++: OpenGL: Drawing multiple geometries - c++

i am programming a Super-Hyper-Mega-Lydian-Über-3D-Game and i am struggling to draw multiple geometries one after another.
Drawing a single geometrie works fine, however if i am trying to draw more than one the geometries switch their vertex-data and their shader-program; or they switch positions and rotational-axis. This is how it looks if i draw one cube:
http://i.imgur.com/zmTPc0h.png
This is how it looks like if i draw a spaceship after that cube:
http://i.imgur.com/10HDjm9.png
Here is my code for this application:
void MainLoop::loop()
{
VisibleObject cube("cube.obj", "vertexShader.glsl", "fragmentShaderCube.glsl");
cube.coordinates = glm::vec3(0.0f, 5.0f, -10.0f);
VisibleObject spaceship("spaceship.obj", "vertexShader.glsl", "fragmentShader.glsl");
spaceship.actualAxisOfRotation = glm::vec3(1.0f, 0.0f, 0.0f);
while (gameState != GAMESTATE_EXITING)
{
//check for input
while (SDL_PollEvent(&evnt))
{
switch (evnt.type)
{
case SDL_QUIT:
gameState = GAMESTATE_EXITING;
break;
default:
break;
}
}
//clear depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
spaceship.draw();
cube.draw();
//display result
SDL_GL_SwapWindow(window);
}
}
class VisibleObject
{
public:
VisibleObject(std::string modelPath, std::string vertexShaderPath, std::string fragmentShaderPath);
~VisibleObject();
void cleanup();
void draw();
glm::vec3 coordinates; //1.0f = 1.0 meter
glm::vec3 actualAxisOfRotation;
GLfloat actualRotation; //radians off the originposition
glm::vec3 velocity; //meters per second
glm::vec3 axisOfRotation;
GLfloat rotationSpeed; //radians per second
private:
short numberOfIndices;
std::vector<short> indices;
short numberOfVertices;
std::vector<glm::vec3> vertices;
glm::mat4 fullMatrix;
GLuint fullMatrixUniformLocation;
GLuint shaderProgramID;
GLuint vertexBufferID;
GLuint indexBufferID;
GLuint vertexArrayObjectID;
};
VisibleObject::VisibleObject(std::string modelPath, std::string vertexShaderPath, std::string fragmentShaderPath)
{
coordinates = glm::vec3(0.0f, 0.0f, -10.0f);
actualAxisOfRotation = glm::vec3(0.0f, 1.0f, 0.0f);
actualRotation = 2.0f;
velocity = glm::vec3(0.0f, 0.0f, 0.0f);
axisOfRotation = glm::vec3(0.0f, 1.0f, 0.0f);
rotationSpeed = 0.0f;
//create shader-program
shaderProgramID = GlslUtilities::installShader(vertexShaderPath, fragmentShaderPath);
//create transformation-matrix-uniform
fullMatrixUniformLocation = glGetUniformLocation(shaderProgramID, "f_matrix");
//load model data
numberOfIndices = 0;
numberOfVertices = 0;
indices.clear();
vertices.clear();
something_that_works_and_loads_the_vertex_and_index_data_from_an_obj-file_into_the_vectors();
//sending data to opengl
glGenVertexArrays(1, &vertexArrayObjectID);
glGenBuffers(1, &indexBufferID);
glGenBuffers(1, &vertexBufferID);
glBindVertexArray(vertexArrayObjectID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vertices[0]), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(indices[0]), &indices[0], GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
VisibleObject::~VisibleObject()
{
}
void VisibleObject::cleanup()
{
glUseProgram(0);
glDeleteProgram(shaderProgramID);
glDeleteBuffers(1, &vertexBufferID);
glDeleteBuffers(1, &indexBufferID);
glDeleteBuffers(1, &vertexArrayObjectID);
}
void VisibleObject::draw()
{
glBindVertexArray(vertexArrayObjectID);
fullMatrix = glm::perspective(glm::radians(85.0f), 800.0f / 600, 0.1f, 150.0f);
fullMatrix = glm::translate(fullMatrix, coordinates);
fullMatrix = glm::rotate(fullMatrix, glm::radians(((float)SDL_GetTicks())/10), actualAxisOfRotation);
glUniformMatrix4fv(fullMatrixUniformLocation, 1, GL_FALSE, &fullMatrix[0][0]);
glUseProgram(shaderProgramID);
glDrawElements(GL_TRIANGLES, numberOfIndices, GL_UNSIGNED_SHORT, 0);
}

You are uploading the fullMatrix to the shader before binding the shader. Since glMatrix4fv calls always operate on the currently bound shader, you are using wrong matrices when drawing.
Solution: Call the functions in the correct order
glUseProgram(shaderProgramID);
glUniformMatrix4fv(fullMatrixUniformLocation, 1, GL_FALSE, &fullMatrix[0][0]);
glDrawElements(GL_TRIANGLES, numberOfIndices, GL_UNSIGNED_SHORT, 0);

Related

OPENGL flickering on updating model uniform to same value

I have looked up almost all related questions regarding flickering in opengl. They all mostly have something to do with z-buffer or perspective projection. However, I'm rendering a single quad on screen that too without depth testing. I update model uniform every frame to the same value and then I get flickering. However if I have my object translate around the screen by updating uniform then it all works fine.
mat4 model = mat4_identity();
model = mat4_translatev(make_vec3(100.0f, 200.0f, 0.0f));
vec4 color = make_vec4(1.0f, 0.8f, 0.7f, 1.0f);
mat4 projection = mat4_ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f);
Shader shader("generic_shader.vs", "generic_shader.fs");
shader.use();
//shader.set_vec4("color", &color);
shader.set_mat4("model", &model);
shader.set_mat4("projection", &projection);
float vertices[] = {
0.0f, 0.0f,
0.0f, 200.0f,
200.0f, 0.0f,
200.0f, 200.0f,
};
unsigned int indices[] = {
0, 1, 2,
2, 1, 3,
};
unsigned int vao, vbo, ebo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
float currentFrame = static_cast<f32>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
while(deltaTime < REQUIRED_FRAME_TIME)
{
currentFrame = static_cast<f32>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
}
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
glDisable(GL_DEPTH_TEST);
glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
//model = mat4_translatev(make_vec3(16.0f * currentFrame, 12.0f * currentFrame, 0.0f)); // <- if I uncomment this then it does not flicker
shader.set_mat4("model", &model);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glfwPollEvents();
glfwSwapBuffers(window);
}
This is what shader.use does
void Shader::use()
{
glUseProgram(this->program_id);
}
My matrices are column major and this is how the shader function sets the uniform
void Shader::set_mat4(const char* uniform_name, mat4* value)
{
*value = mat4_transpose(*value);
glUniformMatrix4fv(glGetUniformLocation(this->program_id, uniform_name), 1, GL_TRUE, &value->E[0][0]);
}
processInput() doesn't do anything. Consider it as an empty body function.
I'm using my own math library for vector and matrix operations. I trying to learn opengl and have made notes on things I have learned. I hope someone already familiar with how opengl works can help me understand what is happening here.
A gif depicting the flickering. Please note the flickering stops if I uncomment that one line in code as marked above.
Flickering GIF
The problem is not with the OpenGL part of your code, but with the way how you transpose your model matrix.
The following code
*value = mat4_transpose(*value);
will override value with it's transposed representation, which means that every second frame the screen is rendered with a wrong matrix. Stop storing the result in value (use a local variable) and everything should work.

How to draw a line along the Z axis in openGL

I'm stuck drawing a line along the Z-axis. I have checked the related topic that OpenGL Can't draw z axis but even if I change my camera position, I still can't see my line; meanwhile, I can see a square draw in XZ-plane.
here is my code:
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
GLFWwindow* window = glfwCreateWindow(1024, 768, "some program", NULL, NULL);
glfwMakeContextCurrent(window);
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to create GLEW" << std::endl;
glfwTerminate();
return -1;
}
glClearColor(0.2f, 0.298f, 0.298f, 1.0f);
// Compile and link shaders here ...
int shaderProgram = compileAndLinkShaders();
int lineVao = createLineVertexArrayObject(LineArray, sizeof(LineArray));
while (!glfwWindowShouldClose(window))
{
GLuint worldMatrixLocation = glGetUniformLocation(shaderProgram, "worldMatrix");
// Each frame, reset color of each pixel to glClearColor
glClear(GL_COLOR_BUFFER_BIT);
glm::mat4 translationMatrix = glm::mat4(1.0f);
glUniformMatrix4fv(worldMatrixLocation, 1, GL_FALSE, &translationMatrix[0][0]);
glUseProgram(shaderProgram);
glBindVertexArray(lineVao);
glDrawArrays(GL_LINES, 0, 2);
glBindVertexArray(0);
glfwSwapBuffers(window);
// Detect inputs
glfwPollEvents();
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS)//see the object in other direction
{
glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.0f, 1.0f, 0.0f), // eye
glm::vec3(0.0f, 0.0f, -1.0f), // center
glm::vec3(0.0f, 1.0f, 0.0f));// up
GLuint viewMatrixLocation = glGetUniformLocation(shaderProgram, "viewMatrix");
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]);
}
}
// Shutdown GLFW
glfwTerminate();
return 0;
}
int createLineVertexArrayObject()
int createLineVertexArrayObject(const glm::vec3* vertexArray, int arraySize)
{
// Create a vertex array
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// Upload Vertex Buffer to the GPU, keep a reference to it (vertexBufferObject)
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, arraySize, vertexArray, GL_STATIC_DRAW);
glVertexAttribPointer(0, // attribute 0 matches aPos in Vertex Shader
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
2 * sizeof(glm::vec3), // stride - each vertex contain 2 vec3 (position, color)
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, // attribute 1 matches aColor in Vertex Shader
2,
GL_FLOAT,
GL_FALSE,
2 * sizeof(glm::vec3),
(void*)sizeof(glm::vec3) // color is offseted a vec3 (comes after position)
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
return vertexArrayObject;
}
my lineArray[] was like this
glm::vec3 LineArray[] = {
glm::vec3(-0.5f, 0.0f, -0.5f), // position
glm::vec3(1.0f, 0.0f, 0.0f), // color (yellow)
glm::vec3(0.0f, 0.0f, 0.0f), // position
glm::vec3(1.0f, 0.0f, 0.0f), // color (yellow)
};
But I can only see a horizontal line if I change my camera position.
Assuming that you want to draw a 3D line, the size argument of glVertexAttribPointer is wrong. By setting it to two, you tell OpenGL to read only two values and add 0 for z.
Set the size to 3 as in
glVertexAttribPointer(0, // attribute 0 matches aPos in Vertex Shader
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
2 * sizeof(glm::vec3), // stride - each vertex contain 2 vec3 (position, color)
(void*)0 // array buffer offset
);
and the z-value will also be read.
Note, that your color binding has the same problem. You only read the read and green value, but not the blue value.

OpenGL Move One Of My Two Shapes

I'm creating a game in SDL where everything has to be drawn in OpenGL. I've drawn two shapes with different textures and added keyboard controls. My problem is only my Player textured shape should be controllable but instead both of my shapes are stuck together and the vector I thought controlled the enemy position doesn't. Is my problem when I draw? How do I make it so I my player controls only move the player shape.
//Declare transform and model matrix.
glm::mat4 Model; glm::mat4 Rotation; glm::mat4 View;
glm::mat4 Projection;
glm::vec3 Player = glm::vec3(2.0f, 0.5f, -1.0f);
GLfloat playermovespeed = 0.1f;
Projection = glm::ortho(0.0f, 4.0f, 0.0f, 3.0f, -1.0f, 100.0f);
Model = glm::translate(Model, Player);
GLint ProjectionLocation = glGetUniformLocation(shaderProgram, "ProjectionMat");
glUniformMatrix4fv(ProjectionLocation, 1, GL_FALSE, glm::value_ptr(Projection));
SDL_GetWindowSize(window, &w, &h); glViewport(0, 0, w, h);
while (WindowOpen)
{
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture[0]);
Model = glm::mat4();
Model = glm::translate(Model, glm::vec3(0.0f, 15.0f, 5.0f)); //Position of enemy shape
GLint ModelLocation = glGetUniformLocation(shaderProgram, "ModelMat");
GLint ViewLocation = glGetUniformLocation(shaderProgram, "ViewMat");
//glUniformMatrix4fv(ModelLocation, 1, GL_FALSE, glm::value_ptr(Model*Rotation));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//Player texture
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, textureA);
Model = glm::mat4(); //y
Model = glm::translate(Model, Player); //Position control of ship.
ModelLocation = glGetUniformLocation(shaderProgram, "ModelMat");
glUniformMatrix4fv(ModelLocation, 1, GL_FALSE, glm::value_ptr(Model));
glUniformMatrix4fv(ViewLocation, 1, GL_FALSE, glm::value_ptr(View));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
SDL_GL_SwapWindow(window);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
WindowOpen = false;
if (event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_RIGHT:
Player.x += playermovespeed;
break;
case SDLK_LEFT:
Player.x -= playermovespeed;
break;
default:
break;
}
}
}
}
}
But just in case here is also how I set up everything.
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // Top Right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
};
GLuint indices[] = { start from 0!
0, 1, 3,
1, 2, 3,
};
//Load image Enemy; //Load image Player; //Load shaders;
GLuint VBO;
glGenBuffers(1, &VBO);
GLuint EBO;
glGenBuffers(1, &EBO);
GLuint texture[2];
glGenTextures(2, texture);
glBindTexture(GL_TEXTURE_2D, texture[0]);
//set texture parameters. First texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
SDL_FreeSurface(image);
//Second texture same way as first; //Set texture parameters
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);

delete array in C++ causing program crash

I am following along with a youtube tutorial concerning opengl (a graphics programming library). I've created classes called vertex, ShapeData and ShapeGenerator. The overall idea is I'm creating code which will hold data for any type of shape I decide to come up with and want to display to the screen. The problem is my program seems to crash once the first "delete[]" is hit within ShapeData.h in the cleanup() function. Here is the relevant code:
Vertex.h
#pragma once
#include "GLM/glm.hpp"
class Vertex
{
public:
Vertex();
Vertex(glm::vec3 thePosition, glm::vec3 theColor);
glm::vec3 position;
glm::vec3 color;
};
Vertex.cpp
#include "Vertex.h"
Vertex::Vertex()
{}
Vertex::Vertex(glm::vec3 thePosition, glm::vec3 theColor) :
position(thePosition),
color(theColor)
{
}
ShapeData.h
#pragma once
#include "Vertex.h"
#include "GL/glew.h"
struct ShapeData
{
ShapeData() :
verticies(0), numberOfVerts(0),
indicies(0), numberOfIndicies(0)
{}
Vertex* verticies;
GLuint numberOfVerts;
GLushort* indicies;
GLuint numberOfIndicies;
GLsizeiptr VertexBufferSize() const
{
return numberOfVerts * sizeof(Vertex);
}
GLsizeiptr IndexBufferSize() const
{
return numberOfIndicies * sizeof(GLushort);
}
void CleanUp()
{
delete[] verticies;
delete[] indicies;
verticies = 0;
indicies = 0;
numberOfIndicies = 0;
numberOfVerts = 0;
}
};
ShapeGenerator.cpp
#include "ShapeGenerator.h"
ShapeData ShapeGenerator::MakeTriangle()
{
Vertex triangle[] = {
Vertex(glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
Vertex(glm::vec3(-1.0f, -1.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
Vertex(glm::vec3(1.0f, -1.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f))
};
ShapeData shapeData;
shapeData.numberOfVerts = sizeof(triangle) / sizeof(*triangle);
shapeData.verticies = new Vertex[shapeData.numberOfVerts];
memcpy(shapeData.verticies, triangle, sizeof(triangle));
shapeData.verticies = triangle;
GLushort indicies[] = { 0,1,2 };
shapeData.numberOfIndicies = sizeof(indicies) / sizeof(*indicies);
shapeData.indicies = new GLushort[shapeData.numberOfIndicies];
memcpy(shapeData.indicies, indicies, sizeof(indicies));
return shapeData;
}
I'm trying to create a triangle and everything works fine without running the cleanup() function within main. Here is the portion where I'm calling Cleanup() in main:
main.cpp
ShapeData triangle = ShapeGenerator::MakeTriangle();
GLuint bufferID;
glGenBuffers(1, &bufferID);
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glBufferData(GL_ARRAY_BUFFER, triangle.VertexBufferSize(), triangle.verticies, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (char*)(sizeof(float) * 3));
GLuint indexBufferID;
glGenBuffers(1, &indexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangle.IndexBufferSize(),triangle.indicies, GL_STATIC_DRAW);
triangle.CleanUp();
You are replacing the new[]'d pointer here. This causes a crash because triangle is not new[]'d.
shapeData.verticies = new Vertex[shapeData.numberOfVerts];
memcpy(shapeData.verticies, triangle, sizeof(triangle));
shapeData.verticies = triangle;

Program Specific OpenGL Runtime Bug: Multiple Input Buffers For Skinned Animation

The Problem:
It seems as if the second GLuint buffer is not being read in properly.
Update: So the problem must be when I try to input the data to the shader. I rewrote the code (the old code is still below) to use swizzling for the index parameter. That was the only way I could get it to work. I would like to use multiple glVertexAttribPointer's, but every time I try to gives me the same undefined results.
What I Am Trying To Do:
I'm testing out very simple skinned animation with a very simplified shader,
#version 330 core
in vec2 model;
in uint jointID;
const int MAX_JOINTS = 10;
uniform mat4 joints[MAX_JOINTS];
void main()
{
gl_Position = joints[jointID] * vec4(model, 0.0f, 1.0f);
}
I input some simple data,
const GLfloat vertices[] =
{
// upper arm
0.0f, 0.0f,
0.4f, 0.0f,
0.4f, 0.2f,
0.0f, 0.0f,
0.4f, 0.2f,
0.0f, 0.2f,
// lower arm
0.4f, 0.0f,
0.8f, 0.0f,
0.8f, 0.2f,
0.4f, 0.0f,
0.8f, 0.2f,
0.4f, 0.2f
};
const GLuint indices[] =
{
// upper arm
0,
1,
1,
0,
1,
0,
// lower arm
1,
1,
1,
1,
1,
1
};
(The first array containing the vertices and the second array containing the corresponding boneID's.) Oddly, the boneID's never seem too equal 1 because when I make the matrix at index 1 some really funky value, the vertices remain untransformed. This leads me to believe that it is a problem with the way I set up my glVertexAttribPointer's,
void SkinnedModel::draw()
{
shaderProgram.use();
glEnableVertexAttribArray(modelLoc);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(modelLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(jointIDLoc);
glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
glUniformMatrix4fv(jointsLoc, 10, GL_FALSE, (GLfloat*)&poseMatrices);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glDisableVertexAttribArray(modelLoc);
glDisableVertexAttribArray(jointIDLoc);
}
I've been banging my head against the desk for the past few hours looking at what seems to be correct code. Anyway, it's probably something dumb I missed. Any help is appreciated.
Here is all the relevant source code (just in case):
SkinnedModel.h
#pragma once
#include "stl/DataTypes.h"
#include "Shader.h"
#include <Dense>
using namespace Eigen;
struct Joint
{
Joint** children;
Joint* parent;
U32 index;
};
class SkinnedModel
{
public:
static void init();
static void destroy();
SkinnedModel();
~SkinnedModel();
void create(const GLfloat* vertices, const GLuint* jointIndices, GLint numVertices, Joint* rootJoint);
void draw();
void rotate(Joint* joint, F32 angle, F32 x, F32 y);
GLuint vertexBuffer;
GLuint indexBuffer;
GLint numVertices;
//GLint numJoints;
Joint* root;
Matrix<GLfloat,4,4> poseMatrices[10];
static ShaderProgram shaderProgram;
static GLuint modelLoc;
static GLuint jointIDLoc;
static GLuint modelViewMatrixLoc;
static GLuint jointsLoc;
};
SkinnedModel.cpp
#include "SkinnedModel.h"
ShaderProgram SkinnedModel::shaderProgram;
GLuint SkinnedModel::modelLoc = -1;
GLuint SkinnedModel::jointIDLoc = -1;
GLuint SkinnedModel::modelViewMatrixLoc = -1;
GLuint SkinnedModel::jointsLoc = -1;
void SkinnedModel::init()
{
ShaderProgramSettings shaderPS;
shaderPS.loadShader("Skinned.v.glsl", ShaderType::VERTEX);
shaderPS.loadShader("Skinned.f.glsl", ShaderType::FRAGMENT);
shaderProgram = shaderPS.create();
shaderProgram.use();
modelLoc = shaderProgram.getAttrib("model");
jointIDLoc = shaderProgram.getAttrib("jointID");
//modelViewMatrixLoc = shaderProgram.getUniform("modelViewMatrix");
jointsLoc = shaderProgram.getUniform("joints");
}
void SkinnedModel::destroy()
{
shaderProgram.destroy();
}
SkinnedModel::SkinnedModel()
{
}
SkinnedModel::~SkinnedModel()
{
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &indexBuffer);
}
void SkinnedModel::create(const GLfloat* vertices, const GLuint* jointIndices, GLint numVertices, Joint* rootJoint)
{
this->numVertices = numVertices;
this->root = rootJoint;
for(U32 i=0;i<10;++i)
{
poseMatrices[i] = Matrix<GLfloat,4,4>::Identity();
}
poseMatrices[1] = Matrix<GLfloat,4,4>::Zero(); // <--- This should mess it up!
// Creating buffers
glDeleteBuffers(1, &vertexBuffer);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices*2*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glDeleteBuffers(1, &indexBuffer);
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(GLuint), jointIndices, GL_STATIC_DRAW);
}
void SkinnedModel::draw()
{
shaderProgram.use();
glEnableVertexAttribArray(modelLoc);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(modelLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(jointIDLoc);
glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
glUniformMatrix4fv(jointsLoc, 10, GL_FALSE, (GLfloat*)&poseMatrices);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glDisableVertexAttribArray(modelLoc);
glDisableVertexAttribArray(jointIDLoc);
}
void SkinnedModel::rotate(Joint* joint, F32 angle, F32 x, F32 y)
{
F32 rcos = cos(angle);
F32 rsin = sin(angle);
Matrix<GLfloat, 4, 4> rotMatrix = Matrix<GLfloat, 4, 4>::Identity();
rotMatrix(0,0) = rcos;
rotMatrix(0,1) = -rsin;
rotMatrix(1,0) = rsin;
rotMatrix(1,1) = rcos;
rotMatrix(0,3) = x-rcos*x+rsin*y;
rotMatrix(1,3) = y-rsin*x-rcos*y;
poseMatrices[joint->index] *= rotMatrix;
}
Game.cpp
void Game::init()
{
GUI::init();
SkinnedModel::init();
getScreen()->setBackgroundColor(1.0f, 1.0f, 1.0f);
const GLfloat vertices[] =
{
// upper arm
0.0f, 0.0f,
0.4f, 0.0f,
0.4f, 0.2f,
0.0f, 0.0f,
0.4f, 0.2f,
0.0f, 0.2f,
// lower arm
0.4f, 0.0f,
0.8f, 0.0f,
0.8f, 0.2f,
0.4f, 0.0f,
0.8f, 0.2f,
0.4f, 0.2f
};
const GLuint indices[] =
{
// upper arm
0,
1,
1,
0,
1,
0,
// lower arm
1,
1,
1,
1,
1,
1
};
upperArm.parent = 0;
upperArm.children = new Joint*[1];
upperArm.children[0] = &lowerArm;
upperArm.index = 0;
lowerArm.parent = &upperArm;
lowerArm.children = 0;
lowerArm.index = 1;
m.create(vertices, indices, 12, &upperArm);
//m.rotate(&lowerArm, PI/4, 0.4f, 0.1f);
//DEBUG("SIZE %i", sizeof(Eigen::Matrix<GLfloat,4,4>));
}
void Game::loop(double dt)
{
m.draw();
}
Update: Apparently if all values for the boneID are set to 1 it never uses 1 in the shader either #.#. So the second array isn't even being read, or it's not being read correctly.
You need to use glVertexAttribIPointer if you are using integer vertex attributes (i.e. something you have declared in uint or in int etc. in your vertex shader).
replace
glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
with
glVertexAttribIPointer(jointIDLoc, 1, GL_UNSIGNED_INT, 0, NULL);
(note that glVertexAttribIPointer doesn't take the normalized parameter)