Replacement for gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - c++

There are a couple of questions like this, but I still haven't really understood. I was coding with OpenGL over 10 years ago and noticed how difficult it is to get into modern OpenGL. The OpenGL.org page is a horrible mess when it comes to examples, you never know what version it is, any version seems to be mixed up in various code examples.
Alright, I have an old code I want to update to OpenGL >3 at least. So first thing I did was to move on from glVertex3fv to finally make it with glVertexAttribPointer (over a step with glVertexPointer until I read this is deprecated now as well). This works out fine, but when trying to place textures I got stuck quickly and I assume it is because of wrong positioning and I wanted to get rid of c++ code :
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0 );
and to draw it
// bind vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_STATIC_DRAW);
// enable arrays
glEnableVertexAttribArray(0);
// set pointers
glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);
// render ComplexSurface
glDrawArrays(GL_TRIANGLE_FAN, 0, size);
glDisableVertexAttribArray(0);
with in the vertexshader
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
And everything is working magically. Now don't get me wrong, I'm a big fan of magic, but...
Then I found a couple of matrix conversions which can be used to get a matrix to replace glFrustum, but whenever I try to replace it, it fails badly (although I think I understood the maths behind glFrustum and the conversion into the matrix).
What tried is something like
buildPerspProjMat(g_ProjView,FovAngle,Aspect,1.0,32768.0 );
glUseProgram(g_program);
glUniformMatrix4fv(g_programFrustum, 1, GL_FALSE, g_ProjView );
glUseProgram(0);
and using the position in the shader from the buffer above with the projection matix, but this doesn't work out at all.
So what I plain don't get now is where to replace this and with what in the shader. I don't know at which point the glMatrixMode takes place and "when" to replace it with some uniform matrix (passing the args as uniform ain't the problem here).
I can't count how many tutorials I read already, but I always get confused over all the mixed versions. I am always happy about some code examples, but please OpenGL 3 or higher.
The next would be a replacement for glTexCoord2f for texturing, but that's a different story :)

I find that when thinking about modern OpenGL it is best to forget that glMatrixMode ever existed.
With that in mind, let's go over what you need for the most basic draw operation: a replacement for gl_ModelViewProjectionMatrix. As it's name implies this is a combination of 3 different matrices: the model matrix, the view matrix, and the projection matrix.
So what you'll need in your shader to accomodate this is 3 uniform variables of type mat4. Which you'll use like so:
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
layout (location = 0) in vec3 position;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(position, 1.0);
}
This bit of shader code performs the same function as the one you had above. What changed is the built-in gl_ModelViewProjectionMatrix was replaced by 3 uniform variables (which could be combined as one if you make sure to multiply them yourself on the C++ side before passing it in). And the builtin gl_Vertex was replaced by an input variable.
On the C++ side you will need to do 2 things. First you'll need to get the location for each of these uniforms:
GLuint modelMatIdx = glGetUniformLocation(shaderProgId, "modelMat");
GLuint viewMatIdx = glGetUniformLocation(shaderProgId, "viewMat");
GLuint projMatIdx = glGetUniformLocation(shaderProgId, "projMat");
And with this in hand you can now pass in the values for each uniform right before drawing using glUniformMatrix4fv.
One particular library which makes this particularly easy is glm. For example to get the same projection matrix as in your example you would do:
glm::mat4 projMat = glm::frustum(-RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0);
and you would pass it in like so:
glUniformMatrix4fv(projMatIdx, 1, GL_FALSE, glm::value_ptr(projMat));
Now that you know how, I'd like to address the issue of "when". You said you weren't clear about the matrix mode stuff and that brings me back to my earlier assertion of "forget about it". The matrix mode was there so that you could tell opengl which built in should be affected by calls to OpenGL matrix operations such as glTranslate, glFrustum and so on, but all of this is gone now. You are now in charge of managing the (possibly many) matrices involved. All you have to do is pass them in before you draw (as I've shown above) and you'll be fine. Just make sure the program is bound before you attempt to modify its uniforms.
Here's a working example (if you're suprised by gl::... instead of gl... it's because I'm using an opengl header generated by glLoadGen which puts all of the opengl API functions in the gl namespace).
GLuint simpleProgramID;
// load the shader and make the program
GLuint modelMatIdx = gl::GetUniformLocation(simpleProgramID, "modelMat");
GLuint viewMatIdx = gl::GetUniformLocation(simpleProgramID, "viewMat");
GLuint projMatIdx = gl::GetUniformLocation(simpleProgramID, "projMat");
GLuint vaoID;
gl::GenVertexArrays(1, &vaoID);
gl::BindVertexArray(vaoID);
GLuint vertBufferID, indexBufferID;
gl::GenBuffers(1, &vertBufferID);
gl::GenBuffers(1, &indexBufferID);
struct Vec2 { float x, y; };
struct Vec3 { float x, y, z; };
struct Vert { Vec3 pos; Vec2 tex; };
std::array<Vert, 8> cubeVerts = {{
{ { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f } }, { { 0.5f, 0.5f, -0.5f }, { 1.0f, 1.0f } },
{ { 0.5f, -0.5f, -0.5f }, { 0.0f, 1.0f } }, { { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f } },
{ { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f } }, { { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f } },
{ { -0.5f, -0.5f, -0.5f }, { 1.0f, 1.0f } }, { { -0.5f, -0.5f, 0.5f }, { 1.0f, 0.0f } }
}};
std::array<unsigned int, 36> cubeIdxs = {{
0, 2, 1, 0, 3, 2, // Right
4, 5, 6, 4, 6, 7, // Left
0, 7, 3, 0, 4, 7, // Top
1, 6, 2, 1, 5, 6, // Bottom
0, 5, 1, 0, 4, 5, // Front
3, 7, 6, 3, 6, 2 // Back
}};
// Vertex buffer
gl::BindBuffer(gl::ARRAY_BUFFER, vertBufferID);
gl::BufferData(gl::ARRAY_BUFFER, sizeof(Vert) * cubeVerts.size(), cubeVerts.data(), gl::STATIC_DRAW);
gl::EnableVertexAttribArray(0); // Matches layout (location = 0)
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE_, sizeof(Vert), 0);
gl::EnableVertexAttribArray(1); // Matches layout (location = 1)
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE_, sizeof(Vert), (GLvoid*)sizeof(Vec3));
// Index buffer
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indexBufferID);
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * cubeIdxs.size(), cubeIdxs.data(), gl::STATIC_DRAW);
gl::BindVertexArray(0);
glm::mat4 projMat = glm::perspective(56.25f, 16.0f/9.0f, 0.1f, 100.0f);
glm::mat4 viewMat = glm::lookAt(glm::vec3(5, 5, 5), glm::vec3(0, 0, 0), glm::vec3(0, 0, 1));
glm::mat4 modelMat; // identity
while (!glfwWindowShouldClose(window))
{
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
gl::UseProgram(simpleProgramID);
gl::UniformMatrix4fv(projMatIdx, 1, gl::FALSE_, glm::value_ptr(projMat));
gl::UniformMatrix4fv(viewMatIdx, 1, gl::FALSE_, glm::value_ptr(viewMat));
gl::UniformMatrix4fv(modelMatIdx, 1, gl::FALSE_, glm::value_ptr(modelMat));
gl::BindVertexArray(vaoID);
gl::DrawElements(gl::TRIANGLES, 36, gl::UNSIGNED_INT, 0);
gl::BindVertexArray(0);
gl::UseProgram(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
Associated Vertex Shader:
//[VERTEX SHADER]
#version 430
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
layout (location = 0) in vec3 in_position; // matches gl::EnableVertexAttribArray(0);
layout (location = 1) in vec2 in_uv; // matches gl::EnableVertexAttribArray(1);
out vec2 uv;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(in_position, 1.0);
uv = in_uv;
}
And finally Fragment shader:
//[FRAGMENT SHADER]
#version 430
in vec2 uv;
out vec4 color;
void main()
{
color = vec4(uv, 0.0, 1.0);
}
The resulting image is:

Well, I agree that most OpenGL tutorials confuse bits of deprecated and non-deprecated stuff. To get you in the right direction, let me explain.
gl_ModelViewProjectionMatrix, gl_ModeView, glMatrixMode() and the matrix stack glPushMatrix() glPopMatrix() are deprecated. You need to define your own matrices as a uniform variables then set and pass them to the shader using glUniform*.
gl_Vertex is also deprecated, actually the whole fixed attributes names are deprecated. Alternatively you need to define your own attribute names and bind them to specific locations. Then you can set their values using glVertexAttribPointer by passing the attribute location to it (Full explanation here). For example:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); // for vertices
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, color); // for color
And for the shader code
layout (location = 0) in vec4 vertex;
layout (location = 1) in vec4 color;
uniform mat4 modelview;
uniform mat4 projection;
void main()
{
gl_Position = projection* modelview* vertex;
}
For the attributes locations you can set them in the shader code as I did, or from OpenGL API using glBindAttribLocation.
Managing uniform variables can be somehow tricky if you are used to the old OpenGL globals variables such as gl_ModelView I wrote an article that hopefully can help you manage uniform variables for a big project.

