Having difficulty with OpenGL in C++, when rendering multiple objects - c++

I'm having trouble rendering multiple cubes to screen. I have a cube class which sets up the cubes vertices and loads the appropriate shader. The problem that happens is that when multiple instances of my class are created like this:
Cube * cube = new Cube();
Cube * cube1 = new Cube();
And then I initialise the cube objects like so:
cube->setPos(0, 0, 0);
cube->setType(Cube::Type::Green);
cube->createCube();
cube1->setPos(1, 0, 0);
cube1->setType(Cube::Type::Red);
cube1->createCube();
Then I draw the cubes to screen in my render method like so:
cube->draw();
cube1->draw();
My cube class looks like this:
include "cube.h"
Shader* shader;
GLuint tex;
GLuint shaderProgram, fragmentShader, vertexShader;
GLuint vbo, ebo;
GLfloat x, y, z;
GLfloat r, g, b;
Cube::Cube() {
}
void Cube::setPos(GLfloat X, GLfloat Y, GLfloat Z) {
x = X;
y = Y;
z = Z;
}
void Cube::setType(Type type) {
switch (type) {
case Type::Red:
r = 1.0f;
g = 0.0f;
b = 0.0f;
break;
case Type::Green:
r = 0.0f;
g = 1.0f;
b = 0.0f;
break;
case Type::Blue:
r = 0.0f;
g = 1.0f;
b = 0.0f;
break;
default:
r = 0.0f;
g = 0.0f;
b = 0.0f;
break;
}
}
Cube::~Cube() {
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
}
void Cube::createCube() {
createShader();
GLfloat vertices[] = {
//X, Y, Z, R, G, B
x - 0.5f, y - 0.5f, z - 0.5f, r, g, b, // 0
x + 0.5f, y - 0.5f, z - 0.5f, r, g, b, // 1
x + 0.5f, y + 0.5f, z - 0.5f, r, g, b, // 2
x - 0.5f, y + 0.5f, z - 0.5f, r, g, b, // 3
x - 0.5f, y - 0.5f, z + 0.5f, r, g, b, // 4
x + 0.5f, y - 0.5f, z + 0.5f, r, g, b, // 5
x + 0.5f, y + 0.5f, z + 0.5f, r, g, b, // 6
x - 0.5f, y + 0.5f, z + 0.5f, r, g, b, // 7
};
GLuint elements[] = {
0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
7, 3, 0, 0, 4, 7,
6, 2, 1, 1, 5, 6,
0, 1, 5, 5, 4, 0,
3, 2, 6, 6, 7, 3
};
// Create a Vertex Buffer Object and copy the vertex data to it
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Create an element array
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements,
GL_STATIC_DRAW);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
// Specify the layout of the vertex data
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
(void*) (3 * sizeof(GLfloat)));
}
void Cube::update() {
// Calculate transformation
glm::mat4 trans;
trans = glm::rotate(trans, (float) clock() / (float) CLOCKS_PER_SEC * 1.0f,
glm::vec3(0.0f, 0.0f, 1.0f));
GLint uniTrans = glGetUniformLocation(shaderProgram, "model");
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));
glm::mat4 view = glm::lookAt(glm::vec3(1.2f, 1.2f, 1.2f), glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f));
GLint uniView = glGetUniformLocation(shaderProgram, "view");
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));
glm::mat4 proj = glm::perspective(45.0f, 800.0f / 600.0f, 1.0f, 10.0f);
GLint uniProj = glGetUniformLocation(shaderProgram, "proj");
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
}
void Cube::draw() {
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}
void Cube::createShader() {
// load vertex shader source
const GLchar* vertexSource = shader->fileRead("src/shaders/vertex.vs");
if (vertexSource != NULL) std::cout << "vertexSource" << std::endl;
// load fragment shader source
const GLchar* fragmentSource = shader->fileRead("src/shaders/fragment.fs");
if (fragmentSource != NULL) std::cout << "fragmentSource" << std::endl;
// Create and compile the vertex shader
vertexShader = shader->compileShader(vertexSource, GL_VERTEX_SHADER);
// Create and compile the fragment shader
fragmentShader = shader->compileShader(fragmentSource, GL_FRAGMENT_SHADER);
// Link the vertex and fragment shader into a shader program
shaderProgram = shader->compileProgram(vertexShader, fragmentShader);
}
Long story short. I create and initialise two cubes. Both are drawn to screen in code yet when teh compiled program is run only the second cube is shown on screen.
A copy of my full code is available from My GitHub, if you'd like to clone and build it.
I've spent hours upon hours searching for a way to fix this and can't so I'm reaching out to the community. I have a feeling it's something to do with needing a VAO but I can't find out how or where to implement this I've tried a few different ways already.
Any helps greatly appreciated. Thanks in advance!

