recently i found an Opengl example that applies a single texture without specifying texture image unit and without sending the corresponding unit integer uniform into the shader, is it possible to apply textures without using texture units?? or it simply uses a default value for both active texture unit and its shader sampler value.
my code block (texture related):
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint TextureID = 0;
SDL_Surface* Surface = IMG_Load("Abrams_Tank.jpg");
glGenTextures(1, &TextureID);
glBindTexture(GL_TEXTURE_2D, TextureID);
int Mode = GL_RGB;
if(Surface->format->BytesPerPixel == 4) {
Mode = GL_RGBA;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Surface->w, Surface->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, Surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLuint vbo;
GLuint vbo_Text;
GLuint vao;
glGenBuffers(1, &vbo);
glGenBuffers(1, &vbo_Text);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData) * 30,vertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(float) * 18));
glDrawArrays(GL_TRIANGLES, 0,6);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(0, vbo);
my fragment shader:
#version 410
in vec2 texCoordout;
uniform sampler2D mysampler;
out vec4 Fcolor;
void main()
{
Fcolor = texture (mysampler, texCoordout);
}
This will work, and is within specs:
The default texture unit is GL_TEXTURE0, so there is no need to ever call glActiveTexture() if only texture unit 0 is used.
Uniforms have a default value of 0, which is the correct value for a sampler that references texture unit 0.
I would still always set the uniform values just to make it explicit. If you don't set the uniform in this case, it is also much more likely that you will miss to set it if you ever use a texture unit other than 0.
Related
The very basic foundation for creating a VAO, VBO and applying a texture goes like this:
unsigned int VBO, VAO, EBO; //#1
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); //#2
And for creating a texture:
unsigned int texture1, texture2;
// texture 1
// ---------
glGenTextures(1, &texture1); //#3
glBindTexture(GL_TEXTURE_2D, texture1); //#4
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
// The FileSystem::getPath(...) is part of the GitHub repository so we can find files on any IDE/platform; replace it with your own image path.
unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
//some more code , inside the render loop
glActiveTexture(GL_TEXTURE0); #5
glBindTexture(GL_TEXTURE0, texture1); #6
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE0, texture1);
glDrawElements(...);
glfwSwapBuffers(...);
//end of render loop
According to what I've understood from learnopengl, from line #1 to line #2, the calls are stored inside the VAO which is why we don't have to write the stuff over and over again and we only switch the VAO for drawing.
But, is the code from line #3 to line #6 also stored in the VAO? If it is, then why don't we write line #5 directly after line #3? And if it isn't how do we link a specific texture unit to a specific VAO if we are using multiple VAOs?
EDIT:
after the glBindTexture(GL_TEXTURE_2D, texture1) the the texture calls that proceed affect the currently bound texture, isn't it? Then does that mean glActiveTexture(...) also affect the currently bound texture? And why do we bind the texture again after Activating it using glBindTexture(...)?
The reason lines 1 and 2 are "stored inside the VAO" is because that's what those functions do. Those functions set state within the currently bound vertex array object.
A vertex array object, as the name suggests, is an object that deals with vertex arrays. Texture management, texture storage, and using textures for rendering have nothing to do with vertex arrays. As such, none of those functions in any way affects VAO state, in much the same way that modifying the contents of a vector<int> won't modify the contents of some list<float> object.
how do we link a specific texture unit to a specific VAO if we are using multiple VAOs?
Again, VAOs deal with vertex data. Textures aren't vertex data, so VAOs don't care about them and vice-versa. You don't link textures and VAOs.
You use VAOs and textures (among other things) to perform rendering. VAOs and textures each do different things within the process of rendering and thus have no direct relationship to one another.
So I'm currently making a game using SDL2 with OpenGL (glew), and using SOIL to load images, and I'm using modern opengl techniques with vertex array objects and shaders and whatnot. I'm currently trying to just render just a texture to the window, but I can't seem to do it. I've looked up many tutorials and solutions, but I can't seem to understand how I'm supposed to do it properly. I'm unsure of whether it's the shader that's the problem, or my code itself. I'll post all the necessary code below, and any more is needed I'd be happy to supply it. Any answers and solutions are welcome. For future context, I have a class I use to store data for VAOs for convenience purposes. Code:
Here's the code to load the texture:
void PXSprite::loadSprite() {
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
int imagew, imageh;
//The path is a class variable, and I haven't received any errors from this function, so I can only assume it's getting the texture file correctly.
unsigned char* image = SOIL_load_image(path.c_str(), &imagew, &imageh, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imagew, imageh, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
//Don't worry about this code. It's just to keep the buffer object data.
//It works properly when rendering polygons.
spriteVAO.clear();
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addTextureCoordinate(0, 0);
spriteVAO.addTextureCoordinate(1, 0);
spriteVAO.addTextureCoordinate(1, 1);
spriteVAO.addTextureCoordinate(0, 1);
glGenVertexArrays(1, &spriteVAO.vaoID);
glGenBuffers(1, &spriteVAO.posVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.posVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*12, nullptr, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &spriteVAO.colVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.colVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, &spriteVAO.colors[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &spriteVAO.texVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.texVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, &spriteVAO.texCoords[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
And Here's my code for rendering the texture:
void PXSprite::render(int x, int y) {
spriteVAO.clear(PXVertexArrayObject::positionAttributeIndex);
spriteVAO.addPosition(x, y);
spriteVAO.addPosition(x+width, y);
spriteVAO.addPosition(x, y+height);
spriteVAO.addPosition(x+width, y+height);
glBindTexture(GL_TEXTURE_2D, textureID);
glBindVertexArray(spriteVAO.vaoID);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.posVBOid);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat)*12, &spriteVAO.positions[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindTexture(GL_TEXTURE_2D, 0);
}
Here's my vertex shader:
#version 330 core
in vec3 in_Position;
in vec4 in_Color;
in vec2 in_TexCoord;
out vec4 outPosition;
out vec4 outColor;
out vec2 outTexCoord;
void main() {
gl_Position = vec4(in_Position.x, in_Position.y*-1.0, in_Position.z, 1.0);
outTexCoord = in_TexCoord;
outColor = in_Color;
}
Here's my fragment shader:
#version 330 core
in vec2 outTexCoord;
in vec4 outColor;
out vec4 glFragColor;
out vec4 glTexColor;
uniform sampler2D pxsampler;
void main() {
vec4 texColor = texture(pxsampler, outTexCoord);
//This outputs the color of polygons if I don't multiply outColor by texColor, but once I add texColor, no colors show up at all.
glFragColor = texColor*outColor;
}
And lastly here's a bit of code to give reference to the VAO Attribute Pointers that I use at the right time when loading the shaders:
glBindAttribLocation(ProgramID, 0, "in_Position");
glBindAttribLocation(ProgramID, 1, "in_Color");
glBindAttribLocation(ProgramID, 2, "in_TexCoord");
Any help or suggestions are welcome. If any extra code is needed I'll add it. I'm sorry if this question seems redundant, but I couldn't find anything to help me. If someone could explain to me how exactly the code for rendering the textures works, that would be great, because from tutorials I've read they usually don't explain what does what so that I know how to do it again, so I'm not clear on what I'm doing exactly. Again, any help is appreciated. Thanks!
I spotted a few problems in this code. Partly already mentioned in other answers/comments, partly not.
VAO binding
The main problem is that your VAO is not bound while you set up the vertex attributes. See this code sequence:
glGenVertexArrays(1, &spriteVAO.vaoID);
glGenBuffers(1, &spriteVAO.posVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.posVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*12, nullptr, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
Here, you create a VAO (or more precisely, the id for a VAO), but don't bind it. The state set up by the glVertexAttribPointer() call is stored in the currently bound VAO. This call should actually give you a GL_INVALID_OPERATION error in a core profile context, since you need to have a VAO bound when making it.
To fix this, bind the VAO after creating the id:
glGenVertexArrays(1, &spriteVAO.vaoID);
glBindVertexArray(spriteVAO.vaoID);
...
glGenerateMipmap() in wrong place
As pointed out in a comment, this call belongs after the glTexImage2D() call. It generate mipmaps based on the current texture content, meaning that you need to specify the texture data first.
This error does not cause immediate harm in your current code since you're not actually using mipmaps. But if you ever set the GL_TEXTURE_MIN_FILTER value to use mipmapping, this will matter.
glEnableVertexAttribArray() in wrong place
This needs to happen before the glDrawArray() call, because the attributes obviously have to be enabled for drawing.
Instead of just moving them before the draw call, it's even better to place them in the attribute setup code, along the glVertexAttribPointer() calls. The enabled/disabled state is tracked in the VAO, so there's no need to make these calls every time. Just set up all of this state once during setup, and then simply binding the VAO before the draw call will set all the necessary state again.
Unnecessary glVertexAttribPointer() call
Harmless, but this call in the render() method is redundant:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
Again, this state is tracked in the VAO, so making this call once during setup is enough, once you fix the problems listed above.
It's best to simplify your problem to track down the issue. For example, instead of loading an actual image, you could just allocate a width*heigth*3 buffer and fill it with 127 to get a grey image (or pink to make it more obvious). Try coloring your fragments with the uv coordinates instead of using the sampler to see whether these values are set correctly.
I think you should enable the vertex attribute arrays before the draw call:
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
Also, before binding a texture to a texture unit, you should specify what unit to use instead of relying on the default:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
And make sure you bind your sampler to that texture unit:
glUniform1i(glGetUniformLocation(ProgramID, "pxsampler"), 0);
For the sampler uniform, we're setting indices directly instead of the GL_TEXTURE* values. So GL_TEXTURE0 needs an index 0 when setting the uniform and not GL_TEXTURE0.
I'm working on some examples, and I was trying to pass a texture to a shader.
To build a VAO, I have this piece of code:
void PlaneShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), _coordinates, GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), _indexes, GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("floor.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
This is how I load the shader attributes:
void PlaneShaderProgram::LoadAttributeVariables()
{
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
void PlaneShaderProgram::LoadUniformVariables()
{
// OpenGL Matrices
GLuint ModelViewProjection_location = glGetUniformLocation(GetProgramID(), "mvpMatrix");
glUniformMatrix4fv(ModelViewProjection_location, 1, GL_FALSE, glm::value_ptr(_ModelViewProjection));
// Floor texture
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, _texture);
// GLint Texture_location = glGetUniformLocation(GetProgramID(), "texture");
// glUniform1i(Texture_location, 0);
}
And my LoatTexture:
GLuint ProgramManager::LoadTexture(const char* imagepath)
{
unsigned char * data = LoadBMP(imagepath, &width, &height);
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
Finally, my draw function, which is called in the OpenGL main loop, is the following:
void PlaneShaderProgram::DrawPlane(const glm::mat4 &Projection, const glm::mat4 &ModelView)
{
_ModelViewProjection = Projection * ModelView;
_ModelView = ModelView;
Bind();
glBindVertexArray(_vao);
LoadUniformVariables();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
UnBind();
}
What I didn't get is that even if I didn't set the uniform texture (commented in the code) used by my shader, the plane is still draw using the texture. This makes no sense for me. Once the shader requires a sample2D, I think this shouldn't work and return some error.
Vertex Shader:
uniform mat4 mvpMatrix;
in vec4 vPosition;
smooth out vec2 uvCoord;
void main()
{
uvCoord = vPosition.xz;
gl_Position = mvpMatrix * vPosition;
}
Frag Shader:
uniform sampler2D texture;
in vec2 uvCoord;
out vec4 fragColor;
void main()
{
fragColor.rgb = texture(texture, uvCoord).rgb;
};
Am I missing something? Somehow this works I don't understand why, but I really like to.
The sampler data types in GLSL reference the texture unit, not a texture object. By default, uniforms will be initialized to 0, so if you don't set the sampler uniforms, they will sample from texture unit 0 (which is also the default unit). In your ProgramManager::LoadTexture() method, you bind the newly created texture, and very likely you are still using GL_TEXTURE0 as the currently active texture unit. You never seem to unbind it, so it is still bound at the time of the draw call, and the shader can access it.
I'm to learn OpenGL 4 and now I working with textures. I would like to apply a texture to a sphere, and my vertex shader looks like this:
#version 410
in vec4 vPosition;
in vec2 texCoord;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
smooth out vec2 uvCoord;
void main (void)
{
uvCoord = texCoord;
vec3 vNormal = vPosition.xyz / vPosition.w;
vVaryingNormal = normalMatrix * vNormal;
vec4 vPosition4 = mvMatrix * vPosition;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
vVaryingLightDir = normalize(vLightPosition - vPosition3);
gl_Position = mvpMatrix * vPosition;
}
After defining the coordinates and triangulation indexes of a sphere, I build a VAO with the following code:
void SphereShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _sphereCoordinates.size() * sizeof(float), &_sphereCoordinates[0], GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _sphereIndexes.size() * sizeof(unsigned int), &_sphereIndexes[0], GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("ball.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
GLuint ProgramManager::LoadTexture(const char* imagepath)
{
unsigned int width, height;
unsigned char * data = LoadBMP(imagepath, &width, &height);
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
To load the attributes, I did the following (before using texture):
void SphereShaderProgram::LoadAttributeVariables()
{
// Vertex Attributes
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
Now, however, I have an array (_sphereTexCoords) which contains the texture coordinates and I don't really know how to pass it to the vertex shader as the vertex coordinates are passed. Do I have to create another VBO? I though of doing something like this:
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
But I don't really know how to specify that this is related to the _sphereTexCoords array.
EDIT
I tried this, but it didn't work.
void SphereShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(2, _vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glBufferData(GL_ARRAY_BUFFER, _sphereCoordinates.size() * sizeof(float), &_sphereCoordinates[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glBufferData(GL_ARRAY_BUFFER, _textureCoordinates.size() * sizeof(float), &_textureCoordinates[0], GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _sphereIndexes.size() * sizeof(unsigned int), &_sphereIndexes[0], GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("ball.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
void SphereShaderProgram::LoadAttributeVariables()
{
// Vertex Attributes
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
}
I get an error when binding the program.
You're very close. The only thing I see missing is that you do not bind the correct buffer before calling glVertexAttribPointer(). When you call glVertexAttribPointer(), you specify that the data for the attribute will be pulled from the buffer that is currently bound to GL_ARRAY_BUFFER.
Your LoadAttributeVariables() method should therefore be:
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
How i can change size of texture on the screen? I'm want make a little 2d game for learning in OpenGL.:-) I try to change vertices[] geometry, but texture doesn't stretch to it. I use something like this code:
tempz = IMG_Load("graphics/menu_start.png");
SDL_InvertSurface(tempz);
//setup quad geometry
//setup quad vertices
vertices[0] = Vector2D(0.0,0.0);
vertices[1] = Vector2D(1.0,0.0);
vertices[2] = Vector2D(1.0,1.0);
vertices[3] = Vector2D(0.0,1.0);
//fill quad indices array
GLushort* id = &indices[0];
*id++ =0;
*id++ =1;
*id++ =2;
*id++ =0;
*id++ =2;
*id++ =3;
//setup quad vao and vbo stuff
glGenVertexArrays(1, &vaoID);
glGenBuffers(1, &vboVerticesID);
glGenBuffers(1, &vboIndicesID);
glBindVertexArray(vaoID);
glBindBuffer (GL_ARRAY_BUFFER, vboVerticesID);
//pass quad vertices to buffer object
glBufferData (GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);
//enable vertex attribute array for position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,0,0);
//pass quad indices to element array buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0], GL_STATIC_DRAW);
int texture_width = 0, texture_height = 0, channels=0;
texture_width = tempz->w;
texture_height = tempz->h;
//setup OpenGL texture and bind to texture unit 0
glGenTextures(1, &textureID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
//set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//allocate texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width, texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempz->pixels);
programID = LoadShaders( "shaders/shader.vert", "shaders/shader.frag" );
glUseProgram(programID);
It would help if you posted the rest, e.g. the shaders, but what I find strange is that you have no texture coordinates in your vertices. Usually they'd be (0,0), (0,1), (1,0) and (1,1) at the corners. These are attributes in your vertices just like the physical positions. Then you can wobble the physical position all over the place and still see the texture mapped the same way over the face.