Related
I'm programming a voxel game. I have implented procedurally generated terrain. Now I want to program a map that should show on the upper right corner of the screen and that shows the biomes that are nearby. To do this my idea was to create a separate shader program, vbo, and vao, and a texture and that I would write to as the player moved around.
Is there a better way to do this?
Here I create the map:
GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &EBO);
glGenBuffers(1, &VBO);
float vertices[] = {
-.5f, -.5f, 0, 0, 0,
-.5f, .5f, 0, 0, 1,
.5f, .5f, 0, 1, 1,
.5f, -.5f, 0, 1, 0
};
/*float vertices[] = {
-1, -.5f, 0,
0, .5f, 0,
.5f, -.5f, 0
};*/
unsigned int indices[] = {
0, 1, 2,
0, 2, 3
};
glBindVertexArray(VAO);
// 2. copy our vertices array in a vertex buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. copy our index array in a element buffer for OpenGL to use
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 4. then set the vertex attributes pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
GLuint tbo;
int apothem = 256;
unsigned char pixels[apothem*apothem*3];
for(size_t i = 0; i < apothem*apothem*3; i++) {
pixels[i] = 1;
//std::cout << "changed pixels[" << i << "]" << std::endl;
}
glGenTextures(1, &tbo);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, tbo);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, apothem, apothem, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
//glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, apothem, apothem, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// set the texture wrapping/filtering options (on the currently bound texture object)
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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
And here's the rendering loop:
while (!glfwWindowShouldClose(window))
{
// Poll and handle events (inputs, window resize, etc.)
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
glfwPollEvents();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
static float scale[3] = {1, 1, 1};
static float rotation[3] = {0, 0, 0};
static float position[3] = {0, 0, 0};
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
ImGui::Begin("Chunk settings"); // Create a window called "Hello, world!" and append into it.
ImGui::SliderFloat3("scale", scale, -5, 5);
ImGui::SliderFloat3("rotation", rotation, -360, 360);
ImGui::SliderFloat3("position", position, -5, 5);
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End();
}
{
int x = mainPlayer.GetPos().x(), z = mainPlayer.GetPos().z();
ImGui::Begin("World settings");
float continentalness = voxelEngine::mainWorld.GetContinentalness(x, z);
ImGui::Text("Continentalness: %.4f, Continentalness degree: %d", continentalness,
voxelEngine::mainWorld.ContinentalnessDegree(continentalness));
float erosion = voxelEngine::mainWorld.GetErosion(x, z);
ImGui::Text("Erosion: %.4f, Erosion Degree: %d", erosion,
voxelEngine::mainWorld.GetErosionDegree(erosion));
float humidity = voxelEngine::mainWorld.GetHumidity(x, z);
ImGui::Text("Humidity: %.4f, Humidity Degree: %d", humidity,
voxelEngine::mainWorld.GetHumidityDegree(humidity));
float temperature = voxelEngine::mainWorld.GetTemperature(x, z);
ImGui::Text("Temperature: %.4f, Temperature Degree: %d", temperature,
voxelEngine::mainWorld.GetTemperatureDegree(temperature));
float elevation = voxelEngine::mainWorld.GetElevation(x, z);
ImGui::Text("Elevation: %.4f, Elevation Degree: %d", elevation,
voxelEngine::mainWorld.GetElevationDegree(elevation));
ImGui::End();
}
static float n = .3, f = .5, speed, sensitivity, fov, pitch, yaw;
static Eigen::Vector3f cam_pos;
speed = voxelEngine::players->GetSpeed();
sensitivity = voxelEngine::players->GetSensitivity();
fov = voxelEngine::players->GetFOV();
pitch = voxelEngine::players->GetPitch();
yaw = voxelEngine::players->GetYaw();
cam_pos = voxelEngine::players->GetPos();
{
ImGui::Begin("Camera settings");
ImGui::SliderFloat("cam x", &cam_pos.x(), -10, 10);
ImGui::SliderFloat("cam y", &cam_pos.y(), -10, 10);
ImGui::SliderFloat("cam z", &cam_pos.z(), -10, 10);
ImGui::SliderFloat("speed", &speed, 0, 1);
ImGui::SliderFloat("sensitivity", &sensitivity, 0, 1);
ImGui::SliderFloat("fov", &fov, 0, 90);
ImGui::SliderFloat("pitch", &pitch, -360, 360);
ImGui::SliderFloat("yaw", &yaw, -360, 360);
ImGui::SliderFloat("near plane", &n, 0, 1);
ImGui::SliderFloat("far plane", &f, 0, 1);
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
ImGui::End();
}
voxelEngine::players->SetPos(cam_pos);
voxelEngine::players->SetSpeed(speed);
voxelEngine::players->SetSensitivity(sensitivity);
voxelEngine::players->SetFOV(fov);
voxelEngine::players->SetDirection(pitch, yaw);
// Rendering
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float projMat[16];
float viewMat[16];
//float modelMat[16];
/*voxelEngine::genModelMatrix({scale[0], scale[1], scale[2]}, {rotation[0], rotation[1], rotation[2]},
{position[0],
position[1],
position[2]}, modelMat);*/
voxelEngine::players->genViewMatrix(viewMat);
voxelEngine::genProjMatrix(n, f, (float)display_h/display_w, voxelEngine::players->GetFOV(), projMat);
//glUniformMatrix4fv(glGetUniformLocation(voxelEngine::program, "modelMatrix"), 1, GL_FALSE, modelMat);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, blockTextures);
glUseProgram(worldProgram);
glUniformMatrix4fv(glGetUniformLocation(worldProgram, "viewMatrix"), 1, GL_FALSE, viewMat);
glUniformMatrix4fv(glGetUniformLocation(worldProgram, "projMatrix"), 1, GL_TRUE, projMat);
mainPlayer.Render();
float mapProj[16];
float mapModel[16];
voxelEngine::genModelMatrix(Eigen::Vector3f(.7, .7, .7), Eigen::Vector3f(0, 0, 0), Eigen::Vector3f(0, 0, 1), mapModel);
voxelEngine::genProjMatrix(n, f, (float)display_h/display_w, 90, mapProj);
glUseProgram(guiProgram);
glUniform1i(glGetUniformLocation(guiProgram, "my_sampler"), 1);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, tbo);
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glUniformMatrix4fv(glGetUniformLocation(guiProgram, "projMat"), 1, GL_TRUE, mapProj);
glUniformMatrix4fv(glGetUniformLocation(guiProgram, "modelMat"), 1, GL_FALSE, mapModel);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
//glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, apothem, apothem, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
//glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, apothem, apothem, GL_RGB, GL_UNSIGNED_BYTE, pixels);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
/*voxelEngine::mainBiomeMap->Bind();
voxelEngine::mainBiomeMap->Render();*/
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// Update and Render additional Platform Windows
// (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
// For this specific demo app we could also call glfwMakeContextCurrent(window) directly)
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
}
glfwSwapBuffers(window);
}
Everything renders fine except the map which is just black.
This is where I render the map:
float mapProj[16];
float mapModel[16];
voxelEngine::genModelMatrix(Eigen::Vector3f(.7, .7, .7), Eigen::Vector3f(0, 0, 0), Eigen::Vector3f(0, 0, 1), mapModel);
voxelEngine::genProjMatrix(n, f, (float)display_h/display_w, 90, mapProj);
glUseProgram(guiProgram);
glUniform1i(glGetUniformLocation(guiProgram, "my_sampler"), 1);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, tbo);
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glUniformMatrix4fv(glGetUniformLocation(guiProgram, "projMat"), 1, GL_TRUE, mapProj);
glUniformMatrix4fv(glGetUniformLocation(guiProgram, "modelMat"), 1, GL_FALSE, mapModel);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
//glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, apothem, apothem, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
//glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, apothem, apothem, GL_RGB, GL_UNSIGNED_BYTE, pixels);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
How can I get this to work?
I am facing an issue with font rendering. I am using the tutorial https://learnopengl.com/In-Practice/Text-Rendering for this.
I am developing the application in OpenGLESV3.
I have made different shader programs for 3D object drawing, for loading textures and lastly for the font rendering.
I am drawing the fonts after the 3D objects and texture drawing is done.
However the issue is that the font is not seen when i draw using orthographic projection. I am able to only see the 3D objects and texture. (Even though the shaders are different)
when I only draw font only with orthographic projection it is drawing perfectly.
I am sure it is the issue with the settings in projection, but i am unable to figure out the issue.
Can anybody help please ?
Here is the code inside my render loop
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, (GLsizei)SCR_WIDTH, (GLsizei)SCR_HEIGHT);
/********************************* 3D objects Rendering ********************************************************/
glUseProgram(shaderpgmPoints);
projection = glm::perspective(glm::radians(camspec.fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderpgmPoints, "projection"), 1, false, &projection[0][0]);
view = glm::lookAt(camspec.cameraPos, camspec.cameraPos + camspec.cameraFront, camspec.cameraUp);
glUniformMatrix4fv(glGetUniformLocation(shaderpgmPoints, "view"), 1, false, &view[0][0]);
model = glm::mat4(1.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderpgmPoints, "model"), 1, false, &model[0][0]);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, quadBufferObject);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)64);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindBuffer(GL_ARRAY_BUFFER, leftlaneBufferObject);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)192);
;
glEnable(GL_PROGRAM_POINT_SIZE);
glDrawArrays(GL_LINES, 0, 12);
glDisable(GL_BLEND);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindBuffer(GL_ARRAY_BUFFER, rightlaneBufferObject);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)32);
glLineWidth(10.0f);
glDrawArrays(GL_LINES, 0, 2);
glDisable(GL_BLEND);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
/********************************* 3D objects Rendering -End ********************************************************/
/********************************* Texture Rendering ********************************************************/
glUseProgram(shaderpgmTexture);
glm::mat4 transform = glm::mat4(1.0f);
transform = glm::translate(transform, glm::vec3(0.0f, 0.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shaderpgmTexture, "transform"), 1, false, &transform[0][0]);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUniform1i(glGetUniformLocation(shaderpgmTexture, "outputTexture"), 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, camTexture);
glBindBuffer(GL_ARRAY_BUFFER, camTextureBufferObject);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glDrawArrays(GL_QUADS, 0, 4);
glDisable(GL_BLEND);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
/********************************* Texture Rendering - End ********************************************************/
/********************************* Font Rendering ********************************************************/
glDisable(GL_DEPTH_TEST);
glUseProgram(shaderpgmFont);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glm::mat4 project = glm::ortho(0.0f, static_cast<GLfloat>(SCR_WIDTH), 0.0f, static_cast<GLfloat>(SCR_HEIGHT));
glUniformMatrix4fv(glGetUniformLocation(shaderpgmFont, "projection"), 1, false, &project[0][0]);
glUniform3f(glGetUniformLocation(shaderpgmFont, "textColor"), 1.0f, 0.0f, 0.0f);
glActiveTexture(GL_TEXTURE0);
GLfloat scale = 1.0f;
GLfloat x = 10.0f;
GLfloat y = 10.0f;
std::string text = "THE";
std::string::const_iterator c;
for (c = text.begin(); c != text.end(); c++)
{
Character ch = Characters[*c];
GLfloat xpos = x + ch.Bearing.x * scale;
GLfloat ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
GLfloat w = ch.Size.x * scale;
GLfloat h = ch.Size.y * scale;
GLfloat vertices[6][4] = {
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos, ypos, 0.0, 1.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos + w, ypos + h, 1.0, 0.0 }
};
// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
// Update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, FontVertexBufferObject);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glUseProgram(0);
glEnable(GL_DEPTH_TEST);
/********************************* Font Rendering - End********************************************************/
I am Initializing the font buffer like this
glDisable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(shaderpgmFont);
// FreeType
FT_Library ft;
// All functions return a value different than 0 whenever an error occurred
if (FT_Init_FreeType(&ft))
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
// Load font as face
FT_Face face;
if (FT_New_Face(ft, "fonts/arial.ttf", 0, &face))
{
std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
}
else
{
// Set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, 48);
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Load first 128 characters of ASCII set
for (GLubyte c = 0; c < 128; c++)
{
// Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
continue;
}
// Generate texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_ALPHA,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// Set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Now store character for later use
Character character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
face->glyph->advance.x
};
Characters.insert(std::pair<GLchar, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
// Destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
// Configure VAO/VBO for texture quads
glGenBuffers(1, &FontVertexBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, FontVertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glUseProgram(0);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
In your initialization function, you've set up some OpenGL state via glVertexAttribPointer, which later gets clobbered.
To fix this, modify your text-rendering code so that it makes two calls glVertexAttribPointer after glBindBuffer.
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.
I need to render a 3d model into many views and the image size is much larger than screen resolution, so I can not open a so large window and I do not need to open a window to see the rendering result, too. I only want to render the 3d model into many images with different viewpoints.
I find this tutorial, http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/, and I try to use glGetTexImage and glReadPixels to read pixel values from fbo.
The problem is if the window is not hidden, it is OK. If I set the window hidden using
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
I can only read the background color from fbo using glGetTexImage or glReadPixels. And the model drawed using glDrawElements disappears.
Could anyone help me or show me an example? Thanks!
This my code of reading fbo: (It work well if the window is not hidden, the remaining part of my code is same as http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/)
Here is my code is:
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 1);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_VISIBLE, GL_TRUE);
// Open a window and create its OpenGL context
int windowWidth = 4000;
int windowHeight = 3000;
window = glfwCreateWindow(windowWidth, windowHeight, "Tutorial 14 - Render To Texture", NULL, NULL);
if (window == NULL) {
fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set the mouse at the center of the screen
glfwPollEvents();
glfwSetCursorPos(window, windowWidth / 2, windowHeight / 2);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders("StandardShadingRTT.vertexshader", "StandardShadingRTT.fragmentshader");
// Get a handle for our "MVP" uniform
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint ViewMatrixID = glGetUniformLocation(programID, "V");
GLuint ModelMatrixID = glGetUniformLocation(programID, "M");
// Load the texture
GLuint Texture = loadDDS("uvmap.DDS");
// Get a handle for our "myTextureSampler" uniform
GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler");
// Read our .obj file
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
bool res = loadOBJ("suzanne.obj", vertices, uvs, normals);
std::vector<unsigned short> indices;
std::vector<glm::vec3> indexed_vertices;
std::vector<glm::vec2> indexed_uvs;
std::vector<glm::vec3> indexed_normals;
indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs, indexed_normals);
// Load it into a VBO
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2), &indexed_uvs[0], GL_STATIC_DRAW);
GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);
// Generate a buffer for the indices as well
GLuint elementbuffer;
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);
// Get a handle for our "LightPosition" uniform
glUseProgram(programID);
GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");
// ---------------------------------------------
// Render to Texture - specific code begins here
// ---------------------------------------------
// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
// The texture we're going to render to
GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, renderedTexture);
// Give an empty image to OpenGL ( the last "0" means "empty" )
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, windowWidth, windowHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
// Poor filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Set "renderedTexture" as our colour attachement #0
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
// Set the list of draw buffers.
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
// Always check that our framebuffer is ok
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
// Render to our framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glViewport(0, 0, windowWidth, windowHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Compute the MVP matrix from keyboard and mouse input
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glm::vec3 lightPos = glm::vec3(4, 4, 4);
glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// Set our "myTextureSampler" sampler to user Texture Unit 0
glUniform1i(TextureID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, // attribute
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 3rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
2, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
// Draw the triangles !
glDrawElements(
GL_TRIANGLES, // mode
indices.size(), // count
GL_UNSIGNED_SHORT, // type
(void*)0 // element array buffer offset
);
unsigned char *image = new unsigned char[windowWidth * windowHeight * 3];
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, windowWidth, windowHeight, GL_RGB, GL_UNSIGNED_BYTE, image);
cv::Mat img;
img = cv::Mat::zeros(windowHeight, windowWidth, CV_8UC3);
for (int i = 0; i < windowHeight; i ++) {
for (int j = 0; j < windowWidth; j ++) {
int index = (i * windowWidth + j) * 3;
cv::Vec3b px;
px.val[0] = image[index + 0];
px.val[1] = image[index + 1];
px.val[2] = image[index + 2];
img.at<cv::Vec3b>(i, j) = px;
}
}
cv::imwrite("test.png", img);
It works very well when the window is visible
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
but if I set it to be GL_TRUE, I can not get the results any more!
Could any one help me?
Thanks very much!
Have you checked this example? It uses Frame Buffer
https://www.opengl.org/wiki/Framebuffer_Object_Examples#Quick_example.2C_render_to_texture_.282D.29
Code below (in case the link gets broken on the future):
//RGBA8 2D texture, 24 bit depth texture, 256x256
glGenTextures(1, &color_tex);
glBindTexture(GL_TEXTURE_2D, color_tex);
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_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//NULL means reserve texture memory, but texels are undefined
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
//-------------------------
glGenFramebuffersEXT(1, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
//Attach 2D texture to this FBO
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color_tex, 0);
//-------------------------
glGenRenderbuffersEXT(1, &depth_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256);
//-------------------------
//Attach depth buffer to FBO
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb);
//-------------------------
//Does the GPU support current FBO configuration?
GLenum status;
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
cout<<"good";
default:
HANDLE_THE_ERROR;
}
//-------------------------
//and now you can render to GL_TEXTURE_2D
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//-------------------------
glViewport(0, 0, 256, 256);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 256.0, 0.0, 256.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//-------------------------
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
//-------------------------
//**************************
//RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0}
//Read http://www.opengl.org/wiki/VBO_-_just_examples
RenderATriangle();
//-------------------------
GLubyte pixels[4*4*4];
glReadPixels(0, 0, 4, 4, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
//pixels 0, 1, 2 should be white
//pixel 4 should be black
//----------------
//Bind 0, which means render to back buffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
Code cleanup:
//Delete resources
glDeleteTextures(1, &color_tex);
glDeleteRenderbuffersEXT(1, &depth_rb);
//Bind 0, which means render to back buffer, as a result, fb is unbound
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, &fb);
I'm still trying to get a grasp of using textures and now I'm trying to use glTexCoordPointer in order to give each vertex a color specific to it's class. I've made some checks and here is the situation:
self.bufferVertices = glGenBuffersARB(1)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferVertices)
glBufferDataARB(GL_ARRAY_BUFFER_ARB, ADT.arrayByteCount(vertices), ADT.voidDataPointer(vertices), GL_STATIC_DRAW_ARB)
self.vertices = vertices
self.bufferNormals = glGenBuffersARB(1)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferNormals)
glBufferDataARB(GL_ARRAY_BUFFER_ARB, ADT.arrayByteCount(normals), ADT.voidDataPointer(normals), GL_STATIC_DRAW_ARB)
self.normals = normals
self.triangles = triangles
textureIndexes = []
for int in areas:
textureIndexes.append(float(int)/190.0)
print str(int) + " " + str(float(int)/190)
print str(len(self.vertices)) + str(len(textureIndexes))
self.bufferTextureIndex = glGenBuffersARB(1)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferTextureIndex)
glBufferDataARB(GL_ARRAY_BUFFER_ARB, ADT.arrayByteCount(numpy.array(textureIndexes,dtype=numpy.float32)), ADT.voidDataPointer(numpy.array(textureIndexes,dtype=numpy.float32)), GL_STATIC_DRAW_ARB)
for color in textureArray:
print str(color)
self.texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_1D, self.texture)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 190, 0, GL_RGB , GL_FLOAT, textureArray)
So I generate my VBO's for vertices, normals, triangles and textureIndexes. Now I wanted to check the value I'm getting for textureIndexes, all are from the interval [0..1] and the length of textureIndexes = length ( vertices ) / 3.
For the texture, I generate a textureArray which is a vector of 190 [x,x,x] rgb values. I've even split it in 6 equal parts. So the first 1/6 entries are one color the next another and so on just to simplify my testing.
Now for the drawing:
glEnableClientState(GL_VERTEX_ARRAY)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferVertices)
glVertexPointer(3, GL_FLOAT, 0, None)
glEnableClientState(GL_NORMAL_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferNormals)
glNormalPointer(GL_FLOAT, 0, None)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferTextureIndex)
glTexCoordPointer(1, GL_FLOAT, 0, None);
glBindTexture(GL_TEXTURE_1D, self.texture)
glEnable(GL_TEXTURE_1D)
glClientActiveTexture(GL_TEXTURE0);
glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, ADT.voidDataPointer(self.triangles))
But all the points are turning out the same color, corresponding to the color of the first 1/6 part of my texture. Any input would be really appreciated.
I'm surprised it is drawing anything at all. On the following line there is a mistake:
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 190, 0, GL_RGB , GL_FLOAT, textureArray)
The OpenGL spec requires that the size of the texture is a power of two. If you replace the 190 with a 256 or a 64, you may get better results.