none of the state you set in the create function will persist beyond another call to it.
First you should move the values to members of the cube class.
Then in create you should create and use a vao:
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
Before specifying the vertex layout.
Then during the draw call:
void Cube::draw() {
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}
Add a call to glUseProgram(shaderProgram); in update as well.
However it's more efficient to use a single static program and then load the model matrix in the uniform;
void Cube::draw() {
//assume program is already bound and non-cube-specific uniforms are already set
glBindVertexArray(vao);
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));//kept in a field
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}

Without going into depth on your OpenGL usage (which #ratchetfreak already did in a separate answer), you have a very fundamental C++ problem.
You're declaring a bunch of variables at the start of your Cube.cpp file:
Shader* shader;
GLuint tex;
GLuint shaderProgram, fragmentShader, vertexShader;
GLuint vbo, ebo;
GLfloat x, y, z;
GLfloat r, g, b;
With the variables declared like this, you will have only a single copy of these values, which are shared between all instances of the Cube class. For example, all your cubes will have the same position, which is the one of the last cube you created, because they all share the same x, y and z variables that hold the position.
You need to define these variables as class members so that each Cube instance has separate values. This means that they need to go into the header file, typically in the private section of the class. For example:
class Cube {
public:
// Declaration of constructor, methods, etc.
private:
GLfloat x, y, z;
};
You'll probably want to use more descriptive names for the variables.

Related

Rotated GLSL texture is pixelated

I've made a program that displays some textures depending on the given input and can rotate, resize and move the textures depending on the given input. The program works perfectly fine but when I rotate the textures the edges appear to be pixelated, like this:
Is there a way for me to smoothen out these edges?
Here are my shaders and texture classes:
texture.vs:
#version 300 es
precision mediump float;
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0f);
ourColor = aColor;
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
texture.fs
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
Here is my texture.cpp:
Texture::Texture(int x, int y, int w, int h, int gw, int gh)
{
pos.TL_x = _VERTICIZE_X(x, gw);
pos.TL_y = -_VERTICIZE_Y(y, gh);
pos.TR_x = _VERTICIZE_X(x + w, gw);
pos.TR_y = -_VERTICIZE_Y(y, gh);
pos.BL_x = _VERTICIZE_X(x, gw);
pos.BL_y = -_VERTICIZE_Y(y + h, gh);
pos.BR_x = _VERTICIZE_X(x + w, gw);
pos.BR_y = -_VERTICIZE_Y(y + h, gh);
}
void set_max_z(int z)
{
max_z = z;
}
int Texture::init(float ang_rad, float z)
{
shader = Shader("./src/opengl/shaders/image.vs", "./src/opengl/shaders/image.fs");
this->angle = ang_rad;
// build and compile our shader zprogram
// ------------------------------------
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[32] = {
// positions // colors // texture coords
pos.TR_x, pos.TR_y, _VERTICIZE_Z(z, max_z), 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, // top right
pos.BR_x, pos.BR_y, _VERTICIZE_Z(z, max_z), 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, // bottom right
pos.BL_x, pos.BL_y, _VERTICIZE_Z(z, max_z), 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // bottom left
pos.TL_x, pos.TL_y, _VERTICIZE_Z(z, max_z), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
glEnable(GL_DEPTH_TEST);
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);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// load and create a texture
// -------------------------
// texture 1
// ----------
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
// -------------------------------------------------------------------------------------------
shader.use(); // don't forget to activate/use the shader before setting uniforms!
// either set it manually like so:
glUniform1i(glGetUniformLocation(shader.ID, "texture"), 0);
return 0;
}
void Texture::render(int w, int h, uint8_t *buffer)
{
// If having trouble doing multiple textures, add "+ index to Active Texture."
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glm::mat4 transform = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first
transform = glm::translate(transform, glm::vec3(0.0f, 0.0f, 0.0f));
transform = glm::rotate(transform, glm::radians(this->angle), glm::vec3(0.0f, 0.0f, 1.0f));
// get matrix's uniform location and set matrix
shader.use();
unsigned int transformLoc = glGetUniformLocation(shader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
Texture::~Texture()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
void Texture::framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
(_VERTICIZE just calculates points)
I'm using ubuntu, GLAD, GLFW.
This appears to be a classic example of Aliasing. We can fix this by enabling MSAA.
GLFW has an inbuilt way of doing that. Put this before you create the window:
glfwWindowHint(GLFW_SAMPLES, 4); /* if effect is not strong enough, change to 8 */
Edit -
You have to call glfwWindowHint(GLFW_SAMPLES, 4) in between glfwInit and glfwCreateWindow.
Also, in case OpenGL doesn't enable multisampling by default, do
glEnable(GL_MULTISAMPLE);

OpenGL Trying to render a cube but there are weird lines between planes

Cube rendering
Hey, i think there may be a mistake in either how i'm sending the data to the vertex or the way my indices are ordered with GL_CCW
struct Vertex
{
glm::vec3 position;
glm::vec3 color;
glm::vec3 normal;
};
Vertices using Vertex struct
Vertex vertices[] =
{
/*FRONT SQUARE*/
///BOTTOM LEFT
glm::vec3(-0.5f, -0.5f, 1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///bottom RIGHT
glm::vec3(0.5f, -0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
////TOP RIGHT
glm::vec3(0.5f, 0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///TOP LEFT
glm::vec3(-0.5f, 0.5f, 1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///BOTTOM LEFT
glm::vec3(-0.5f, -0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///bottom RIGHT
glm::vec3(0.5f, -0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
////TOP RIGHT
glm::vec3(0.5f, 0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f),
///TOP LEFT
glm::vec3(-0.5f, 0.5f, -1.0f), glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f)
};
unsigned noOfVertices = sizeof(vertices) / sizeof(Vertex);
This is my indices ordering
GLuint indices[] =
{
// /front face
0, 1, 2,
2, 3, 0,
// right
1, 5, 6,
6, 2, 1,
// back
7, 6, 5,
5, 4, 7,
// left
4, 0, 3,
3, 7, 4,
// bottom
4, 5, 1,
1, 0, 4,
// top
3, 2, 6,
6, 7, 3
};
unsigned noOfIndices = sizeof(indices) / sizeof(GLuint);
Main function and initliase the window
int main()
{
Initiase window
///initialise GLFW for Window
if (glfwInit() == GLFW_FALSE)
{
std::cout << "ERROR::GLFW-INTI::FAILED" << "\n";
glfwTerminate();
}
///Create window with functions
GLFWwindow* window;
const int window_height = 480;
int window_width = 680;
int framebuffer_height = window_height;
int framebuffer_width = window_width;
char* title = "mytutorial";
int GLverMAJ = 3;
int GLverMin = 3;
///sets how the window should be drawn and which hints
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GLverMAJ);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GLverMin);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
///create the window with the previously set options
window = glfwCreateWindow(window_width, window_height, title, NULL, NULL);
//checks if window created
if (window == nullptr)
{
std::cout << "ERROR:::GLFWCREATEWINDOWFAILED" << "\n";
}
///sets the frame buffer size
glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height);
glfwMakeContextCurrent(window);
//need to read on this part
glewExperimental = GL_TRUE;
//initiliase the glew
if (glewInit() != GLEW_OK)
{
std::cout << "ERROR::GLEWINIT::FAILED" << "\n";
}
initiliase opengl options
///enable functions first
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
//initialise the enabled functions
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LESS);
///set the way its draw
glFrontFace(GL_CCW);
///set the polygon mode and fill ////Set as GL_LINE TO LOOK AT CUBE MESH
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
This is where i initialise the matrices the view, project and model
///initialise the matrices
///view
///front, position, up then use in lookat
glm::vec3 cameraPos(0.f, 0.f, 1.f);
glm::vec3 cameraUp(0.f, 1.f, 0.f);
glm::vec3 cameraFront(0.f, 0.f, -0.1f);
glm::mat4 ViewMatrix(1.f);
ViewMatrix = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
///set up prespective projection
float fov = 90.f;
float nearPlane = -1.f;
float farPlane = 1000.f;
///projection
glm::mat4 ProjectionMatrix(1.f);
ProjectionMatrix = glm::perspective(glm::radians(fov), static_cast<float>(framebuffer_width / framebuffer_height), nearPlane, farPlane);
//Model Matrix
glm::mat4 ModelMatrix(1.f);
Then i create my shaders
///set up SHADERS
char infolog[512];
GLint success;
GLuint Vertexshader = glCreateShader(GL_VERTEX_SHADER);
///std::string str_src =
std::string temp = "";
std::string src = "";
std::ifstream infile;
infile.open("vert.glsl");
if (infile.is_open())
{
while (std::getline(infile, temp))
src += temp + "\n";
}
infile.close();
const GLchar* source = src.c_str();
///link created shader with shader source
glShaderSource(Vertexshader, 1, &source, NULL);
glCompileShader(Vertexshader);
///error check compilation status
glGetShaderiv(Vertexshader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(Vertexshader, 512, NULL, infolog);
std::cout << infolog;
}
success = 0;
GLuint FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
///std::string str_src =
temp = "";
src = "";
infile.open("frag.glsl");
if (infile.is_open())
{
while (std::getline(infile, temp))
src += temp + "\n";
}
infile.close();
source = src.c_str();
///link created shader with shader source
glShaderSource(FragmentShader, 1, &source, NULL);
glCompileShader(FragmentShader);
///error check compilation status
glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(FragmentShader, 512, NULL, infolog);
std::cout << infolog;
}
Link the created shaders with the program
///create and link the program
success = 0;
GLuint programID;
programID = glCreateProgram();
glAttachShader(programID, Vertexshader);
glAttachShader(programID, FragmentShader);
glLinkProgram(programID);
glGetProgramiv(programID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(programID, 512, NULL, infolog);
std::cout << "ERROR::SHADER::COULD_NOT_LINK_PROGRAM" << "\n";
std::cout << infolog << "\n";
}
after linking unuse and delete buffers
///after linking we unuse the program and delete the shaders
glUseProgram(0);
glDeleteShader(Vertexshader);
glDeleteShader(FragmentShader);
This is where i initiliase VAO VBO AND EBO
///vbo, ebo and vertex array
GLuint VAO;
GLuint VBO;
GLuint EBO;
//gen and bind vao
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
///gen vbo
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, noOfVertices * sizeof(Vertex), vertices, GL_STATIC_DRAW);
///gen EBO
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, noOfIndices * sizeof(GLuint), indices, GL_STATIC_DRAW);
This is the part where i feel like there may be a problem
///tell buffer where data is located
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
//colour
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, normal));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
///use program send in uniforms to the shader.
glUseProgram(programID);
///GLuint s = glGetUniformLocation(programID, "ViewMatrix");
GLuint s = glGetUniformLocation(programID, "ModelMatrix");
glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ModelMatrix));
s = glGetUniformLocation(programID, "ProjectionMatrix");
glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ProjectionMatrix));
s = glGetUniformLocation(programID, "ViewMatrix");
glUniformMatrix4fv(s, 1, GL_FALSE, glm::value_ptr(ViewMatrix));
glUseProgram(0);
///main while loop
while (!glfwWindowShouldClose(window))
{
//clear
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
///draw
glfwPollEvents();
glUseProgram(programID);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, noOfIndices, GL_UNSIGNED_INT, 0);
///flush
glfwSwapBuffers(window);
glFlush();
///unuse
glBindVertexArray(0);
glUseProgram(0);
}
return 0;
}
Both the near plane and the far plane have to be positive values for glm::perspective and static_cast<float>(framebuffer_width / framebuffer_height) would be an integral division:
float fov = 90.f;
float nearPlane = 0.1f; // 0.1 instead of -1.0
float farPlane = 1000.f;
glm::mat4 ProjectionMatrix(1.f);
ProjectionMatrix = glm::perspective(glm::radians(fov),
static_cast<float>(framebuffer_width) / static_cast<float>(framebuffer_height),
nearPlane, farPlane);
See glm::perspective:
GLM_FUNC_DECL mat<4, 4, T, defaultp> glm::perspective(
T fovy,
T aspect,
T near,
T far
)
[...]
near Specifies the distance from the viewer to the near clipping plane (always positive).
far Specifies the distance from the viewer to the far clipping plane (always positive).
The glm library provides matrix operations related to OpenGL and GLSL. The glm API documentation refers to The OpenGL Shading Language specification 4.20.
See The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors, page 101:
To initialize a matrix by specifying vectors or scalars, the components are assigned to the matrix elements in column-major order.
mat4(float, float, float, float, // first column
float, float, float, float, // second column
float, float, float, float, // third column
float, float, float, float); // fourth column
This means the transformation of the vertex coordinate in the vertex shader has to be:
gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(vertex_position,1.0);
See also GLSL Programming/Vector and Matrix Operations:
Likely the matrix can be transposed when set to the uniform, by setting the 3rd paramter of glUniformMatrix4fv to GL_TRUE:
GLuint s = glGetUniformLocation(programID, "ModelMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ModelMatrix));
s = glGetUniformLocation(programID, "ProjectionMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ProjectionMatrix));
s = glGetUniformLocation(programID, "ViewMatrix");
glUniformMatrix4fv(s, 1, GL_TRUE, glm::value_ptr(ViewMatrix));
And compute the vertex coordinate transformation in the reverse order:
gl_Position = vec4(vertex_position,1.0) * ModelMatrix * ViewMatrix * ProjectionMatrix;
Further, the winding order of the faces of the cube a is clockwise, so it has to be:
glFrontFace(GL_CCW);
glFrontFace(GL_CW);
Change the camera position to
glm::vec3 cameraPos(0.f, 0.f, 2.f);
and you'll get the following result:
To me, it would seem that your program is working correctly. If I'm not mistaken, then your camera is located inside the cube, looking straight from the position of one of the faces at the face on the other side. What you're seeing is exactly what one would expect to see in this case. In the center of the image you have the two triangles that make the backside of the face you're looking out of. The "weird lines" you get are simply the edges of the triangles that make the other faces. Since your camera is inside the cube, these faces necessarily reach all the way behind your camera and everything gets cut off at the near plane, which is where you get the outer rectangle from that "encloses" everything.
Everything is a bit squashed because this
static_cast<float>(framebuffer_width / framebuffer_height)
will not have the effect you most likely intend it to have. You are still performing an integer division here.
Also, I'm not sure what exactly you expect the effect of using a negative value for the near plane to be. Most likely, it's also not what you actually want, I suggest you use some positive value, e.g., 0.1f there… 😉

opengl 2d game only drawing second sprite texture and not first

I'm currently creating a 2d fighting game utilizing OpenGL and I have run into a problem where OpenGL is only drawing at my last initialized sprite position, regardless of how many sprites I initialize and try and draw. Even when I initialize a sprite1 and sprite2 but only draw sprite1, sprite is what will still be drawn. It starts with my sprite class where I initialize where on the screen I want my image as well as what image to use:
Sprite.cpp
Init(int screenCoordinateX, int screenCoordinateY, uint imageWidth, unsigned int imageHeight, std::string imageFilePath)
{
//casting to float since GLSL shader variables vec2,3,4 require vertex data to be in floats
this->x = static_cast<float>(x);
this->y = static_cast<float>(y);
this->width = static_cast<float>(width);
this->height = static_cast<float>(height);
glGenBuffers(1, &vboID);
Blz::Graphics::GLTexture texture(imageFilePath);
this->texture = texture;
float halfWidth = this->width / 2;
//Setting sprite origin at bottom middle of image by subtracting half width
this->vertexData.at(0).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y + this->height, 0.0f });//Top right corner
this->vertexData.at(1).SetPosition(glm::vec3{ this->x - halfWidth, this->y + height, 0.0f });//Top left corner
this->vertexData.at(2).SetPosition(glm::vec3{ this->x - halfWidth, this->y, 0.0f });//Bottom left corner
this->vertexData.at(3).SetPosition(glm::vec3{ this->x - halfWidth, this->y, 0.0f });//Bottom left corner
this->vertexData.at(4).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y, 0.0f });//Bottom right corner
this->vertexData.at(5).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y + this->height, 0.0f });//Top right corner
this->vertexData.at(0).SetUV(glm::vec2{ 1.0f, 1.0f });
this->vertexData.at(1).SetUV(glm::vec2{ 0.0f, 1.0f });
this->vertexData.at(2).SetUV(glm::vec2{ 0.0f, 0.0f });
this->vertexData.at(3).SetUV(glm::vec2{ 0.0f, 0.0f });
this->vertexData.at(4).SetUV(glm::vec2{ 1.0f, 0.0f });
this->vertexData.at(5).SetUV(glm::vec2{ 1.0f, 1.0f });
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, (sizeof(Vector3D) * this->vertexData.size()), &this->vertexData.front(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, position));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, textureCoordinates));
//Unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
I then try and render sprites passed in to renderer like so:
Renderer.cpp
void Renderer::Draw(Sprite& sprite)
{
glm::mat4 orthoProjection = glm::ortho(0.0f, static_cast<sfloat>(1024), 0.0f, static_cast<sfloat>(768));
GLuint transformationMatrixUniformLocation = this->shaderProgram.GetUniformLocation("transformationMatrix");
glUniformMatrix4fv(transformationMatrixUniformLocation, 1, GL_FALSE, &(orthoProjection[0][0]));
glBindTexture(GL_TEXTURE_2D, sprite.texture.id);
glBindBuffer(GL_ARRAY_BUFFER, sprite.vboID);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
I here is my main.cpp where I begin to call everything:
int main()
{
Blz::Graphics::Renderer renderer;
Blz::Window window;
Blz::Input input;
Scene scene;
window.Initialize();
renderer.Init();
Sprite sprite1;
sprite.Init(900, 300, 200, 200, "CharImage.png");
Sprite sprite2;
sprite2.Init(100, 100, 200, 200, "CharImage.png");
while (!input.IsKeyPressed(SDLK_ESCAPE))
{
window.ClearBuffers();
renderer.Draw(sprite1);
window.SwapBuffers();
}
return 0;
}
So even though I ask for sprite1 to be drawn, only sprite2's position at 100x 100y gets drawn to the screen. Even if I manually try and enter a vboID of 1 (which is the vboID of sprite1) within renderer.cpp, it still draws sprite2's position. What am I doing wrong?
Here are my Shaders if necessary:
VertexShader.glsl
#version 430
in vec3 vertexPosition;
in vec2 textCoord;
out vec2 TextureCoord;
uniform mat4 transformationMatrix;
void main()
{
vec4 position = vec4(vertexPosition, 1.0f);
gl_Position = transformationMatrix * position;
TextureCoord = textCoord;
};
FragmentShader.glsl
#version 430
out vec4 daColor;
in vec2 TextureCoord;
uniform sampler2D basicTexture;
void main()
{
vec4 texel = texture(basicTexture, TextureCoord);
daColor = texel;
};
So I guess this is a lesson for anyone aspiring to learn and use OpenGL. Anytime you are using VBOs and vbo ids to bind an OpenGL buffer to you also need to again specify your vertexattribpointers before drawing. So my new renderer.cpp file looks like this:
void Renderer::Draw(Sprite& sprite)
{
glm::mat4 orthoProjection = glm::ortho(0.0f, static_cast<sfloat>(1024), 0.0f, static_cast<sfloat>(768));
GLuint transformationMatrixUniformLocation = this->shaderProgram.GetUniformLocation("transformationMatrix");
glUniformMatrix4fv(transformationMatrixUniformLocation, 1, GL_FALSE, &(orthoProjection[0][0]));
glBindTexture(GL_TEXTURE_2D, sprite.texture.id);
glBindBuffer(GL_ARRAY_BUFFER, sprite.vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, position));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, textureCoordinates));
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
This other SO answer gives a reason as to why: is VertexAttribPointer needed after each BindBuffer?. To avoid this, you would use the newer VAO's which store vertex attribute info so you don't have to specify vertexattribpointer functions everytime.