Related

How do I get this vector of objects to render in OpenGL?

My scene: (the video is blurry because I had to convert this to a GIF)
There are two other objects that should be rendered here!
I am writing a program with GLFW/OpenGL. Essentially what I am trying to do is to be able to render a bunch of independent objects, who all can move freely around. To do this, I create a shader, a VAO, a VBO, and a EBO for each model that I want to render. static_models is a vector of class Model, and class Model is just a way to organize my vertices, indices, colors, and normals.
First is creating the vector of Models: (I know this class works as it should, because I use the exact same class for different shaders and buffer objects and things render well)
std::vector<Model> static_models; // scale // color
Model plane("models/plane.ply", { 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f });
Model tetrahedron("models/tetrahedron.ply", { 1.0f, 1.0f, 1.0f }, { 0.2f, 1.0f, 1.0f });
static_models.emplace_back(plane);
static_models.emplace_back(tetrahedron);
The code for generating the shader objects, VAOS, VBOS, and EBOS:
for (int i = 0; i < static_models.size(); i++)
{
Shader tempShader("plane.vert", "plane.frag");
// create a shader program for each model (in case we need to rotate them or transform them in some way they will be independent)
static_model_shaders.emplace_back(tempShader);
VAOS_static.emplace_back();
VAOS_static.back().Bind();
VBO tempVBO(&static_models.at(i).vertices.front(), static_models.at(i).vertices.size() * sizeof(GLfloat));
EBO tempEBO(&static_models.at(i).indices.front(), static_models.at(i).indices.size() * sizeof(GLuint));
VAOS_static.back().LinkAttrib(tempVBO, 0, 3, GL_FLOAT, 11 * sizeof(float), (void*)0);
VAOS_static.back().LinkAttrib(tempVBO, 1, 3, GL_FLOAT, 11 * sizeof(float), (void*)(3 * sizeof(float)));
VAOS_static.back().LinkAttrib(tempVBO, 2, 2, GL_FLOAT, 11 * sizeof(float), (void*)(6 * sizeof(float)));
VAOS_static.back().LinkAttrib(tempVBO, 3, 3, GL_FLOAT, 11 * sizeof(float), (void*)(8 * sizeof(float)));
VAOS_static.back().Unbind();
tempVBO.Unbind();
tempEBO.Unbind();
}
Then the code to create the positions and mat4 matrixes for each model:
// static model vectors for position and matrix
std::vector<glm::vec3> staticModelPositions;
std::vector<glm::mat4> staticModels;
// initialize all static_model object positions
for (int i = 0; i < static_models.size(); i++)
{
staticModelPositions.emplace_back();
staticModelPositions.back() = glm::vec3(0.0f, 1.0f, 0.0f);
staticModels.emplace_back();
staticModels.back() = glm::translate(staticModels.back(), staticModelPositions.back());
}
Then I set some initial values for the uniforms:
std::vector<Texture> textures;
//static objects
for (int i = 0; i < static_models.size(); i++)
{
//activate first before setting uniforms
static_model_shaders.at(i).Activate();
// static model load model, then load lightColor, then load lightPos for each static_model
glUniformMatrix4fv(glGetUniformLocation(static_model_shaders.at(i).ID, "model"), 1, GL_FALSE, glm::value_ptr(staticModels.at(i)));
glUniform4f(glGetUniformLocation(static_model_shaders.at(i).ID, "lightColor"), lightColor.x, lightColor.y, lightColor.z, 1.0f);
glUniform3f(glGetUniformLocation(static_model_shaders.at(i).ID, "lightPos"), lightPos.x, lightPos.y, lightPos.z);
//create texture objects
textures.emplace_back(Texture("brick.png", GL_TEXTURE_2D, GL_TEXTURE0, GL_RGBA, GL_UNSIGNED_BYTE));
textures.back().texUnit(static_model_shaders.at(i), "tex0", 0);
}
Then drawing the models in the game loop: (game loop not shown this is a big program)
//draw all static models (each with a different shader and matrix)
for (int i = 0; i < static_model_shaders.size(); i++)
{
//activate shader for current model
// Tells OpenGL which Shader Program we want to use
static_model_shaders.at(i).Activate();
// Exports the camera Position to the Fragment Shader for specular lighting
glUniform3f(glGetUniformLocation(static_model_shaders.at(i).ID, "camPos"), camera.Position.x, camera.Position.y, camera.Position.z);
glUniformMatrix4fv(glGetUniformLocation(static_model_shaders.at(i).ID, "model"), 1, GL_FALSE, glm::value_ptr(staticModels.at(i)));
glUniform4f(glGetUniformLocation(static_model_shaders.at(i).ID, "lightColor"), lightColor.x, lightColor.y, lightColor.z, 1.0f);
// Export the camMatrix to the Vertex Shader of the pyramid
camera.Matrix(static_model_shaders.at(i), "camMatrix");
// Binds texture so that is appears in rendering
textures.at(i).Bind();
VAOS_static.at(i).Bind();
glDrawElements(GL_TRIANGLES, static_models.at(i).indices.size(), GL_UNSIGNED_INT, 0);
VAOS_static.at(i).Unbind();
}
My vertex shader:
#version 330 core
// Positions/Coordinates
layout (location = 0) in vec3 aPos;
// Colors
layout (location = 1) in vec3 aColor;
// Texture Coordinates
layout (location = 2) in vec2 aTex;
// Normals (not necessarily normalized)
layout (location = 3) in vec3 aNormal;
// Outputs the color for the Fragment Shader
out vec3 color;
// Outputs the texture coordinates to the Fragment Shader
out vec2 texCoord;
// Outputs the normal for the Fragment Shader
out vec3 Normal;
// Outputs the current position for the Fragment Shader
out vec3 crntPos;
// Imports the camera matrix from the main function
uniform mat4 camMatrix;
// Imports the model matrix from the main function
uniform mat4 model;
void main()
{
// calculates current position
crntPos = vec3(model * vec4(aPos, 1.0f));
// Outputs the positions/coordinates of all vertices
gl_Position = camMatrix * vec4(crntPos, 1.0);
// Assigns the colors from the Vertex Data to "color"
color = aColor;
// Assigns the texture coordinates from the Vertex Data to "texCoord"
texCoord = aTex;
// Assigns the normal from the Vertex Data to "Normal"
Normal = aNormal;
}
And fragment shader:
#version 330 core
// Outputs colors in RGBA
out vec4 FragColor;
// Imports the color from the Vertex Shader
in vec3 color;
// Imports the texture coordinates from the Vertex Shader
in vec2 texCoord;
// Imports the normal from the Vertex Shader
in vec3 Normal;
// Imports the current position from the Vertex Shader
in vec3 crntPos;
// Gets the Texture Unit from the main function
uniform sampler2D tex0;
// Gets the color of the light from the main function
uniform vec4 lightColor;
// Gets the position of the light from the main function
uniform vec3 lightPos;
// Gets the position of the camera from the main function
uniform vec3 camPos;
void main()
{
// ambient lighting
float ambient = 0.40f;
// diffuse lighting
vec3 normal = normalize(Normal);
vec3 lightDirection = normalize(lightPos - crntPos);
float diffuse = max(dot(normal, lightDirection), 0.0f);
// specular lighting
float specularLight = 0.50f;
vec3 viewDirection = normalize(camPos - crntPos);
vec3 reflectionDirection = reflect(-lightDirection, normal);
float specAmount = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 8);
float specular = specAmount * specularLight;
// outputs final color
FragColor = texture(tex0, texCoord) * lightColor * (diffuse + ambient + specular);
}
I have other objects in the scene, and they render and update well. There are no errors in the code and everything runs fine, the objects in static_models are just not being rendered. Anyone have any ideas as to why it wouldn't be showing anything?
I fixed this after a very long time spent. The issue was this block of code:
// static model vectors for position and matrix
std::vector<glm::vec3> staticModelPositions;
std::vector<glm::mat4> staticModels;
// initialize all static_model object positions
for (int i = 0; i < static_models.size(); i++)
{
staticModelPositions.emplace_back();
staticModelPositions.back() = glm::vec3(0.0f, 1.0f, 0.0f);
staticModels.emplace_back();
staticModels.back() = glm::translate(staticModels.back(), staticModelPositions.back());
}
There is a line missing here. After doing staticModels.emplace_back(); we must create the identity matrix for the model. This code allows the program to function as intended:
// static model vectors for position and matrix
std::vector<glm::vec3> staticModelPositions;
std::vector<glm::mat4> staticModels;
// initialize all static_model object positions
for (int i = 0; i < static_models.size(); i++)
{
staticModelPositions.emplace_back();
staticModelPositions.back() = glm::vec3(0.0f, 1.0f, 0.0f);
staticModels.emplace_back();
staticModels.at(i) = glm::mat4(1.0f);
staticModels.back() = glm::translate(staticModels.back(), staticModelPositions.back());
}

