I'm trying to implement instancing into my 2d Game Engine so that it can support particle systems without losing any performance. My class, ISprite, is derived from a working Sprite class. I just went through and removed all the functionality affecting single sprites and replaced it with an instancing plan in mind. Unfortunately, nothing is drawing on the screen.
Here is the relevant information:
Vertex Shader
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoords;
layout (location = 2) in vec4 colorSource;
layout (location = 3) in mat4 transform;
out vec2 TexCoords;
out vec4 Color;
uniform mat4 uniformView;
uniform mat4 uniformProjection;
void main()
{
gl_Position = uniformProjection * uniformView * transform * vec4(position, 1.0f);
TexCoords = texCoords;
Color = colorSource;
}
Fragment Shader
#version 330 core
in vec2 TexCoords;
in vec4 Color;
out vec4 color;
uniform sampler2D Texture;
uniform vec4 uniformColor;
void main()
{
vec4 texColor = texture(Texture, TexCoords) * Color;
if(texColor.a < 0.1)
discard;
color = texColor;
}
Load - Prepares all sprites for drawing, called once.
void ISprite::Load(Shader spriteShader)
{
spriteShader.Use();
GLfloat vertices[] = {
//X Y Z
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
glGenVertexArrays(1, &vertexArray);
glGenBuffers(1, &positionBuffer);
glGenBuffers(1, &texCoordsBuffer);
glGenBuffers(1, &colorBuffer);
glGenBuffers(1, &matrixBuffer);
glBindVertexArray(vertexArray);
//The vertex data will never change, so send that data now.
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//For vertex Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (GLvoid*)0);
//For texture coordinates
glBindBuffer(GL_ARRAY_BUFFER, texCoordsBuffer);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0);
//For Color
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);
//For Transformation Matrix
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
for (int i = 0; i < 4; ++i)
{
glEnableVertexAttribArray(3 + i);
glVertexAttribPointer(3 + i, 4, GL_FLOAT, GL_FALSE,
4 * 4 * sizeof(GLfloat), (GLvoid*)(4 * i * sizeof(GLfloat)));
}
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texCoordsBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
glBindVertexArray(0);
glVertexAttribDivisor(positionBuffer, 0);
glVertexAttribDivisor(texCoordsBuffer, 1);
glVertexAttribDivisor(colorBuffer, 1);
glVertexAttribDivisor(matrixBuffer, 1);
glVertexAttribDivisor(matrixBuffer + 1, 1);
glVertexAttribDivisor(matrixBuffer + 2, 1);
glVertexAttribDivisor(matrixBuffer + 3, 1);
ISprite::shader = &spriteShader;
}
Prepare Draw - called by each sprite, each frame. Sends data to static vectors
void ISprite::prepareDraw(void)
{
//Adds their personal data to vectors shared by class
glm::mat4 transform = calculateTransorm();
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
ISprite::transformMatrices.push_back(transform[i][j]);
}
texture.updateAnimation();
for (int i = 0; i < 12; ++i)
ISprite::textureCoordinatesAll.push_back(texture.textureCoordinates[i]);
ISprite::colorValues.push_back(color.x);
ISprite::colorValues.push_back(color.y);
ISprite::colorValues.push_back(color.z);
ISprite::colorValues.push_back(color.w);
}
Draw Sprites - called once each frame, actually draws the sprites
void ISprite::drawSprites(Texture testTexture)
{
shader->Use();
for (std::vector<ISprite*>::iterator it = Isprites.begin(); it != Isprites.end(); ++it)
(*it)->prepareDraw();
glBindVertexArray(vertexArray);
glBindTexture(GL_TEXTURE_2D, testTexture.ID);
//Bind texture here if you want textures to work. if not, a single texture atlas will be bound
glBindBuffer(GL_ARRAY_BUFFER, texCoordsBuffer);
glBufferData(GL_ARRAY_BUFFER, textureCoordinatesAll.size() * sizeof(GLfloat),
textureCoordinatesAll.data(), GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, colorValues.size() * sizeof(GLfloat),
colorValues.data(), GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
glBufferData(GL_ARRAY_BUFFER, transformMatrices.size() * sizeof(GLfloat),
transformMatrices.data(), GL_STREAM_DRAW);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 6, Isprites.size());
textureCoordinatesAll.clear();
colorValues.clear();
transformMatrices.clear();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
}
There could be a lot of reasons why nothing is rendered. Problems with the transformations, coordinates out of range, etc. But one thing related to instancing definitely looks wrong in the posted code:
glBindVertexArray(0);
glVertexAttribDivisor(positionBuffer, 0);
glVertexAttribDivisor(texCoordsBuffer, 1);
glVertexAttribDivisor(colorBuffer, 1);
...
The first argument to glVertexAttribDivisor() is the location of a vertex attribute, not the name of a buffer. Also, the state set by this call is part of the VAO state, so you should make these calls while the VAO is still bound.
So the calls should look like this:
glVertexAttribDivisor(0, 0);
glVertexAttribDivisor(1, 0);
glVertexAttribDivisor(2, 1);
...
glBindVertexArray(0);
where the first arguments to glVertexAttribDivisor() match the location values you also use as the first argument to glVertexAttribPointer() and glEnableVertexAttribArray().
The divisor value for the texture coordinates (attribute 1) should most likely be 0, since you want the texture coordinates to be set per vertex, just like the positions. For the colors and other remaining attributes, 1 is the correct value so that they are applied per instance.
Also, as I mentioned in a comment, you may also want to look into using point sprites. While they do not offer the same flexibility you can get from drawing individual quads, they can often be used for sprites. With point sprites, you only need one vertex per sprite, and the texture coordinates are generated automatically. My answer here gives an outline on how point sprites are used, including how to apply textures to them: Render large circular points in modern OpenGL.
Related
I cannot get texture coordinates to have any effect on what is rendered on screen. My texture constantly seemed to rendering from 0,0 to 1,1.
The method I am using is to send the following buffer layout: x,y,u,v (xy: vertex position and u,v texture coordinates).
However, changing the values u & v have no effect on the rendered texture.
I've removed a lot of surrounding code to try and make it easier to read, but I can post it in full if the problem isn't immediately obvious to someone.
Vertex Shader:
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 mytextpos;
out vec2 v_TexCoord;
uniform mat4 u_Model;
void main()
{
gl_Position = u_Model * vec4(position, 0.0f, 1.0f);
v_TexCoord = mytextpos;
}
Fragment Shader:
#version 330 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
uniform sampler2D u_Texture;
void main()
{
color = texture(u_Texture, v_TexCoord);
}
My Rectangle Class Constructor:
// GENERATE BUFFERS
glGenVertexArrays(1, &VertexArrayObject);
glGenBuffers(1, &VertexBufferId);
glGenBuffers(1, &IndexBufferObjectId);
Indices = {
0, 1, 2,
2, 3, 0
};
unsigned int numberOfVertices = Vertices.size();
unsigned int numberOfIndices = Indices.size();
glBindVertexArray(VertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObjectId);
Vertices = {
0.2f, 0.0f, 0.0f, 0.5f,
1.0f, 0.0f, 1.5f, 0.5f,
1.0f, 1.0f, 1.5f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f
};
// ADD BUFFER DATA
glBufferData( GL_ARRAY_BUFFER, Vertices.size() * sizeof(float), Vertices.data(), GL_STATIC_DRAW );
// ARRANGE ATTRIBUTES
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr);
glEnableVertexAttribArray(1);
glBufferData( GL_ELEMENT_ARRAY_BUFFER, numberOfIndices * sizeof(unsigned int), Indices.data(), GL_STATIC_DRAW );`
Render Function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLint u_Texture = glGetUniformLocation( shader.getId(), "u_Texture" );
glUniform1i( u_Texture, 0 );
GLint u_Model = glGetUniformLocation( shader.getId(), "u_Model" );
glUniformMatrix4fv( u_Model, 1, GL_FALSE, glm::value_ptr( rect.TransformMatrix() ) );
glDrawElements(GL_TRIANGLES, rect.Indices.size(), GL_UNSIGNED_INT, nullptr);
// SWAP BUFFERS
glfwSwapBuffers( _window->WindowInstance );
glfwPollEvents();
My program runs, but my texture is mapped between 0,0 and 1,0 no matter what my vertex or u,v positions are. I would expect the texture to be interpolated between the u,v coordinates for each vertex?
You attribute setup is wrong:
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr);
This tells OpenGL that it should attach the first two floats of each vertex to the mytextpos attribute. But you actually want it to read the 3rd and 4th float. Thus you have to set the offset such that it skips the first two floats:
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
I am trying to get vec3 colour data to a vertex shader (as an attrib pointer) , and then passing that into the fragment to be all settup .
It all started off by not being able to pass texture coords into the vertex shader . I've looked everywhere but not been able to find a definitive soloution . I can (by setting the colour manually in the vertex shader) , get a white square to renderer, but the colour data from the VAO cannot seem to be passed to it.
Also i'm certain that the shader loading system works . My best idea is that info is not being passed to the 'layout = 1' of the vertex shader, but I'm most likely wrong.
VAO / Buffer / shader settup
float vert[] = {
//Vert Locs Normal Coords
-0.5f,-0.5f, 1.0f,1.0f,1.0f, //0
0.5f,-0.5f, 1.0f,1.0f,1.0f, //1
0.5f,0.5f, 1.0f,1.0f,1.0f, //2
-0.5f, 0.5f, 1.0f,1.0f,1.0f, //3
};
unsigned int index[] = {
0,1,2, //Order of drawing vertices
2,3,0
};
unsigned int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 5 * 4 * sizeof(float), vert, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT,GL_FALSE, 5 * sizeof(float), 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(0); // vao ^^
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), index, GL_STATIC_DRAW);
Shader v("VertexN.shader", GL_VERTEX_SHADER);
Shader f("FragmentN.shader", GL_FRAGMENT_SHADER);
unsigned int shaders2[] = {v.id, f.id};
unsigned int program2 = Shader::getProgram(shaders2);
glUseProgram(0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Render loop
glClearColor(0, 0, 0, 1);
/* Render here */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glUseProgram(program2);
//tex.bind(slot);
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); //Drawing mode, Type indecies , type of index buffer , pointer to index buffer
glfwSwapBuffers(window);
glfwPollEvents();
glFlush();
glBindVertexArray(0);
glUseProgram(0);
glActiveTexture(0);
Vertex shader
#version 330 core
layout(location = 0)in vec2 pos;
layout(location = 1)in vec3 normals;
out vec3 normal;
void main() {
normal = normals;
gl_Position = vec4(pos, 0.0f, 1.0f);
};
Fragment shader
#version 330 core
layout(location = 0)out vec4 colour;
in vec3 normal;
void main() {
colour = vec4(normal, 1.0f);
};
I have no idea what that source code comment here:
glEnableVertexAttribArray(0); // vao ^^
is supposed to mean. However, I get the impression that you misunderstood what this function does.
The GL manages a set of generic vertex attributes (the spec guarantees that there are at least 16, maybe more), and for each such attribute, the data can come from an array. Besides having to specify the attribute pointer and data formats, you also have to enable the array from each attribute individually. When a draw call is made, for each vertex index i, the GPU will fetch the i-the value in the attribute array for each attribute where the array is enabled. For attributes where the array is disabled, it will use a constant value throughout the whole draw call. (You can set it via the glVertexAttrib*() familiy of functions before issuing the draw call).
Since you never enable the array for attribute 1 (your normals input for the shader), all vertices will see the current value of attribute 1 - most likely just vec4(0) as that is the initial default, and you never seem to have changed it.
The solution of course is to enable all the attribute arrays you want to fetch from:
glEnableVertexAttribArray(1);
And, while you're at it: In your render loop, you have
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
That is not necessary. The VAO will store this information already, there is no need to re-bind it for drawing.
I am trying to draw a grid of velocity vectors, I expect the velocity at each grid point to be a line with a slop of 1. A slanting line, but I always end up with a vertical line. I'm not sure what I'm doing wrong. Is there something I'm overlooking?
Here is how my vertex buffer looks :
float vel_pos[6*(N+2)*(N+2)];
int index1 = 0;
for (int i=0;i<N+2;i++)
{
for (int j=0;j<N+2;j++)
{
vel_pos[index1] = float(i);
vel_pos[index1+1] = float(j);
vel_pos[index1+2] = 0.0f;
vel_pos[index1+3] = float(i) +0.5f;
vel_pos[index1+4] = float(j) + 0.5f;
vel_pos[index1+5] = 0.0f;
index1 += 6;
}
}
Here is how I am creating my VBO and VAO :
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// Bind vertex array object first and then bind the vertex buffer objects
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vel_pos), vel_pos, GL_STREAM_DRAW);
GLint velAttrib = glGetAttribLocation(ourShader.ID, "aPos");
// iterpreting data from buffer
glVertexAttribPointer(velAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
Here is my vertex shader :
out vec4 vertexColor;
layout (location = 0) in vec3 aPos;
layout (location = 1) in float densitySource; /* source of density */
uniform mat4 transform;
uniform mat4 projection;
void main()
{
gl_Position = projection*transform * vec4(aPos, 1.0);
vertexColor = vec4(1, 0.0, 0.0, 1.0);
}
And here's my drawing code :
ourShader.use();
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::translate(trans, glm::vec3(-0.5f, -0.5f, 0.0f));
unsigned int transformMatrixLocation = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformMatrixLocation, 1, GL_FALSE, glm::value_ptr(trans));
glm::mat4 projection = glm::ortho(-10.0f, 110.0f, -1.0f, 110.0f, -1.0f, 100.0f);
unsigned int projectionMatrixLocation = glGetUniformLocation(ourShader.ID, "projection");
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO);
glLineWidth(1.0f);
glDrawArrays(GL_LINES, 0, (N+2)*(N+2));
This is the image I get :
resulting image
The 5th parameter (stride) of glVertexAttribPointer is the offset between two vertex coordinates and not between to primitives. Since your vertex coordinates have 3 components of type float, the offset has to be 3 * sizeof(float):
glVertexAttribPointer(velAttrib, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
Because you set an offset of 6 * sizeof(float), you have skipped every 2 coordinate and have drawn lines between the points of the grid.
But note, if stride is 0, the generic vertex attributes are understood to be tightly packed in the array. This is the case, so you ca use an offset of 0:
glVertexAttribPointer(velAttrib, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
I'm trying to render this model in openGL:
model in image viewer
this is my attempt so far:
model rendered by my code
I only gave it the verticies so far, no normals or faces. I'm wondering why it doesn't look full like the first one. Is it because of lack of normals? I'm pretty sure I got the number of verticies/triangles right but I'm not sure if I've made mistakes. What is the next step to fully render the model like the first image?
buffer creation:
//Vertex buffer
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
//color buffer
GLuint colorbuffer;
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
//create shaders and attach them to a program object
GLuint program = rigShadersToProgram();
GLuint matrixID = glGetUniformLocation(program, "MVP");
rendering loop:
// Rendering loop
while (!glfwWindowShouldClose(window))
{
//clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
////////////////////////////matrix operations/////////////////////////////////////////
//projection matrix 45 degree FoV, 4:3 ratio, display range 0.1 - 100
glm::mat4 projection = glm::perspective(99.0f, 4.0f/3.0f, 0.1f, 100.0f);
//camera matrix
glm::mat4 view = glm::lookAt(
glm::vec3(2, 1, -1), //camera is at (2,1,-1)
glm::vec3(0, 0 , 0), //looks at origin
glm::vec3(0,1, 0) //head is up
);
//model matrix identity matrix
glm::mat4 model = glm::mat4(1.0f);
//rotate
model = glm::rotate(model, e, glm::vec3(1,2,3));
//model-view-projection
glm::mat4 MVP = projection * view * model;
//////////////////////////////////////////////////////////////////////////////////////
//use the compiled shaders
glUseProgram(program);
//send transformation matrix to currently bound shader
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &MVP[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
//vertex buffer
glVertexAttribPointer(
0, //index
3, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
0 //array buffer offset
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
//color buffer
glVertexAttribPointer(
1, //index
3, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
0 //array buffer offset
);
//draw triangle
glDrawArrays(GL_TRIANGLES, 0, 12722*3);
std::cout << glfwGetTime() << "\n";
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glfwSwapBuffers(window);
glfwPollEvents();
the model data is stored in an array:
static const GLfloat g_vertex_buffer_data[] = {
-1.557376f, 0.094970f, 0.171995f,
-1.565967f, 0.098142f, 0.171995f,
-1.557376f, 0.094970f, -0.048469f,
-1.565967f, 0.098142f, -0.048469f,
-1.532660f, 0.162907f, -0.048469f,
-1.541251f, 0.166079f, -0.048469f,
-1.444236f, 0.405840f, 0.171996f,
-1.452827f, 0.409013f, 0.171996f,
-1.463533f, 0.352575f, 0.171995f,
-1.472257f, 0.355747f, 0.171995f,
-1.528166f, 0.175331f, 0.011009f,
-1.536757f, 0.178371f, 0.011009f,
-1.538475f, 0.146781f, 0.025019f, ... etc
vertex shader:
#version 430 core
layout(location =0) in vec3 vpos;
layout(location =1) in vec3 vertexColor;
out vec3 fragmentColor;
uniform mat4 MVP;
void main(void)
{
//output position of the vertex in clip space MVP*position
gl_Position = MVP * vec4(vpos,1);
fragmentColor = vertexColor;
};
fragment shader:
#version 430 core
in vec3 fragmentColor;
out vec3 color;
void main()
{
color = fragmentColor;
};
You don't show the actual model loading or rendering code. But what's clear from the screenshot of your program is, that your vertex indexing order is totally messed up. There are vertices connected with each other in your program's drawing that definitely are not connected in the model. Time to recheck the model loader code.
BTW: why did you hardcode the number of vertices to draw in the glDrawArrays call? That doesn't make sense at all.
I have been having difficulty texturing a plane I made. The first quad on the plane is textured properly, but the rest of the plane then only seems to use the first pixel of the texture so it all ends up as a solid color. It seems to work properly if I make one giant plane and just texture that, but when I try to break up the plane into sections I keep getting this issue. I’m assuming I am missing something as far as the coordinates go, but from my understanding I thought they were always supposed to be between 0 and 1? Any help is appreciated.
[![enter image description here][1]][1]
Texture coordinates
GLfloat grassTexCoords[]
{
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
};
Setting up VAO
GLuint makePlane()
{
float size = 5;
for (int i = -5; i < 5; ++i)
{
for (int j = -5; j < 5; ++j)
{
verts.push_back({ glm::vec3((i * size), -11.f, (j * size)) });
verts.push_back({ glm::vec3((i * size), -11.f, (j * size) + size) });
verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size)) });
verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size)) });
verts.push_back({ glm::vec3((i * size), -11.f, (j * size) + size) });
verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size) + size) });
}
}
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(VertexPos), verts.data(), GL_STATIC_DRAW);
GLuint vboTex;
glGenBuffers(1, &vboTex);
glBindBuffer(GL_ARRAY_BUFFER, vboTex);
glBufferData(GL_ARRAY_BUFFER, 2 * 6 * sizeof(GLfloat), &grassTexCoords, GL_STATIC_DRAW);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vboTex);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
return vao;
}
Rendering
void render()
{
glViewport(0, 0, window.getSize().x, window.getSize().y);
glClearColor(.4f, .4f, .4f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//1st program
glUseProgram(sphereProgram);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, objPointCount);
//2nd program
glFrontFace(GL_CCW);
glDepthMask(GL_FALSE);
glUseProgram(cubeProgram);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
glBindVertexArray(cubeVao);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDepthMask(GL_TRUE);
//3rd program
glFrontFace(GL_CCW);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
sf::Texture::bind(&grassTex);
glUseProgram(planeProgram);
glBindVertexArray(planeVao);
glDrawArrays(GL_TRIANGLES, 0, verts.size());
//-----------------------
window.display();
//window.setFramerateLimit(FPS);
window.setVerticalSyncEnabled(true);
}
Vertex shader
#version 410
layout (location = 0) in vec3 vertexPos;
layout (location = 1) in vec2 texCoords;
uniform mat4 view, proj;
out vec3 posEye;
out vec2 coords;
void main()
{
coords = texCoords; //repeat texture over plane
gl_Position = proj * view * vec4(vertexPos, 1.0);
posEye = (view * vec4(vertexPos, 1.0)).xyz;
}
Fragment shader
#version 410
in vec3 posEye;
in vec2 coords;
out vec4 fragColor;
uniform sampler2D tex;
//fog
const vec3 fogColor = vec3(0.2, 0.2, 0.2);
const float minFogRad = 300;
const float maxFogRad = 900;
void main()
{
vec4 texture = texture2D(tex, coords);
fragColor = texture;
float distance = length(-posEye);
float fogFactor = (distance - minFogRad) / (maxFogRad - minFogRad);
fogFactor = clamp(fogFactor, 0.0, 1.0);
fragColor.rgb = mix(fragColor.rgb, fogColor, fogFactor);
}
The problem here is, that texture coordinates are just supplied for the first quad (for the first 6 vertices). All other vertices seem to get [0,0], which causes them to only read the top-left texel. The solution here is to provide enough texture coordinates for all of the vertices.
Texture coordinates in general are not necessarily between 0 and 1. One can specify how values outside of [0,1] should be treated by setting GL_TEXTURE_WRAP_[RST].
Note, that not supplying enough data in a VBO can lead to crashes (depends on the driver) when OpenGL tries to read outside the buffer.
You are using a GL_ARRAY_BUFFER which stores per vertex data.
The 2 and GL_FLOAT arguments in glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL); are declaring that you have 2 floats in vboTex per vertex but you haven't done this, you have 2 floats for each vertex in the first quad only.
In the same way, the 3 and GL_FLOAT arguments in glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); are declaring that you have 3 floats in vbo per vertex which you have done.
The easiest fix for this is to create a bigger GL_ARRAY_BUFFER which repeats the same texture coordinates for every quad.