I'm doing a bachelor project with some freinds, and we've run in to a pretty confusing bug with OpenGL textures. And I'm wondering if there's any knowledge about such things here...
The problem we're having, is that at our laptops (running Intel HD graphics) we can see the textures fine. But if we change it to run at dedicated graphics cards, we can't see the textures. We can't see them at our desktops with dedicated craphics cards either (both AMD and Nvidia).
So, what is up with that? Any ideas?
EDIT: Added texture & render code, not made by me so I don't know 100% how it works. But I think i found everything.
Texture load:
Texture::Texture(const char* imagepath)
{
textureImage = IMG_Load(imagepath);
if (!textureImage)
{
fprintf(stderr, "Couldn't load %s.\n", imagepath);
}
else{
textureID = 0;
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);
glTexImage2D(GL_TEXTURE_2D,
0, GL_RGB,
textureImage->w,
textureImage->h,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
textureImage->pixels);
SDL_FreeSurface(textureImage);
}
}
Platform VBO:
PlatformVBO::PlatformVBO() {
glGenBuffers(1, &vboID);
glGenBuffers(1, &colorID);
glGenBuffers(1, &texID);
//glGenBuffers(1, &indID);
texCoords.push_back(0.0f);
texCoords.push_back(0.0f);
texCoords.push_back(1.0f);
texCoords.push_back(0.0f);
texCoords.push_back(1.0f);
texCoords.push_back(1.0f);
texCoords.push_back(0.0f);
texCoords.push_back(1.0f);
//
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
indices.push_back(0);
indices.push_back(2);
indices.push_back(3);
bgTexture = new Texture("./Texture/shiphull.png");
platform = new Texture("./Texture/Abstract_Vector_Background.png");
// Give the image to OpenGL
glBindBuffer(GL_ARRAY_BUFFER, texID);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) *texCoords.size() / 2, &texCoords, GL_STATIC_DRAW);
//glBindBuffer(GL_ARRAY_BUFFER, texID);
//glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) *texCoords.size() / 2, &texCoords, GL_STATIC_DRAW);
}
Update VBO:
void PlatformVBO::setVBO(){
// Vertices:
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) *vertices.size(), &vertices.front(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorID);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) *colors.size(), &colors.front(), GL_STATIC_DRAW);
}
Draw:
void PlatformVBO::drawTexture(){
if (vertices.size() > 0){
setVBO();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indID);
//Enable states, and render (as if using vertex arrays directly)
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexPointer(2, GL_FLOAT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, texID);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
if (bgTexture->GetTexture() >= 0) {
glEnable(GL_TEXTURE_2D); // Turn on Texturing
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, bgTexture->GetTexture());
}
//Draw the thing!
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, &indices[0]);
//restore the GL state back
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
if (bgTexture->GetTexture() >= 0) {
glDisable(GL_TEXTURE_2D); // Turn off Texturing
glBindTexture(GL_TEXTURE_2D, bgTexture->GetTexture());
}
glBindBuffer(GL_ARRAY_BUFFER, 0); //Restore non VBO mode
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
Do not divide your texture coordinate size by 2 (that will cut the coordinates in half), and do not pass the address of the vector (that will give undefined results as there is no guarantee about the memory layout of std::vector).
Use this instead:
glBufferData (GL_ARRAY_BUFFER, sizeof(GLfloat) * texCoords.size(), &texCoords [0], GL_STATIC_DRAW);
Notice how this uses the address of the reference returned by std::vector's operator [] instead? C++03 guarantees the memory used internally for element storage is a contiguous array. Many earlier implementations of the C++ standard library worked this way, but the spec. did not guarantee it. C++11 adds std::vector::data (), which effectively does the same thing, but makes your code require a newer compiler.
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.
I'm trying to implement shadows on my custom renderer through dynamic shadow mapping and forward rendering (deferred rendering will be implemented later). For instance, everything renders correctly to the Framebuffer used to generate the shadow map. However, when using the default Framebuffer to render the scene normally only the skybox gets rendered (it means that the default Framebuffer is used) and my only hypothesis is that the problem is related with the depth buffer since disabling the call to DrawActors(...) (in ForwardRenderShadows) appears to solve the problem but I can't generate my depth map if doing so. Any suggestions on the matter?
Code:
void Scene::DrawActors(const graphics::Shader& shader)
{
for(const auto& actor : actors_)
actor->Draw(shader);
}
template <typename T>
void ForwardRenderShadows(const graphics::Shader& shadow_shader, const std::vector<T>& lights)
{
for(const auto& light : lights)
{
if(light->Shadow())
{
light->DrawShadows(shadow_shader);
DrawActors(shadow_shader); //removing this line "solves the problem"
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}
}
/*
shadow mapping is only implemented on directional lights for the moment, and that is the
relevant code that gets called when the process starts, more code details at the end of code
snippet.
*/
void DirectionalLight::SetupShadows()
{
glGenFramebuffers(1, &framebuffer_);
glGenTextures(1, &shadow_map_);
glBindTexture(GL_TEXTURE_2D, shadow_map_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, constants::SHADOW_WIDTH, constants::SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_map_, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("Directional light framebuffer is not complete \n");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
ShadowSetup(true);
}
void DirectionalLight::DrawShadows(const graphics::Shader& shader)
{
if(!ShadowSetup())
SetupShadows();
glViewport(0, 0, constants::SHADOW_WIDTH, constants::SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glClear(GL_DEPTH_BUFFER_BIT);
shader.Use();
projection_ = clutch::Orthopraphic(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 100.0f);
transform_ = clutch::LookAt(direction_ * -1.0f, {0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f});
shader.SetUniformMat4("light_transform", projection_ * transform_);
}
void DirectionalLight::Draw(const graphics::Shader& shader)
{
shader.SetUniform4f("light_dir", direction_);
shader.SetUniform4f("light_color", color_);
shader.SetUniformMat4("light_transform", transform_);
shader.SetUniformMat4("light_projection", projection_);
shader.SetUniformInt("cast_shadow", shadows_);
glActiveTexture(GL_TEXTURE12);
shader.SetUniformInt("shadow_map", 12);
glBindTexture(GL_TEXTURE_2D, shadow_map_);
}
Code the repo: https://github.com/rxwp5657/Nitro
Relevant Files for the problem:
include/core/scene.hpp
include/core/directional_light.hpp
include/core/light_shadow.hpp
include/core/directional_light.hpp
include/graphics/mesh.hpp
src/core/scene.cpp
src/core/directional_light.cpp
src/core/light_shadow.cpp
src/core/directional_light.cpp
src/graphics/mesh.cpp
Finally, what I have tried so far is:
Deactivating depth testing with glDepthMask(GL_FALSE) and glDisable(GL_DEPTH_TEST) //same problem.
Changing depth function to glDepthFunc(GL_ALWAYS); // No desired results;
If you have a NVIDIA graphics card, you could have a look a Nsight. You can capture a frame and view all occurred GL-calls.
Then, you can select an event, for instance the event 22 in my example, and inspect all textures, the color buffer, the depth buffer and the stencil buffer.
Furthermore, you can have a look on all GL-state parameters at one event.
Ok, after using apitrace I found out that the VBO changes when switching from a custom Framebuffer to the default one. Because of this, the solution to the problem is to set again the VBO after switching to the default frame buffer.
Based on the code of the project, the solution is calling the Setup function again after switching to the default Framebuffer.
Setup function of the Mesh class:
void Mesh::Setup(const Shader& shader)
{
glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glGenBuffers(1, &elementbuffer_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(unsigned int), &indices_[0], GL_STATIC_DRAW);
glGenBuffers(1, &vbo_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex), &vertices_[0], GL_STATIC_DRAW);
shader.PosAttrib("aPosition", 3, GL_FLOAT, sizeof(Vertex), 0);
shader.PosAttrib("aNormal", 3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, normal));
shader.PosAttrib("aTexCoord", 2, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, tex_coord));
shader.PosAttrib("aTangent", 3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, tangent));
shader.PosAttrib("aBitangent",3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, bitangent));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
loaded_ = true;
}
Vertices buffer after switching to default frame buffer
Vertices buffer with no Framebuffer switching (no shadow map generated)
I am having an issue with implementing a frame buffer for post processing. So far I can draw everything to a textured quad and a apply a shader to change the screen, so in that respect it works.
My issue is when I move my models or camera, the model start to render incorrectly and parts of them get "cut off". See the following screen shots as it is hard to explain.
To avoid putting pages and pages of code, all the rendering works fine without the Frame Buffer and every looks fine if I don't move the camera or models.
I set up the frame buffer like this.
//Set up FBO
glGenFramebuffers(1, &m_FrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_FrameBuffer);
glActiveTexture(GL_TEXTURE2);
glGenTextures(1, &m_TexColorBuffer);
glBindTexture(GL_TEXTURE_2D, m_TexColorBuffer);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGB, 1280, 720, 0, GL_RGB, GL_UNSIGNED_BYTE, 0
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_TexColorBuffer, 0
);
glGenRenderbuffers(1, &m_RBODepthStencil);
glBindRenderbuffer(GL_RENDERBUFFER, m_RBODepthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1280, 720);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_RBODepthStencil
);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_TexColorBuffer, 0);
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Frame Buffer: Contructor: Issue completing frame buffer" << std::endl;
//Set Up Shader
m_ScreenShader = new Shader("../Assets/Shaders/screen.vert", "../Assets/Shaders/screen.frag");
//Setup Quad VAO
glGenBuffers(1, &m_QuadVBO);
glBindBuffer(GL_ARRAY_BUFFER, m_QuadVBO);
glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), points, GL_STATIC_DRAW);
glGenVertexArrays(1, &m_QuadVAO);
glBindVertexArray(m_QuadVAO);
//glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, m_QuadVBO);
//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
GLint posAttrib = glGetAttribLocation(m_ScreenShader->getID(), "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
GLint texAttrib = glGetAttribLocation(m_ScreenShader->getID(), "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
I then Bind it prior to drawing the scene (skybox and models) and then draw it like this.
Unbind();
glBindVertexArray(m_QuadVAO);
glDisable(GL_DEPTH_TEST);
m_ScreenShader->enable();
m_ScreenShader->setUniform1f("time", glfwGetTime());
GLint baseImageLoc = glGetUniformLocation(m_ScreenShader->getID(), "texFramebuffer");
glUniform1i(baseImageLoc, 2);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, m_TexColorBuffer);
glDrawArrays(GL_TRIANGLES, 0, 6);
Any help is appreciated!
When rendering into a framebuffer that has a depth buffer and the depth test is enabled, then the depth buffer must be cleared. The depth buffer must be cleared after binding the framebuffer and before drawing to the framebuffer:
gllBindFramebuffer( GL_FRAMEBUFFER, m_FrameBuffer );
glClear( GL_DEPTH_BUFFER_BIT );
Note, if you do not clear the deep buffer, it retains its content. This causes that the depth test may fail at positions, where the geometry has been in the past. It follows that parts are missing in the geometry, as in the image in the question.
So in my program I have a number of textures that I am trying to display. Earlier in my code I generate the VAO for the textures and the ibo (or index buffer) for each texture. But when I run my code it crashes at the glDrawElements() call and in nvoglv32.dll. I've read around that a bug in the nvidia driver might be causing it but I doubt it. Something is probably wrong when I generate or bind the VAO or ibo but I have no idea where. Here's the section of code where the error happens:
for (int i = 0; i < NUM_TEXTURES; i++){
glBindVertexArray(VAO_T[i]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[i]);
glBindTexture(GL_TEXTURE_2D, texture[i]);
//error here
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, BUFFER_OFFSET(0));//error right here
}
This is the error I get when running in debug:
Unhandled exception at 0x0263FE4A in Comp465.exe: 0xC0000005: Access violation reading location 0x00000000.
Heres my code where I generate the VAO, ibo, and textures:
glGenVertexArrays(NUM_TEXTURES, VAO_T);
glGenBuffers(NUM_TEXTURES, VBO_T);
glGenBuffers(NUM_TEXTURES, ibo);
glGenTextures(NUM_TEXTURES, texture);
...
for (int i = 0; i < NUM_TEXTURES; i++){
//Tel GL which VAO we are using
glBindVertexArray(VAO_T[i]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[i]), indices[i], GL_STATIC_DRAW);
//initialize a buffer object
glEnableVertexAttribArray(VBO_T[i]);
glBindBuffer(GL_ARRAY_BUFFER, VBO_T[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(point[i]) + sizeof(texCoords), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(point[i]), point[i]);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(point[i]), sizeof(texCoords), texCoords);
GLuint vPosition = glGetAttribLocation(textureShader, "vPosition");
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(vPosition);
GLuint vTexCoord = glGetAttribLocation(textureShader, "vTexCoord");
glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(point[i])));
glEnableVertexAttribArray(vTexCoord);
//Get handles for the uniform structures in the texture shader program
VP = glGetUniformLocation(textureShader, "ViewProjection");
//Bind the texture that we want to use
glBindTexture(GL_TEXTURE_2D, texture[i]);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// set texture parameters
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
//Load texture
texture[i] = loadRawTexture(texture[i], TEX_FILE_NAME[i], PixelSizes[i][0], PixelSizes[i][1]);
if (texture[i] != 0) {
printf("texture loaded \n");
}
else
printf("Error loading texture \n");
}
This statement certainly looks wrong:
glEnableVertexAttribArray(VBO_T[i]);
glEnableVertexAttribArray() takes an attribute location as its argument, not a buffer id. You actually use it correctly later:
GLuint vPosition = glGetAttribLocation(textureShader, "vPosition");
...
glEnableVertexAttribArray(vPosition);
GLuint vTexCoord = glGetAttribLocation(textureShader, "vTexCoord");
...
glEnableVertexAttribArray(vTexCoord);
So you should be able to simply delete that extra call with the invalid argument.
Apart from that, I noticed a couple of things that look slightly off, or at least suspicious:
The following call is meaningless if you use the programmable pipeline, which you are based on what's shown in the rest of the code. It can be deleted.
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
This is probably just a naming issue, but textureShader needs to be a program object, i.e. the return value of a glCreateProgram(), not a shader object.
While inconclusive without seeing the declaration, I have a bad feeling about this, and a couple other similar calls:
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[i]), indices[i], GL_STATIC_DRAW);
If indices[i] is an array, i.e. the declaration looks something like this:
indices[NUM_TEXTURES][INDEX_COUNT];
then this is ok. But if indices[i] is a pointer, or degenerated to a pointer when it was passed as a function argument, sizeof(indices[i]) will be the size of a pointer. You may want to double check that it gives the actual size of the index array. Same thing for other similar cases.
I am working on a school laboration whereas my task is to render a basic terrain using a heightmap, and also some sort of particle system (right now I'm just blasting away points that are drawn into flat squares).
The problem is that while I can render both the terrain and the particle system, for some reason I cannot render both of them at the same time.
The terrain's initiation and draw functions:
int Buffers()
{
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "Vertex.txt"},
{ GL_FRAGMENT_SHADER, "Fragment.txt"},
{ GL_NONE, NULL},
};
program = LoadShaders(shaders);
createTerrain.loadBMP_custom("heightmap.bmp");
textureID = createTerrain.loadBMP_texture("texture.bmp");
textureLocID = glGetUniformLocation(program, "tex");
glUniform1i(textureLocID, textureID);
glGenBuffers(1, &VBOid); // Generate our Vertex Buffer Object
glBindBuffer(GL_ARRAY_BUFFER, VBOid); // Bind our Vertex Buffer Object
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData)*createTerrain.vertices.size(), &createTerrain.vertices[0], GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW
glGenBuffers(1, &indexes);// bind kopplingarna med buffern
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexes);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*createTerrain.indices.size(), &createTerrain.indices[0], GL_STATIC_DRAW);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, createTerrain.globalWidth, createTerrain.globalHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, createTerrain.globalData);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
MVPMatrixID = glGetUniformLocation(program, "gMVPMatrix");
return 0;
}
void Render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glClearColor(1, 0, 0, 1);
glEnable(GL_DEPTH_TEST);
camera.SetPosition(glm::vec3(camera.ReturnPosition().x, height - createTerrain.checkHeight(camera.ReturnPosition().x, camera.ReturnPosition().z), camera.ReturnPosition().z));
camera.ComputeMatricesFromInputs(window);
projectionMatrix = camera.ReturnProjectionMatrix();
viewMatrix = camera.ReturnViewMatrix();
MVPMatrix = projectionMatrix * viewMatrix;
particles.CalculateMVPMatrix(camera);
//binda ihop location i shadern med buffern
glBindBuffer(GL_ARRAY_BUFFER, VBOid);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), BUFFER_OFFSET(16)); //The starting point of normals, 12 bytes away
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), BUFFER_OFFSET(28));
glUseProgram(program);
glUniformMatrix4fv(MVPMatrixID, 1, GL_FALSE, &MVPMatrix[0][0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexes);
glDrawElements(GL_TRIANGLES, createTerrain.indices.size(), GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
}
The particle systems init and draw functions:
void Particles::Init()
{
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "ParticleVert.txt"},
{ GL_GEOMETRY_SHADER, "ParticleGeo.txt"},
{ GL_FRAGMENT_SHADER, "ParticleFrag.txt"},
{ GL_NONE, NULL},
};
program = LoadShaders(shaders);
glGenVertexArrays(1, VAOid);
glBindVertexArray(VAOid[0]);
glGenBuffers(1, &VBOid);
glBindBuffer(GL_ARRAY_BUFFER, VBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(PARTICLE) * particlePos.size(), &particlePos[0], GL_STATIC_DRAW);
MVPMatrixID = glGetUniformLocation(program, "gMVPMatrix");
}
void Particles::Render(glm::mat4 MVPMatrix)
{
UpdateParticles();
glBindBuffer(GL_ARRAY_BUFFER, VBOid);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glUseProgram(program);
glUniformMatrix4fv(MVPMatrixID, 1, GL_FALSE, &MVPMatrix[0][0]);
glDrawArrays(GL_POINTS, 0, maxParticles);
glDisableVertexAttribArray(0);
}
My current call order is Terrain.Buffers(), Particles.Init(), Terrain.Render(), Particles.Render().
As it looks now, the program will render the terrain and Only the terrain. What makes this such a troubling case is that there are two lines of code in Terrain.Render(), namely:
glUseProgram(program);
glUniformMatrix4fv(MVPMatrixID, 1, GL_FALSE, &MVPMatrix[0][0]);
If I switch place on these two, so that glUniformMatrix4fv comes before glUseProgram, the particles are rendered instead of the terrain.
EDIT:
added glGenVertexArrays(1, VAOid);
glBindVertexArray(VAOid[0]);
in the code, in Particles.Init. I honestly do not know how VAO's works, a friend of mine said this was all I needed to do. Hasn't solved the problem though.