Triangle Vertexes in wrong place with GLM Orthographic Projection Matrix

Rencently, I am trying to render a triangle(as Figure 1) in my Window Content View (OSX NSView) using OpenGL, I make an "Orthographic projection" with GLM library function glm::ortho, after render, the vertexes of the triangle are all in wrong place, they seems has an offset to the Window Content View.
I have 2 questions:
Am I misunderstood about glm::ortho(base the following code)?
When the window resize(Zoom In, Zoom Out), How to keep the triangle retain the same place in the Window(i.e. the top vertex at the middle of the width, and the bottom vertexes at the corner)?
The following is the result:
my render function:
- (void)render
{
float view_width = self.frame.size.width;
float view_height = self.frame.size.height;
glViewport(0, 0, view_width, view_height);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Using Orthographic Projection Matrix, vertex position
// using view coordinate(pixel coordinate)
float positions[] = {
0.0f, 0.0f, 0.0f, 1.0f,
view_width, 0.0f, 0.0f, 1.0f,
view_width/(float)2.0, view_height, 0.0f, 1.0f,
};
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), positions);
glm::mat4 p = glm::ortho(0.0f, view_width, 0.0f, view_height);
glm::mat4 v = glm::lookAt(glm::vec3(0, 0, 1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
glm::mat4 m = glm::mat4(1.0f);
// upload uniforms to shader
glUniformMatrix4fv(_projectionUniform, 1, GL_FALSE, &p[0][0]);
glUniformMatrix4fv(_viewUniform, 1, GL_FALSE, &v[0][0]);
glUniformMatrix4fv(_modelUniform, 1, GL_FALSE, &m[0][0]);
glDrawElements(GL_TRIANGLE_STRIP, sizeof(positions) / sizeof(positions[0]),GL_UNSIGNED_SHORT, 0);
[_openGLContext flushBuffer];
}
my vertex shader:
#version 410
in vec4 position;
uniform highp mat4 projection;
uniform highp mat4 view;
uniform highp mat4 model;
void main (void)
{
gl_Position = position * projection * view * model;
}
A glm matrix is initialized in the same way as GLSL matrix. See The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors, page 101 for further information.
A vector has to be multiplied to the matrix from the right.
See GLSL Programming/Vector and Matrix Operations:
Note that the vector has to be multiplied to the matrix from the right.
If a vector is multiplied to a matrix from the left, the result corresponds to multiplying a row vector from the left to the matrix. This corresponds to multiplying a column vector to the transposed matrix from the right.
This means you've to change the vertex transformation in the vertex shader:
gl_Position = position * projection * view * model;
gl_Position = projection * view * model * position;
#Rabbid76 has answered my first question, it works! Thanks a lot.
The second question, in OSX, when resizing a window(contain a OpenGL View), the NSOpenGLContext should be update, like this:
- (void)setFrameSize:(NSSize)newSize {
[super setFrameSize:newSize];
// update the _openGLContext object
[_openGLContext update];
// reset viewport
glViewport(0, 0, newSize.width*2, newSize.height*2);
// render
[self render];
}

OpenGL Matrices and Shaders Confusion

I've been following a tutorial on modern OpenGL with the GLM library
I'm on a segment where we introduce matrices for transforming models, positioning the camera, and adding perspective.
I've got a triangle:
const GLfloat vertexBufferData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
I've got my shaders:
GLuint programID = loadShaders("testVertexShader.glsl",
"testFragmentShader.glsl");
I've got a model matrix that does no transformations:
glm::mat4 modelMatrix = glm::mat4(1.0f); /* Identity matrix */
I've got a camera matrix:
glm::mat4 cameraMatrix = glm::lookAt(
glm::vec3(4.0f, 4.0f, 3.0f), /*Camera position*/
glm::vec3(0.0f, 0.0f, 0.0f), /*Camera target*/
glm::vec3(0.0f, 1.0f, 0.0f) /*Up vector*/
);
And I've got a projection matrix:
glm::mat4 projectionMatrix = glm::perspective(
90.0f, /*FOV in degrees*/
4.0f / 3.0f, /*Aspect ratio*/
0.1f, /*Near clipping distance*/
100.0f /*Far clipping distance*/
);
Then I multiply all the matrices together to get the final matrix for the triangle I want to draw:
glm::mat4 finalMatrix = projectionMatrix
* cameraMatrix
* modelMatrix;
Then I send the matrix to GLSL (I think?):
GLuint matrixID = glGetUniformLocation(programID, "MVP");
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &finalMatrix[0][0]);
Then I do shader stuff I don't understand very well:
/*vertex shader*/
#version 330 core
in vec3 vertexPosition_modelspace;
uniform mat4 MVP;
void main(){
vec4 v = vec4(vertexPosition_modelspace, 1);
gl_Position = MVP * v;
}
/*fragment shader*/
#version 330 core
out vec3 color;
void main(){
color = vec3(1, 1, 0);
}
Everything compiles and runs, but I see no triangle. I've moved the triangle and camera around, thinking maybe the camera was pointed the wrong way, but with no success. I was able to successfully get a triangle on the screen before we introduced matrices, but now, no triangle. The triangle should be at origin, and the camera is a few units away from origin, looking at origin.
Turns out, you need to send the matrix to the shader after you've bound the shader.
In other words, you call glUniformMatrix4fv() after glUseProgram()
Lots of things could be your problem - try outputting a vec4 color instead, with alpha explicitly set to 1. One thing I often do as a sanity check is to have the vertex shader ignore all inputs, and to just output vertices directly, e.g. something like:
void main(){
if (gl_VertexID == 0) {
gl_Position = vec4(-1, -1, 0, 1);
} else if (gl_VertexID == 1) {
gl_Position = vec4(1, -1, 0, 1);
} else if (gl_VertexID == 2) {
gl_Position = vec4(0, 1, 0, 1);
}
}
If that works, then you can try adding your vertex position input back in. If that works, you can add your camera or projection matrices back in, etc.
More generally, remove things until something works, and you understand why it works, and then add parts back in until you stop understanding why things don't work. Quite often I've been off by a sign, or in the order of multiplication.

