So, I'm a beginner learning graphics programmer. I'm working on a program for camera movement. I think there's something wrong with the vertex shader. The program runs with no errors but the screen is completely blank. Here is the vertex shader I'm using:
#version 330
in vec4 vPosition;
out vec4 vColor;
uniform mat4 model_view;
uniform mat4 projection;
void main()
{
vec4 pos = projection * model_view * vPosition / vPosition.w;
gl_Position = pos;
vColor = vPosition;
}
If I switch the shader back to basic version:
#version 330
in vec4 vPosition;
out vec4 vColor;
void
main()
{
gl_Position = vPosition;
vColor = vPosition;
}
The program runs and renders a triangle successfully. So, I'm pretty sure the error is with the shader.
The shader is called in the initialize function:
void initialize(void)
{
glClearColor(1.0, 1.0, 1.0, 1.0); // white background
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
// Load shaders and use the resulting shader program
GLuint program = InitShader("res/shaders/vshader21.glsl", "res/shaders/fshader21.glsl");
model_view = glGetUniformLocation(program, "model_view");
projection = glGetUniformLocation(program, "projection");
glUseProgram(program);
// Initialize the vertex position attribute from the vertex shader
GLuint loc = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
}
the 'points' in glBufferData is as follows:
const int WIDTH = 500, HEIGHT = 500;
/* Positions */
vec4 points[] = {
vec4(0.5,0.5, 1, 1),
vec4(-0.5,0.5, 1, 1),
vec4(0.5,-0.5, 1, 1) ,
vec4(-0.5,-0.5, 1, 1)
};
model_view and projection are of GLuint type in main application and global.
I set the uniform variables (position, model_view) in the display functions.
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT); // clear the window
glPointSize(20.0);
// Projection transformation parameters
GLfloat left = -1.0, right = 1.0;
GLfloat bottom = -1.0, top = 1.0;
GLfloat zNear = 0, zFar = 3.0;
mat4 p = Ortho(left, right, bottom, top, zNear, zFar);
glUniformMatrix4fv(projection, 1, GL_TRUE, p);
vec4 eye(0.0, 0.0, -1.0, 1.0);
vec4 at(0.0, 0.0, 0.0, 1.0);
vec4 up(0.0, 1.0, 0.0, 0.0);
mat4 mv = LookAt(eye, at, up);
glUniformMatrix4fv(model_view, 1, GL_TRUE, mv);
glDrawArrays(GL_TRIANGLES, 0, 3); // draw the points
glFlush();
}
What could possibly be going wrong?
The explicit division by the .w component is superfluous.
vec4 pos = projection * model_view * vPosition / vPosition.w;
vec4 pos = projection * model_view * vPosition;
Note, the Perspective divide is automatically performed after clipping.
Since the vector is multiplied to the uniforms form the right, you do not have to transpose the matrices:
glUniformMatrix4fv(projection, 1, GL_TRUE, p);
glUniformMatrix4fv(projection, 1, GL_FALSE, p);
glUniformMatrix4fv(model_view, 1, GL_TRUE, mv);
glUniformMatrix4fv(model_view, 1, GL_FALSE, mv);
See GLSL Programming/Vector and Matrix Operations
Related
I'm making a simple game in OpenGL where there is one player and multiple bubbles, all being spheres. Unfortunately, instancing doesn't work as expected and causes some strange effects. I'm new to instancing and can't see what may be causing a problem.
Draw method in player class:
void Player::draw(glm::mat4 ViewMat, GLfloat aspect, glm::vec3 light, GLfloat zoom)
{
bindProgram();
bindBuffers();
glm::mat4 Projection = glm::perspective(zoom, aspect, 0.1f, 100.0f);
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * ViewMat * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "M"), 1, GL_FALSE, &Model[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "V"), 1, GL_FALSE, &ViewMat[0][0]);
glUniform3f(glGetUniformLocation(shaderProgram, "origin"), origin.x, origin.y, origin.z);
glUniform3f(glGetUniformLocation(shaderProgram, "lightPosWorld"), light.x, light.y, light.z);
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size() / 3);
}
Static draw method in bubble class:
void Bubble::drawAll(glm::mat4 ViewMat, GLfloat aspect, glm::vec3 light, GLfloat zoom,
std::vector<Bubble *> allInstances)
{
std::vector<float> origins;
uint count = 0;
for (auto b : allInstances)
{
origins.push_back(b->origin.x);
origins.push_back(b->origin.y);
origins.push_back(b->origin.z);
count++;
}
allInstances[0]->bindProgram();
allInstances[0]->bindBuffers();
glBufferData(GL_ARRAY_BUFFER, origins.size() * sizeof(origins), origins.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, originsBuffer);
glVertexAttribPointer(1, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void *)0 // array buffer offset
);
glm::mat4 Projection = glm::perspective(zoom, aspect, 0.1f, 100.0f);
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * ViewMat * Model;
GLuint programID = allInstances[0]->shaderProgram;
glVertexAttribDivisor(0, 0);
glVertexAttribDivisor(1, 1);
glUniformMatrix4fv(glGetUniformLocation(programID, "MVP"), 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(glGetUniformLocation(programID, "M"), 1, GL_FALSE, &Model[0][0]);
glUniformMatrix4fv(glGetUniformLocation(programID, "V"), 1, GL_FALSE, &ViewMat[0][0]);
glUniform3f(glGetUniformLocation(programID, "lightPosWorld"), light.x, light.y, light.z);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, allInstances[0]->vertices.size() / 3, count);
}
Player vertex shader:
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
uniform mat4 MVP;
uniform mat4 M;
uniform mat4 V;
uniform vec3 origin;
uniform vec3 lightPosWorld;
uniform vec3 cameraPos;
out vec3 vertexPosWorld;
out vec3 vertexNormal;
out vec3 eyeDirectionCamera;
out vec3 lightDirectionCamera;
void main()
{
gl_Position = MVP * vec4(vertexPosition_modelspace + origin,1);
vertexPosWorld = (M * vec4(vertexPosition_modelspace + origin,1)).xyz;
vertexNormal = normalize(vertexPosWorld - origin);
}
Bubble vertex shader:
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 origin;
uniform mat4 MVP;
uniform mat4 M;
uniform mat4 V;
uniform vec3 lightPosWorld;
uniform vec3 cameraPos;
out vec3 vertexPosWorld;
out vec3 vertexNormal;
out vec3 eyeDirectionCamera;
out vec3 lightDirectionCamera;
void main()
{
gl_Position = MVP * vec4(vertexPosition_modelspace + origin,1);
vertexPosWorld = (M * vec4(vertexPosition_modelspace + origin,1)).xyz;
vertexNormal = normalize(vertexPosWorld - origin);
}
This is what I get:
Effect
But I wanted to get two bubbles that look exactly like the player (which draws correctly).
There are 2 issues in the code:
sizeof(origins) is a byte size of std::vector but not its underlying type. It should be sizeof(float).
glBindBuffer should be called before modifying the buffer’s data and properties.
It should help:
glBindBuffer(GL_ARRAY_BUFFER, originsBuffer);
glBufferData(GL_ARRAY_BUFFER, origins.size() * sizeof(float), origins.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void *)0 // array buffer offset
);
I use an integer to use as a "filter" and pass it to a geometric shader and use a bitwise operation to get the bit values. It works in macOS, but not in Windows. To show my point, I used and modified the tutorial code in the geometric shader part in the learnopengl.com found at
https://learnopengl.com/Advanced-OpenGL/Geometry-Shader
Based on the tutorial code, I added the following code in the main.cpp. (I added enabledFaces[] and VFO, and passed them to the shaders.) I only set one bit to each enabledFaces[] integer for simplicity.
int enabledFaces[] = {
1 << 0, 1 << 1, 1 << 2, 1 << 3
};
unsigned int VBO, VAO, VFO;
glGenBuffers(1, &VBO);
glGenBuffers(1, &VFO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), &points, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glBindVertexArray(VFO);
glBindBuffer(GL_ARRAY_BUFFER, VFO);
glBufferData(GL_ARRAY_BUFFER, sizeof(enabledFaces), &enabledFaces, GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_INT, GL_FALSE, sizeof(int), 0);
glBindVertexArray(0);
In the vertex shader as a pass-through:
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in int vEnabledFaces;
out int gEnabledFaces;
out VS_OUT {
vec3 color;
} vs_out;
void main() {
vs_out.color = aColor;
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
gEnabledFaces = vEnabledFaces;
}
And the geometric shader (added the if statement with the gEnabledFaces):
##version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 5) out;
in int gEnabledFaces[];
in VS_OUT {
vec3 color;
} gs_in[];
out vec3 fColor;
void build_house(vec4 position)
{
fColor = gs_in[0].color; // gs_in[0] since there's only one input vertex
gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0); // 1:bottom-left
EmitVertex();
gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0); // 2:bottom-right
EmitVertex();
gl_Position = position + vec4(-0.2, 0.2, 0.0, 0.0); // 3:top-left
EmitVertex();
gl_Position = position + vec4( 0.2, 0.2, 0.0, 0.0); // 4:top-right
EmitVertex();
gl_Position = position + vec4( 0.0, 0.4, 0.0, 0.0); // 5:top
fColor = vec3(1.0, 1.0, 1.0);
EmitVertex();
EndPrimitive();
}
void main() {
if ( (gEnabledFaces[0] & 0x01) != 0 || (gEnabledFaces[0] & 0x04) != 0)
build_house(gl_in[0].gl_Position);
}
No change in the fragment shader:
#version 330 core
out vec4 FragColor;
in vec3 fColor;
void main()
{
FragColor = vec4(fColor, 1.0);
}
Due to the if statement in the main() in the geometric shader, two houses (the first and the third polygons) out of the 4 polygons should be displayed. It works correctly on Mac, but nothing is displayed in Windows. If I remove the if statement in Windows, all polygons display correctly. Would someone please explain why this does not work in Windows and how to fix it? Thank you.
As suggested by G.M., the use of glVertexAttribIPointer solves the problem.
But I use Qt and unfortunately, it seems that glVertexAttribIPointer is not available. So I changed the glVertexAttribPointer to float type instead of an integer type. So,
Changing from
glVertexAttribPointer(2, 1, GL_INT, GL_FALSE, sizeof(int), 0);
to
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(float), 0);
Then it works in Windows, in spite of the fact that the passing variables (in the C++ and also in shaders) are all integer type. Strange but it works.
As we know if we want to draw something in World space we need multiply our data by view and projection matrices. Now I need for my task to make vertex transformation outside shaders and sent transformated vertex directly. Like this:
Initialization matrix
glm::mat4 view, projection;
view = glm::lookAt(this->cameraPos, this->cameraPivot, this->Up);
projection = glm::perspective(glm::radians(60.0f), (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
Code
vector<glm::vec3> data;
glm::mat4 projection, view;
...
data.push_back(glm::vec3(projection * view * glm::vec4(0.0, 0.0, 0.5, 0.0)));
data.push_back(glm::vec3(projection * view * glm::vec4(0.0, 0.5, 0.5, 0.0)));
data.push_back(glm::vec3(projection * view * glm::vec4(0.5, 0.5, 0.5, 0.0)));
data.push_back(glm::vec3(projection * view * glm::vec4(0.5, 0.0, 0.5, 0.0)));
...
shader.set();
GLuint VAO,VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &wVBO);
glBindVertexArray(wVAO);
glBindBuffer(GL_ARRAY_BUFFER, wVBO);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(vector<glm::vec3>), &data.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
...
glBindVertexArray(wVAO);
glDrawArrays(GL_LINE_LOOP, 0, data.size());
glBindVertexArray(0);
Shader
#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0f);
}
But I get wrong view transformation - it looks like my data doesn't take into account the projection matrix, only the view matrix. But if I change it as usual:
Code
...
data.push_back(glm::vec3(glm::vec4(0.0, 0.0, 0.5, 0.0)));
...
shader.set();
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "matrices"), 1,
GL_FALSE, glm::value_ptr(projection * view));
Shader
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 matrices;
void main()
{
gl_Position = matrices * vec4(position, 1.0f);
}
it's works as expected. What is my mistake? In my task needs to know position all of vertex in World-space before it will sended in shader. How can I do that?
The homogeneous coorinate "w" for your vertices should be 1.0f or else no transform will be applied to the vertex.
I got it! Thanks Daniel for idea!!!
In my case no matters "w" is in inicialization of vertices. This is important in another.
Looks on a shader code in example #2:
#version 330 core
layout (location = 0) in --->vec3<--- position;
uniform mat4 matrices;
void main()
{
gl_Position = matrices * vec4(position, --->1.0f<---);
}
In input shader I send vec3 and it's wrong! We need to save "w" component which produced from matrix multiplication:
Shader
layout (location = 0) in vec4 position;
...
void main()
{
gl_Position = matrices * position;
}
Code
vector<glm::vec4> data;
glm::mat4 projection, view;
...
data.push_back(projection * view * glm::vec4(0.0, 0.0, 0.5, 1.0));
...
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(glm::vec4), &data.data(), GL_STATIC_DRAW);
....
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
That's it! Thanks everyone!
glm::vec4 as bytes is smth + 4 floats when shader expects 4 floats. At least size is wrong(and I suspect data too).That's said about all : question ,answer and comments.
I have a cube with vertex at 1 and -1 (1 1 1, 1 1 -1, etc).
Currently I'm using only the view matrix and set the projection to be identity:
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
mat4 view = glm::lookAt(vec3(0,0,3),
vec3(0,0,0),
vec3(0,0,1));
mat4 mvp = view;
GLuint location = glGetUniformLocation(p_myGLSL->getProgramID(), "mvp");
glUniformMatrix4fv(location, 1, GL_FALSE, &mvp[0][0]);
glBindVertexArray(vaoHandle);
glDrawArrays(GL_TRIANGLES, 0, countV);
glFlush();
glutSwapBuffers();
Vertex shading code:
layout (location = 0) in vec3 VertexPosition;
uniform mat4 mvp;
void main()
{
gl_Position = mvp * vec4(VertexPosition,1.0);
}
VBO, VAO code:
// fill values into VBO
GLuint positionBufferHandle;
glGenBuffers(1, &positionBufferHandle);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
glBufferData(GL_ARRAY_BUFFER, countV*sizeof(float), positionData, GL_STATIC_DRAW);
// Vertex array object
glGenVertexArrays(1, &vaoHandle);
glBindVertexArray(vaoHandle);
// Read into vertex shader
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, 0, (GLubyte *) NULL);
glutMainLoop();
Why is it showing a blank screen for now?
P/S: If I create the view matrix manually it works:
mat4 translate = glm::translate(glm::mat4(1), vec3(-centerx, -centery, -centerz));
mat4 scale = glm::scale(glm::mat4(1), vec3(0.2, 0.2, 0.2));
mat4 mvp = scale * translate;
Use vec3(0,1,0) as up vector. When you are looking at (0,0,0) from (0,0,3), you looking in (0,0,-1) direction. The up vector should be perpendicular to this vector, which you can use vec3(0, 1, 0) vector. So, change the view matrix assignment part to:
mat4 view = glm::lookAt(vec3(0,0,3),
vec3(0,0,0),
vec3(0,1,0));
Also, Add #version 430 or whatever GLSL version which you are using to beginning of your vertex shader. layout qualifer is part of OpenGL core, since OpenGL 4.1 not earlier.
I am using GLM to manage my matrices, but I am running in to some problems that make no sense to me. When I set the projection matrix to anything other than an identity matrix, I can't see the square I am trying to draw. If it is an identity it will work. Something similiar happens with my view matrix. If I try and translate past -1 or +1 the square will dissapear, otherwise it seems to have no effects.
There are no OpenGL errors, GLSL linker/compiler errors, and glGetUniformLocation returns a valid location. Also the shader program is correctly being used.
Also I have tested the shader to see if it is getting the correct values passed to each of the matrices (by changing the color of the square if the value is correct).
Here's how I set up the projection matrix:
projectionMatrix = glm::perspective(60.0f, (float)windowWidth / (float)windowHeight, 0.1f, 100.0f);
And here's my draw function:
void OpenGLContext::render(void) {
glViewport(0, 0, windowWidth, windowHeight); // Set the viewport size to fill the window
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers
//Set up matrices
viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -5.0f));
modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(.5f));
shader->bind();
int projectionMatrixLocation = glGetUniformLocation(shader->id(), "projectionMatrix");
int viewMatrixLocation = glGetUniformLocation(shader->id(), "viewMatrix");
int modelMatrixLocation = glGetUniformLocation(shader->id(), "modelMatrix");
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]);
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]);
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, &modelMatrix[0][0]);
glBindVertexArray(vaoID[0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
shader->unbind();
SwapBuffers(hdc);
}
Here's the shader.vert
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec3 in_Position;
in vec3 in_Color;
out vec3 pass_Color;
void main(void)
{
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);
pass_Color = in_Color;
}
Here's shader.frag
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec3 pass_Color;
out vec4 out_Color;
void main(void)
{
out_Color = vec4(pass_Color, 1.0);
}
Sorry forgot about what i'm drawing:
void OpenGLContext::createSquare(void)
{
float* vertices = new float[18];
vertices[0] = -0.5; vertices[1] = -0.5; vertices[2] = 0.0; // Bottom left corner
vertices[3] = -0.5; vertices[4] = 0.5; vertices[5] = 0.0; // Top left corner
vertices[6] = 0.5; vertices[7] = 0.5; vertices[8] = 0.0; // Top Right corner
vertices[9] = 0.5; vertices[10] = -0.5; vertices[11] = 0.0; // Bottom right corner
vertices[12] = -0.5; vertices[13] = -0.5; vertices[14] = 0.0; // Bottom left corner
vertices[15] = 0.5; vertices[16] = 0.5; vertices[17] = 0.0; // Top Right corner
glGenVertexArrays(1, &vaoID[0]);
glBindVertexArray(vaoID[0]);
glGenBuffers(1, vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint) 0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0); // Disable our Vertex Array Object
glBindVertexArray(0);
delete [] vertices;
}
Setting my matrices like this results in nothing being drawn on the screen. Like I said if I set the projection and view matrices to an identity it will work. The scaling on the modelMatrix seems to always work as well.
There is no attribute on position 1 (in_Color). If you just left it out of this question, then the problem are the locations, which you are not defining in the shaders. I've never actually tested it without the location part, but I think it's necessary, at least for multiple values: you should use e.g. layout(location = 0) in in_Position.