How to pass the model matrix off to the shader and make the triangle rotate

I am using OpenGL and GLM library, and I try to pass the model matrix off to the shader and make the triangle rotate. I have already got the basic code and getting the IDs of the variables in the vertex shader. While I have no idea how to actually setting them.
#include <GL/GLEW.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/gtc/matrix_transform.hpp> // glm::translate/rotate/scale/etc
#include <glm/gtc/type_ptr.hpp> // glm::value_ptr
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
glm::mat4 M;
glm::mat4 V;
glm::mat4 P;
glm::mat4 trans;
glm::mat4 rot;
float rotAmount = 0.0f;
GLint umM;
GLint umV;
GLint umP;
void func(GLuint LocationMVP, float Translate, glm::vec2 const & Rotate)
{
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.f);
glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate));
glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));
glm::mat4 View = glm::rotate(ViewRotateX, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(LocationMVP, 1, GL_FALSE, glm::value_ptr(MVP));
}
void render()
{
trans = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, -1));
rot = glm::rotate(glm::mat4(1.0f), rotAmount, glm::vec3(0, 1, 0));
M = trans*rot;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 9, GL_UNSIGNED_INT, NULL);
glutSwapBuffers();
glutPostRedisplay();
}
void specialKeys(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP: printf("The UP key was pressed\n"); break;
case GLUT_KEY_DOWN: printf("The DOWN key was pressed\n"); break;
}
}
void mousePressed(int button, int state, int x, int y)
{
if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) {
//printf("Mouse clicked at %d %d\n", x, y);
}
}
void mouseMoved(int x, int y) {
//printf("Mouse moved at %d %d\n", x, y);
}
void mouseDragged(int x, int y) {
//printf("Mouse dragged at %d %d\n", x, y);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); // Set up buffers
glutInitWindowPosition(200, 200); // Optional: position the upper-left of the window
glutInitWindowSize(800, 600); // Set the window size
glutCreateWindow("Lab 5"); // Create the window and give it a title
glewInit(); // Ask the driver for all the OpenGL functions
// Some callback functions
glutDisplayFunc(render); // Use the render function to draw
glutSpecialFunc(specialKeys); // Use the specialKeys function for Up/Down/Left/Right keys
glutMouseFunc(mousePressed); // Use for mouse clicks
glutMotionFunc(mouseDragged); // Use for mouse dragging
glutPassiveMotionFunc(mouseMoved); // Use for mouse moving
#pragma region SHADER_STUFF
// ========= SHADER STUFF ===============
const GLchar* vertexShaderCode = "#version 150\n\
in vec4 vPosition;\n\
in vec4 vColor;\n\
out vec4 color;\n\
void main () {\n\
color = vColor;\n\
\tgl_Position = vPosition;\n\
}\n";
const GLchar* fragmentShaderCode = "#version 150\n\n\
out vec4 fColor;\n\
in vec4 color;\n\
void main () {\
fColor = color;\n\
}";
// Vertex Shader
GLint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderID, 1, &vertexShaderCode, NULL);
glCompileShader(vertexShaderID);
GLint compiled = -10;
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &compiled);
printf("Vertex compile status %d!\n", compiled);
printf("Vertex shader ID is %d\n", vertexShaderID);
// Fragment Shader
GLint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShaderID, 1, &fragmentShaderCode, NULL);
glCompileShader(fragmentShaderID);
GLint compiled2 = -19;
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &compiled2);
printf("Fragment compile status %d!\n", compiled2);
printf("Fragment shader ID is %d\n", fragmentShaderID);
// Make the program
GLint shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShaderID);
glAttachShader(shaderProgram, fragmentShaderID);
glLinkProgram(shaderProgram);
GLint linkedStatus = 14;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &linkedStatus);
printf("Link status is %d\n", linkedStatus);
printf("Shader program ID is %d\n", shaderProgram);
glUseProgram(shaderProgram);
#pragma endregion SHADER_STUFF
// Positions
GLfloat vertices[] = { -0.5f, -0.5f, 0.0f, // 0
-0.25f, 0.0f, 0.0f, // 1
0.0f, 0.5f, 0.0f, // 2
0.0f, -0.5f, 0.0f, // 3
0.25f, 0.0f, 0.0f, // 4
0.5f, -0.5f, 0.0f, // 5
};
// Color information
GLfloat colors[] = { 1.0f, 0.73f, 0.0f, 1.0f, //0
1.0f, 1.0f, 0.0f, 1.0f, // 1
1.0f, 1.0f, 0.0f, 1.0f, // 2
1.0f, 0.73f, 0.0f, 1.0f, // 3
1.0f, 0.65f, 0.0f, 1.0f, // 4
1.0f, 0.65f, 0.0f, 1.0f, // 5
};
// Connect the dots
GLuint index_buffer[] = { 0, 3, 1, 2, 1, 4, 4, 3, 5 };
int numVertices = 6;
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao); // Use the Vertex Array Object we created above
GLuint vbo; // The Vertex Buffer Object ID
glGenBuffers(1, &vbo); // Ask the GPU driver for a buffer array. "vbo" now has the ID
glBindBuffer(GL_ARRAY_BUFFER, vbo); // Make this buffer the active one for subsequent operations (below)
// Specify how big the buffer is, but don't pass the data yet (see NULL). We *could* have, but I wanted to show glBufferSubData
glBufferData(GL_ARRAY_BUFFER, numVertices * 7 * sizeof(GLfloat), NULL, GL_STATIC_DRAW);
// NOW we copy the data in as a separate step. There is an "offset" of 0 - meaning the beginning of the buffer.
// We specify the size of the data we want to copy, followed by a pointer to the actual data
glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * 3 * sizeof(GLfloat), vertices);
glBufferSubData(GL_ARRAY_BUFFER, numVertices * 3 * sizeof(GLfloat), numVertices * 4 * sizeof(GLfloat), colors);
// Figure out where vPosition is in our shader and get its ID
GLuint loc = glGetAttribLocation(shaderProgram, "vPosition");
GLuint loc2 = glGetAttribLocation(shaderProgram, "vColor");
glEnableVertexAttribArray(loc);
glEnableVertexAttribArray(loc2);
printf("vPosition ID is %d\n", loc);
printf("vColor ID is %d\n", loc2);
// When it's time for vPosition to find information, we need to tell it where the data is (or how the data should be parsed)
// Here, we're saying that "vPosition" (loc from above) should look for 3 GLfloats. The data isn't normalized or interlaced,
// and starts at index 0 (the beginning of the current buffer)
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(loc2, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(numVertices * 3 * sizeof(GLfloat)));
GLuint index_vbo;
// Ask the graphics card (driver) for another buffer – same as the old code
glGenBuffers(1, &index_vbo);
// We still want the VAO active to remember these settings
glBindVertexArray(vao);
// Here's where we tell the driver that it's an index buffer.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_vbo);
// This time, we'll just go ahead and pass the data off to the buffer because
// we're not packing multiple data sets into the buffer - only indices
umM = glGetUniformLocation(shaderProgram, "mM"); // Find the mM variable
umV = glGetUniformLocation(shaderProgram, "mV"); // Find the mV variable
umP = glGetUniformLocation(shaderProgram, "mP"); // Find the mP variable
if (umP != -1)
{
glUniformMatrix4fv(umP, 1, GL_FALSE, glm::value_ptr(P));
}
if (umV != -1)
{
glUniformMatrix4fv(umV, 1, GL_FALSE, glm::value_ptr(V));
}
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 9*sizeof(GLuint), index_buffer, GL_STATIC_DRAW);
P = glm::perspective(-60.0f, 1.3f, 0.1f, 1000.0f);
V = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0));
glm::mat4 T = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
glm::mat4 Rx = glm::rotate(T, rotation_x, glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 Ry = glm::rotate(Rx, rotation_y, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 M = glm::rotate(Ry, rotation_z, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 MVP = P*V*M;
glutMainLoop(); // Start listening for events
}
and also my shader file is like
#version 150
in vec4 vPosition;
uniform mat4 mM; // The matrix for the pose of the model
uniform mat4 mV; // The matrix for the pose of the camera
uniform mat4 mP; // The perspective matrix
void main()
{
gl_Position = mP*mV*mM*vPosition;
}
Could any one help me, or teach me how to setting them?

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)