OpenGL : Why can't I pass a single float from vertex shader to fragment shader?

EDIT: see at the end for new investigations on the subject.
I've been experiencing an odd behavior with my shaders. In short, I find it very strange that to pass a single float from a vertex shader to a fragment shader I have to pass also a fake variable, and I am looking for an explanation of this behavior.
In more details : I wrote two minimalistic shaders
a vertex shader that passes one float (only one, this is important), vertAlpha, to the fragment shader, like so:
#version 150
uniform float alphaFactor;
uniform mat4 cameramodel;
in float vertAlpha;
in vec3 vert;
in vec3 vertScale;
in vec3 trans;
out float fragAlpha;
void main()
{
fragAlpha = alphaFactor * vertAlpha;
gl_Position = cameramodel * vec4( trans + ( vert * vertScale ), 1.0f );
}
and a fragment shader that uses the passed variable:
#version 150
in float fragAlpha;
out vec4 finalColor;
void main()
{
finalColor = vec4( 0.0f, 0.0f, 0.0f, fragAlpha );
}
But that doesn't work, nothing appears on the screen, it seems that in the fragment shader, fragAlpha keeps it's initialization value of 0, and ignores the passed value.
After investigating, I found a "hack" to solve this. I found that the fragment shader "sees" the passed value for fragAlpha only if a fake (unused) value is passed with it (depending on the platform (osx / NVidia GeForce 9400, Windows laptop / Intel HD Graphics), a vec3 or a vec2 is sufficient).
So this vertex shader solves the problem:
#version 150
uniform float alphaFactor;
uniform mat4 cameramodel;
in vec3 vertFake;
in float vertAlpha;
in vec3 vert;
in vec3 vertScale;
in vec3 trans;
out float fragAlpha;
out vec3 fragFake;
void main()
{
fragAlpha = alphaFactor * vertAlpha;
fragFake = vertFake;
gl_Position = cameramodel * vec4( trans + ( vert * vertScale ), 1.0f );
}
I find this more like a "hack" than a solution. What should I do to solve this properly?
Is there a "per-driver manufacturer minimum threshold" in terms of size of data that can pass from a vertex shader to a fragment shader?
EDIT:
After reading derhass comment, I went back to my code to see if I was doing something wrong.
After more investigation, I found that the problem is not inherent to the fact that I pass the attribute value to the fragment shader. I changed the order of attributes declarations in the vertex shader and saw that the attribute that has the "0" location (location returned by glGetAttribLocation) is not updated by a call to glVertexAttribute, it's value stays at 0.
It will occur for example for the "trans" attribute if it is declared before all other attributes. Introducing a fake attribute in my shader only fixed the issue because the fake attribute took the location "0".
In any case, glGetError returns no error anywhere.
I use glDrawElements to render, with a vbo that contains the vertex positions, maybe I'm using it inadequatly... or it's not well supported by my hardware(s)?
To give some more context, I copy here the calls i do to opengl, for setup and rendering:
Setup:
GLuint vao, vbo;
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLfloat vertexData[] = {
// X Y Z
0.0f, 0.0f, 1.0f, // 0
1.0f, 0.0f, 1.0f, // 1
0.0f, 0.0f, 0.0f, // 2
1.0f, 0.0f, 0.0f, // 3
0.0f, 1.0f, 1.0f, // 4
1.0f, 1.0f, 1.0f, // 5
1.0f, 1.0f, 0.0f, // 6
0.0f, 1.0f, 0.0f // 7
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
GLint vert = glGetAttribLocation(p, "vert")
glEnableVertexAttribArray(vert);
glVertexAttribPointer(vert, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindVertexArray(0);
render:
glUseProgram(p)
aphaFactor = glGetUniformLocation(p,"alphaFactor");
glUniform1f(alphaFactor, 1.0f);
cameramodel = glGetUniformLocation(p,"cameramodel");
glm::mat4 mat = gCamera.matrix();
glUniformMatrix4fv(cameramodel, 1, GL_FALSE, glm::value_ptr(mat); //
glBindVertexArray(vao);
GLubyte indices[36] =
{
3, 2, 6, 7, 6, 2, 6, 7, 4, 2, 4, 7, 4, 2, 0, 3, 0, 2, 0, 3, 1, 6, 1, 3, 1, 6, 5, 4, 5, 6, 5, 4, 1, 0, 1, 4
};
GLint trans = glGetAttribLocation(p, "trans");
GLint alpha = glGetAttribLocation(p, "vertAlpha");
GLint scale = glGetAttribLocation(p, "vertScale");
loop over many entities:
glVertexAttrib3f(trans, m_vInstTransData[offset], m_vInstTransData[offset + 1], m_vInstTransData[offset + 2]);
glVertexAttrib1f(alpha, m_vInstTransData[offset + 3]);
glVertexAttrib3f(scale, m_vInstTransData[offset + 4], m_vInstTransData[offset + 5], m_vInstTransData[offset + 6]);
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
end loop
glBindVertexArray(0);
you need to specify the interpolator for this so to prevent interpolation between fragments of the same primitive change:
out float fragAlpha;
in float fragAlpha;
into:
out flat float fragAlpha;
in flat float fragAlpha;
because float is interpolated by default. Similarly mat3 is not interpolated by default and if you want to interpolate it then use smooth instead of flat ...
If I remember correctly Scalars (int,float,double) and vectors (vec?,dvec?) are interpolated by default and matrices (mat?) are not.
Not sure which property will be set in your flat variable my bet is the one set on the last vertex of the primitive pass ... In case you need to compute it on some specified vertex then you should move the computation into geometry shader.

How to do instancing the right way in OpenGL.

I am trying to use VBO and Instancing mechanism the most efficent way. I have a world based on voxels and I would like to draw them using least possible number of draw-calls. The code below prepares VBO with a quad:
void VoxelView::initVBOs() {
/*--------------------- Main OpenGL Program ---------------------*/
/* Vertices of a triangle (counter-clockwise winding) */
float data[6][3] = {
// Left bottom triangle
{ -0.5f, 0.5f, 0.0f },
{ -0.5f, -0.5f, 0.0f },
{ 0.5f, -0.5f, 0.0f },
// Right top triangle
{ 0.5f, -0.5f, 0.0f },
{ 0.5f, 0.5f, 0.0f },
{ -0.5f, 0.5f, 0.0f }
};
/*---------------------- Initialise VBO - (Note: do only once, at start of program) ---------------------*/
/* Create a new VBO and use the variable "triangleVBO" to store the VBO id */
glGenBuffers(1, &triangleVBO);
/* Make the new VBO active */
glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
/* Upload vertex data to the video device */
glBufferData(GL_ARRAY_BUFFER, 6 * 3 * sizeof(float), data, GL_STATIC_DRAW);
/* Specify that our coordinate data is going into attribute index 0(shaderAttribute), and contains three floats per vertex */
glVertexAttribPointer(shaderAttribute, 3, GL_FLOAT, GL_FALSE, 0, 0);
/* Enable attribute index 0(shaderAttribute) as being used */
glEnableVertexAttribArray(shaderAttribute);
/* Make the new VBO active. */
glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
/*-------------------------------------------------------------------------------------------------------*/
/*--------------------- Load Vertex and Fragment shaders from files and compile them --------------------*/
/* Read our shaders into the appropriate buffers */
vertexSource = filetobuf("Shaders/exampleVertexShader1.vert");
fragmentSource = filetobuf("Shaders/exampleFragmentShader1.frag");
/* Assign our handles a "name" to new shader objects */
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
/* Associate the source code buffers with each handle */
glShaderSource(vertexShader, 1, (const GLchar**)&vertexSource, 0);
glShaderSource(fragmentShader, 1, (const GLchar**)&fragmentSource, 0);
/* Free the temporary allocated memory */
free(vertexSource);
free(fragmentSource);
/* Compile our shader objects */
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
/*-------------------------------------------------------------------------------------------------------*/
/*-------------------- Create shader program, attach shaders to it and then link it ---------------------*/
/* Assign our program handle a "name" */
shaderProgram = glCreateProgram();
/* Attach our shaders to our program */
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
/* Bind attribute index 0 (shaderAttribute) to in_Position*/
/* "in_Position" will represent "data" array's contents in the vertex shader */
glBindAttribLocation(shaderProgram, shaderAttribute, "in_Position");
/* Link shader program*/
glLinkProgram(shaderProgram);
I am rendering the quad the following way:
void VoxelView::renderVBO()
{
/* Set shader program as being actively used */
glUseProgram(shaderProgram);
/* Set background colour to BLACK */
glClearColor(0.0, 0.0, 0.0, 1.0);
/* Clear background with BLACK colour */
glClear(GL_COLOR_BUFFER_BIT);
/* Actually draw the triangle, giving the number of vertices provided by invoke glDrawArrays
while telling that our data is a triangle and we want to draw 0-3 vertexes
*/
glDrawArrays(GL_TRIANGLES, 0, 6);
}
I would like to draw this quad (which uses VBO) multiple times using the instancing mechanizm. I would like it to fe fairly simple as I want to implement it for more sophisticated code. I know that I should use glDrawElementsInstanced method to use instancing but I don't know how to do it. Does anybody know how to do it?
When using glDrawElementsInstanced you need to make your shaders use gl_InstanceiD
#version 410
layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;
layout (location = 3) in mat4 WVP;
layout (location = 7) in mat4 World;
out vec2 TexCoord0;
out vec3 Normal0;
out vec3 WorldPos0;
flat out int InstanceID;
void main()
{
gl_Position = WVP * vec4(Position, 1.0);
TexCoord0 = TexCoord;
Normal0 = World * vec4(Normal, 0.0)).xyz;
WorldPos0 = World * vec4(Position, 1.0)).xyz;
InstanceID = gl_InstanceID;
};
glDrawElementsInstanced use gl_InstanceID variable as if it were a static integer vertex attribute. When the first copy of the vertices is sent to OpenGL,
gl_InstanceID will be zero. It will then be incremented once for each copy of the geometry and will eventually reach instanceCount - 1.
It behaves like this
for (int n = 0; n < instancecount; n++)
{
// Set the value of gl_InstanceID
glVertexAttrib1i(gl_InstanceID, n); // except this is internally incremented and not a real vertex attribute
// Make a normal call to glDrawElements
glDrawElements(mode, count, type, indices);
}
Except that this happens internally, and you only need to call glDrawArraysInstanced() once. In order to use different transforms for each instance you can pass an array of uniform matrices and index that using gl_InstanceID or you can use texture buffer objects and store transforms there.
So your drawing code should become like this, but note that you still need to pass uniform matrices for each intsance in an array or pass a texture buffer object once for all.
glDrawElementsInstanced(primitivetype, indices, GL_UNSIGNED_INT, 0, instanceCount-1);
and your vertex shader should become
uniform mat4 instancematrices[32];
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * instancematrices[gl_InstanceID] * gl_Vertex;
}