OpenGL - Render to texture - always blackscreen - opengl

I am new to OpenGL and i am working on a Voxelengine. I want to render my current scene to a texture and then render this texture on a quad. The problem is that i always get a black screen. when i multiply the frag color output by 5 my screen become grey. Therefore I think the problem is, that the texture don't get the output of my renderer. Rendering directly to the default renderer works fine so i think its a problem with my fbo.
Renderer.h:
public ref class DefaultRenderer : RendererBase, IRenderer
{
public:
internal:
protected:
private:
EngineCore::Graphics::GraphicController* GraphicControl_;
Controllers::CameraControl^ CameraControl_;
Controllers::ColorPaletteControl^ ColorPaletteControl_;
Controllers::LightControl^ LightControl_;
unsigned int texture_;
unsigned int FBO_;
unsigned int RBO_;
unsigned int quadVAO_;
unsigned int quadVBO_;
array<float>^ quadVertices_;
EngineCore::Graphics::Shaders::ShaderProgram* screenShader_;
bool IsShadowsEnabled_ = false; // At the moment not used / not implemented
bool IsSkyBoxEnabled_ = true; // At the moment not used / not implemented
bool IsBloomEnabled_ = false; // At the moment not used / not implemented
bool IsToneMappingEnabled_ = false; // At the moment not used / not implemented
bool IsFxaaEnabled_ = false; // At the moment not used / not implemented
public:
DefaultRenderer() {};
~DefaultRenderer() {
this->!DefaultRenderer();
};
!DefaultRenderer() {};
internal:
protected:
private:
public:
/// <summary>
/// Enables Shadows
/// </summary>
virtual void EnableShadows();
/// <summary>
/// Disables Shadows
/// </summary>
virtual void DisableShadows();
/// <summary>
/// Enables Skybox
/// </summary>
virtual void EnableSkyBox();
/// <summary>
/// Disables Skyboy
/// </summary>
virtual void DisableSkyBox();
/// <summary>
/// Enables Bloom
/// </summary>
virtual void EnableBloom();
/// <summary>
/// Disables Bloom
/// </summary>
virtual void DisableBloom();
/// <summary>
/// Enables ToneMapping
/// </summary>
virtual void EnableToneMapping();
/// <summary>
/// Disables ToneMapping
/// </summary>
virtual void DisableToneMapping();
/// <summary>
/// Enables Fxaa
/// </summary>
virtual void EnableIsFxaa();
/// <summary>
/// Disables Fxaa
/// </summary>
virtual void DisableIsFxaa();
/// <summary>
/// This function enable the use of ColorPalette in the PBR-Rendering
/// and disables the use of Texturing for World-Elements.
/// World-Elements are the Voxels.
/// </summary>
virtual void EnableRenderingWithColorPalette();
/// <summary>
/// This function disable the use of ColorPalette in the PBR-Rendering
/// and enables the use of Texturing for World-Elements.
/// World-Elements are the Voxels.
/// </summary>
virtual void DisableRenderingWithColorPalette();
/// <summary>
/// Enables color palette transparency
/// </summary>
virtual void EnableColorTransparency();
/// <summary>
/// Disables color palette transparency
/// </summary>
virtual void DisableColorTransparency();
internal:
void Init(VoxelEngine::IEngine^ engine, EngineCore::Graphics::GraphicController* graphicControl, Controllers::CameraControl^ cameraControl, Controllers::ColorPaletteControl^ colorPalette, EngineCore::Input::InputSystem* input) override;
void Render(std::vector<std::shared_ptr<EngineCore::Culling::Data::ChunkData>> chunksForRendering, frameTimeOffset offsetTime) override;
protected:
private:
/// <summary>
/// This function adds all of our shaders and create an Open GL shader
/// program from them.
/// </summary>
void AddShadersAndCreateGLProgram(VoxelEngine::IEngine^ engine);
/// <summary>
/// In this function all needed uniform buffers are created.
/// </summary>
void CreateUniformBuffers();
/// <summary>
/// In this function all needed voxel buffers are created.
/// </summary>
void CreateVoxelBuffers();
/// <summary>
/// In this function the uniform gets their values.
/// </summary>
void AddUniforms();
/// <summary>
/// In this function the buffers got rendered.
/// </summary>
void RenderVoxelBuffer(EngineCore::Graphics::Buffer::VoxelBuffer tmp, const EngineCore::Graphics::Shaders::ShaderProgram& shaderProgram);
/// <summary>
/// This function creates the framebuffer.
/// </summary>
void CreateFrameBuffer();
};
Renderer.cpp CreateFrameBuffer:
void DefaultRenderer::CreateFrameBuffer()
{
quadVertices_ = gcnew array<float>
{ // positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
float quadVertices[24];
for (size_t i = 0; i < 24; i++)
{
quadVertices[i] = quadVertices_[i];
}
// screen quad VAO
unsigned int quadVAO;
unsigned int quadVBO;
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
quadVAO_ = quadVAO;
quadVBO_ = quadVBO;
glBindVertexArray(quadVAO_);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO_);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
screenShader_ = &GraphicControl_->GetShaderProgram("framebuffer_screen_Program");
screenShader_->Use();
glUniform1i(screenShader_->GetUniform("screenTexture"), 0);
unsigned int framebuffer;
glGenFramebuffers(1,&framebuffer);
FBO_ = framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, FBO_);
// generate texture
unsigned int texColorBuffer;
glGenTextures(1, &texColorBuffer);
texture_ = texColorBuffer;
glBindTexture(GL_TEXTURE_2D, texture_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1920, 1080, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// attach it to currently bound framebuffer object
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
RBO_ = rbo;
glBindRenderbuffer(GL_RENDERBUFFER, RBO_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1920, 1080);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO_);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
}
FBO_ = framebuffer;
texture_ = texColorBuffer;
RBO_ = rbo;
quadVBO_ = quadVBO;
quadVAO_ = quadVAO;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Renderer.cpp Render Loop:
void DefaultRenderer::Render(std::vector<std::shared_ptr<EngineCore::Culling::Data::ChunkData>> chunksForRendering, frameTimeOffset offsetTime)
{
//bind to framebuffer and draw scene to color texture
glBindFramebuffer(GL_FRAMEBUFFER, FBO_ );
//clear framebuffer
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
auto tmp = GraphicControl_->GetVoxelBuffer("test");
tmp.ClearVoxelRenderList();
tmp.VoxelBufferData(chunksForRendering);
AddUniforms();
RenderVoxelBuffer(tmp, GraphicControl_->GetShaderProgram("testProgram"));
// bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//// clear all relevant buffers
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GraphicControl_->GetShaderProgram("framebuffer_screen_Program").Use();
glBindVertexArray(quadVAO_);
glDisable(GL_DEPTH_TEST); // disable depth test
glBindTexture(GL_TEXTURE_2D, texture_); // use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);
}
Renderer.cpp RenderVoxelBuffer:
void DefaultRenderer::RenderVoxelBuffer(EngineCore::Graphics::Buffer::VoxelBuffer tmp, const EngineCore::Graphics::Shaders::ShaderProgram& shaderProgram)
{
shaderProgram.Use();
for (auto const& singleChunk : tmp.List_)
{
glBindVertexArray(singleChunk->Id);
glBindBuffer(GL_ARRAY_BUFFER, singleChunk->VoxelBuffer);
glBufferData(GL_ARRAY_BUFFER, singleChunk->VoxelCount * sizeof(EngineCore::Graphics::Data::VoxelData), singleChunk->List.data(), GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, sizeof(EngineCore::Graphics::Data::VoxelData), 0);
glUniform3f(shaderProgram.GetUniform("u_chunk_location"), (float)singleChunk->OffsetX, (float)singleChunk->OffsetY, (float)singleChunk->OffsetZ);
glDrawArrays(GL_POINTS, 0, singleChunk->VoxelCount);
}
glBindVertexArray(0);
}
framebuffer_screen.fs:
#version 450 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D screenTexture;
void main()
{
vec3 col = texture(screenTexture, TexCoords).rgb;
FragColor = vec4(col, 1.0);
}
framebuffer_screen.vs:
#version 450 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoords;
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}

I forgot to activate my shader before i set my shader attributes. Now everything is working properly

Related

Apply succesive shaders

Recently I've found the following link about simulating fluids on the GPU. I decided to try to implement it using OpenGL but I got stuck on how to apply successive shaders.
For example, I'd need to apply the advection shader, take its output and apply it into the difuse shader (from the link: "The operator is defined as the composition of operators for advection, diffusion, force application, and projection") but I can't figure out how. I've re-read learn opengl framebuffers tutorial but I'm still lost.
Right now I'm trying to do the following, to test communication between shaders:
1- load texture;
2- apply kernel 1 (inverse shader);
3- apply kernel 2 (advect shader);
Step 1 is done only once, while steps 2 and 3 are done while the windows is open.
Here is the shader code:
/////////////////////////////
// read image - shader.frag
/////////////////////////////
#version 330 core
out vec4 FragColor;
in vec2 uv;
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, uv);
}
/////////////////////////////
// color inversion shader
/////////////////////////////
#version 330 core
out vec4 FragColor;
in vec2 uv;
const float offset = 1.0 / 300.0;
void main()
{
FragColor = vec4(vec3(1.0 - texture(screenTexture, uv)), 1.0);
}
/////////////////////////////
// advect shader
/////////////////////////////
#version 330 core
out vec4 FragColor;
in vec2 uv;
uniform float dt;
uniform float sigma_x_inv;
uniform sampler2D u;
uniform sampler2D x;
void main()
{
// change texture2D to texture
vec2 pos = uv - dt * sigma_x_inv * texture(u, uv).xy;
FragColor = texture(x, pos);
}
/////////////////////////////
// vertex shader
/////////////////////////////
#version 330 core
layout (location = 0) in vec3 aPos;
out vec2 uv;
void main()
{
gl_Position = vec4(aPos, 1.0);
uv = aPos.xy;
}
Here is part of my code, mostly taken from here (learn opengl). The screen is just black. If I use one framebuffer(like shown in learn opengl) I can pass data to one shader just fine - I managed to see the inversion and advection shaders working in isolation - but when I add a new frame buffer the screen just goes black. I've also tried using one framebuffer for the two shaders but it didn't work.
Also, how could I pass two textures to one shader? The advection shader, for example, needs to textures, representing two different vector fields. Bellow is my code.
#include "include/glad/glad.h"
#include <GLFW/glfw3.h>
#include "include/shader.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "include/stb_image.h"
#include <glm/glm.hpp>
#include <chrono>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
unsigned int loadTexture(char const * path);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
unsigned int s_width = SCR_WIDTH;
unsigned int s_height = SCR_HEIGHT;
float sigma_x_inv = 1.0f / SCR_WIDTH;
const float dt = 1/60;
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// build and compile our shader program
// ------------------------------------
Shader shader("shaders/shader.vert", "shaders/shader.frag");
Shader advectShader("shaders/shader.vert", "shaders/advect.frag");
Shader inversionShader("shaders/shader.vert", "shaders/inversion.frag");
Shader boundaryShader("shaders/shader.vert", "shaders/boundary.frag");
Shader divergenceShader("shaders/shader.vert", "shaders/divergence.frag");
Shader gradientShader("shaders/shader.vert", "shaders/gradient.frag");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float planeVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
float quadVertices[] =
{
// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
// plane VAO
unsigned int planeVAO, planeVBO;
glGenVertexArrays(1, &planeVAO);
glGenBuffers(1, &planeVBO);
glBindVertexArray(planeVAO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
// screen quad VAO
unsigned int quadVAO, quadVBO;
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
// load and create a texture
// -------------------------
unsigned int texture1, texture2;
// texture 1
// ---------
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
unsigned int blackTexture = loadTexture("textures/black.png");
unsigned int awesomeTexture = loadTexture("textures/awesomeface.png");
shader.use();
shader.setInt("texture1", 0);
// framebuffer configuration
// -------------------------
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create a color attachment texture
unsigned int textureColorbuffer;
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, textureColorbuffer, 0);
// framebuffer configuration
// -------------------------
unsigned int framebuffer2;
glGenFramebuffers(1, &framebuffer2);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
// create a color attachment texture
unsigned int textureColorbuffer2;
glGenTextures(1, &textureColorbuffer2);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, textureColorbuffer2, 0);
// create a renderbuffer object for depth and
// stencil attachment (we won't be sampling these)
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
// use a single renderbuffer object for both a depth AND stencil buffer.
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT);
// now actually attach it
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
// now that we actually created the framebuffer and added all
// attachments we want to check if it is actually complete now
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// tell opengl for each sampler to which texture
// unit it belongs to (only has to be done once)
// -------------------------------------------------------------------------------------------
// advectShader.use(); // don't forget to activate/use the shader before setting uniforms!
// // either set it manually like so:
// advectShader.setInt("u", 0);
// // or set it via the texture class
// advectShader.setInt("x", 1);
divergenceShader.use();
divergenceShader.setFloat("sigma_x_inv", sigma_x_inv);
boundaryShader.use();
boundaryShader.setFloat("scale", 1.0f);
shader.use();
// Program start time
auto start = std::chrono::system_clock::now();
// render
// ------
// bind to framebuffer and draw scene as we normally would to color texture
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
shader.use();
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, awesomeTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// ----
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
glDisable(GL_DEPTH_TEST);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
inversionShader.use();
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer2);
glDrawArrays(GL_TRIANGLES, 0, 6);
// test boy
// -----------------------------
// now bind back to default framebuffer and draw a quad plane
// with the attached framebuffer color texture
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
// glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// glClear(GL_COLOR_BUFFER_BIT);
// density step
// -----------------------------
// boundaryShader.use();
// boundaryShader.setFloat("scale", 1.0f);
// boundaryShader.setVec2("offset", 0.5, 0.5);
// pass current time to shader
advectShader.use();
auto now = std::chrono::system_clock::now();
std::chrono::duration<float> diff = now - start;
advectShader.setFloat("dt", diff.count());
advectShader.setFloat("sigma_x_inv", 1000 * 1 / s_width);
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glDrawArrays(GL_TRIANGLES, 0, 6);
// needs to check how to get shader
// velocity step
// -----------------------------
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &planeVAO);
glDeleteVertexArrays(1, &quadVAO);
glDeleteBuffers(1, &planeVBO);
glDeleteBuffers(1, &quadVBO);
glDeleteFramebuffers(1, &framebuffer);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
s_width = width;
s_height = height;
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// set the texture wrapping parameters
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 texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}

OpenGL Corrupt Shader on MAC

I'm trying to run code from the OpenGL book on my Mac (Mojave) and it doesn't work. The errors I'm getting are:
ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ
ERROR::PROGRAM_LINKING_ERROR of type: PROGRAM
ERROR: Compiled vertex shader was corrupt.
ERROR: Compiled fragment shader was corrupt.
Failed to load texture
#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <shader_s.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// build and compile our shader zprogram
// ------------------------------------
Shader ourShader("st.vs", "st.fs");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int VBO, VAO, EBO;
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);
// load and create a texture
// -------------------------
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
// 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;
// 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("container.jpg", &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);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// bind Texture
glBindTexture(GL_TEXTURE_2D, texture);
// render container
ourShader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
Texture file st.fs
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
The texture st.vs
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
Try using an absolute path instead of a relative one.

Qt & OpenGL : render a 2D texture

I'm trying to render my first texture with Qt & OpenGL.
This is the code.
initializeGL function
void OpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(debugCallback, nullptr);
program = genProgram("../06_HelloTexture/vert.glsl", "../06_HelloTexture/frag.glsl");
glUseProgram(program);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glEnable(GL_DEPTH_TEST);
// vertices is std::vector<QVector3D>
vertices = {
{-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 0.0f},
{-0.5f, +0.5f, 0.0f}, {0.0f, 1.0f, 0.0f},
{+0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f},
{+0.5f, +0.5f, 0.0f}, {1.0f, 1.0f, 0.0f},
};
// indices is std::vector<GLuint>
indices = {
0, 1, 2,
1, 2, 3,
};
GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(QVector3D), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(GLuint), &indices[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2*sizeof(QVector3D), static_cast<void*>(nullptr));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 2*sizeof(QVector3D), (void*)sizeof(QVector3D));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
QImage image("../lightbulb-solid.svg");
// QImage image("../test.png");
qDebug() << image;
// this outputs
// QImage(QSize(352, 512),format=6,depth=32,devicePixelRatio=1,bytesPerLine=1408,sizeInBytes=720896)
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
// glGenerateMipmap(GL_TEXTURE_2D);
lightbulbSolidLocation = glGetUniformLocation(program, "lightbulbSolid");
glUniform1i(lightbulbSolidLocation, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
}
paintGL function
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, nullptr);
}
vertex shader
#version 450 core
layout (location = 0) in vec3 vertPosition;
layout (location = 1) in vec3 vertTexCoord;
out vec3 fragTexCoord;
void main()
{
gl_Position = vec4(vertPosition, 1.0);
fragTexCoord = vertTexCoord;
}
fragment shader
#version 450 core
in vec3 fragTexCoord;
out vec4 pixelColor;
uniform sampler2D lightbulbSolid;
void main()
{
// pixelColor = vec4(fragColor, 1.0f);
// pixelColor = texture(lightbulbSolid, vec2(fragTexCoord.x, fragTexCoord.y));
vec4 temp = texture(lightbulbSolid, vec2(fragTexCoord.x, fragTexCoord.y));
if (!all(equal(temp.xyz, vec3(0.0f))))
{
pixelColor = temp;
}
else
{
pixelColor = vec4(fragTexCoord, 1.0f);
}
}
And this is the result
As you can see, all the colors generated by the texture function in the fragment shader are black, so the if statement choose the texture coordinate as color rather than the real texture color.
I tried to catch some error, but the callback function didn't find something wrong in the code. I also tried with another image (of PNG format rather than SVG), but the result is the same.
If you want to load a PNG file, then you can load it to a QImage directly,
QImage image("../test.png");
but if you want to render SVG file, then you have to use the QSvgRenderer and QPainter to paint the content to an QImage. You have to choose the format, the resolution and the background color of the target bitmap:
e.g.:
#include <Qtsvg/QSvgRenderer>
QSvgRenderer renderer(QString("../lightbulb-solid.svg"));
QImage image(512, 512, QImage::Format_RGBA8888); // 512x512 RGBA
image.fill(0x00ffffff); // white background
QPainter painter(&image);
renderer.render(&painter);
const uchar *image_bits = image.constBits();
int width = image.width();
int height = image.height();
Note, you have to link qt5svgd.lib (debug) respectively qt5svg.lib (release).
The default minifying function parameter (GL_TEXTURE_MIN_FILTER) is GL_NEAREST_MIPMAP_LINEAR. See glTexParameteri
This means either you have to change the GL_TEXTURE_MIN_FILTER parameter to GL_LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image_bits);
or you have to create mipmaps
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image_bits);
glGenerateMipmap(GL_TEXTURE_2D);
In the initializeGL method the texture is bound to texture unit 0, but it is not guaranteed, that this is still the current state in the paintGL method. You have to bind the texture in the paintGL method:
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, nullptr);
}

GL_TEXTURE_2D as render input

I have an image in a GL_TEXTURE_2D. From here, I need to move this texture onto the framebuffer object. Can someone please point me to an example that uses a 2d texture that is filled with data and places it onto the FBO? I am not trying to render to a texture, but from a texture.
Here is a simple FBO demonstration.
You can find the entire code here on github (the code is based on this sample program from the OpenGL SuperBible).
The program does the following
Draws a red square onto a green background into a FBO. The backing store for the FBO is a 2D texture.
Draw a square onto a blue screen but map the texture from step 1 to the square. This maps the entire scene from the previous step onto the square.
So the theory when using a framebuffer,
(Initialisation) Attach textures to an off-screen framebuffer.
and then there are 2 programs (or 2 passes)
In program 1, render into the framebuffer (which renders into the textures)
In program 2, now render to the window (screen) and use the texture(s) from the first program as input.
So the output of the first program is the input for the second program.
That means the vertex shaders for both stages will be the same. As there is no mathes (rotation) and no lighting effects, all the vertex shader does is pass the input to the output (i.e. the coordinates).
But each stage will have slightly different fragment shader.
The 1st fragment shader outputs a constant color for each pixel. In the source code the output of the 1st fragment shader is configured to the FBO and the FBO uses a texture to store the color data.
The texture generated in the 1st fragment shader is used as input in the 2nd fragment shader. In the 2nd fragment shader, the color is determined by the texture (which is the output of the 1st fragment shader).
So here is the vertex shader. Note the input to the vertex shader is the coordinates (vp) and the texture coordinates. The texcoords are needed by the 2 program's fragment shader to know where to map the texture. In the vertex shader the texcoord's are simply passed from the input to the output.
#version 130
in vec3 vp;
in vec2 texcoord;
out vec2 outtexcoord;
void main () {
gl_Position = vec4 (vp, 1.0);
outtexcoord = texcoord;
}
This is the 1st program's fragment shader. Every pixel is drawn red.
#version 130
in vec2 outtexcoord;
out vec4 frag_colour;
void main () {
frag_colour = vec4 (1.0, 0.0, 0.0, 0.0); //everything red
}
And the 2nd programs fragment shader. Note the sampler2D which is the input texture (generated by the 1st program). Also the outtexcoord are the texture coordinates from the vertex shader. The output color (frag_color) is determined by the texture.
#version 130
uniform sampler2D tex;
in vec2 outtexcoord;
out vec4 frag_color;
void main () {
frag_color = texture(tex, outtexcoord);
}
And here is the C program (I compiled with g++, see the makefile in the github link).
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "shader_utils.h" //see github link for details
void Initialize();
void InitGL();
void InitProgramFBO();
void InitProgramScreen();
void InitBuffer();
void InitFBO();
void Loop();
void RenderToFBO();
void RenderToScreen();
void Shutdown();
void OnWindowResize(GLFWwindow* window, int width, int height);
GLFWwindow* window;
int screenWidth = 640;
int screenHeight = 480;
GLuint render2FBOProgram;
GLuint render2ScreenProgram;
GLuint vao;
GLuint vbo;
GLuint fbo;
GLuint color_texture;
int main() {
Initialize();
Loop();
Shutdown();
return 0;
}
void Initialize() {
InitGL();
InitProgramScreen();
InitProgramFBO();
InitBuffer();
InitFBO();
}
void InitGL() {
glfwInit();
window = glfwCreateWindow(screenWidth, screenHeight, "FBO Demo", NULL, NULL);
glfwMakeContextCurrent(window);
glewInit();
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
}
void InitProgramFBO() {
GLuint vs;
GLuint fs;
render2FBOProgram = create_program("vs.glsl", "fbo.fs.glsl", vs, fs);
glDeleteShader(vs);
glDeleteShader(fs);
}
void InitProgramScreen() {
GLuint vs;
GLuint fs;
render2ScreenProgram = create_program("vs.glsl", "screen.fs.glsl", vs, fs);
glDeleteShader(vs);
glDeleteShader(fs);
}
void InitBuffer() {
//define the square made up of 2 triangles
static const GLfloat points[] = {
//x y z texcoord u and v
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f
};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//create buffer for points
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
//tell opengl how to find the coordinate data
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLubyte*)NULL);
glEnableVertexAttribArray(0);
//tell opengl how to find the texcoord data
glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
}
void InitFBO() {
//create a framebuffer
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//create a texture as the backing store for the framebuffer
glGenTextures(1, &color_texture);
glBindTexture(GL_TEXTURE_2D, color_texture);
glTexStorage2D(GL_TEXTURE_2D, 9, GL_RGBA8, 512, 512); //1 = mipmap levels
//mip map filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//attach the texture as the color attachment of the framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);
//tell opengl to draw into the color attachment
static const GLenum draw_buffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_buffers);
}
void Loop() {
//glBindVertexArray(vao);
//glBindBuffer(GL_ARRAY_BUFFER, vbo);
while (!glfwWindowShouldClose(window)) {
RenderToFBO();
RenderToScreen();
glfwSwapBuffers(window);
glfwPollEvents();
if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
glfwSetWindowShouldClose(window, 1);
}
}
}
void RenderToFBO() {
static const GLfloat green[] = { 0.0f, 1.0f, 0.0f, 1.0f }; //texture background is green
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, 512, 512); //set view port to texture size
glClearBufferfv(GL_COLOR, 0, green);
glUseProgram(render2FBOProgram);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void RenderToScreen() {
static const GLfloat blue[] = { 0.0f, 0.0f, 1.0f, 1.0f }; //screen background is blue
glViewport(0, 0, screenWidth, screenHeight);
glClearBufferfv(GL_COLOR, 0, blue);
glBindTexture(GL_TEXTURE_2D, color_texture);
glUseProgram(render2ScreenProgram);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Shutdown() {
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteProgram(render2FBOProgram);
glDeleteProgram(render2ScreenProgram);
glfwTerminate();
}
// a call-back function
void OnWindowResize(GLFWwindow* window, int width, int height) {
screenWidth = width;
screenHeight = height;
glViewport(0, 0, screenWidth, screenHeight);
}

How can I make my render textures use correct depth?

I'm writing a little voxel thing in OpenGL and this is my first time using framebuffers.
As you'll be able to see above, the water and above water terrain is rendering above the underwater terrain. This is an undesired effect, and I was wondering if there was a way to get rid of it.
Framebuffer's are initialized with the code below.
bool Framebuffer::Create(int width, int height) {
// set width and height
m_width = width;
m_height = height;
// create a frame buffer object
glGenFramebuffers(1, &m_fbo);
// generate a texture id
glGenTextures(1, &m_tid);
// bind both the fbo and to
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glBindTexture(GL_TEXTURE_2D, m_tid);
// generate a texture for the framebuffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// set the texture filtering to nearest
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// create a depth renderbuffer
glGenRenderbuffers(1, &m_dbr);
glBindRenderbuffer(GL_RENDERBUFFER, m_dbr);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// set the color output for the texture to be the render texture
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_tid, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_dbr);
// set the amount of draw buffers for the framebuffer
GLenum buffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, buffers);
int fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fboStatus != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "[ERROR]: Framebuffer failed to create!" << std::endl;
std::cout << ((fboStatus == GL_FRAMEBUFFER_UNSUPPORTED) ? "Framebuffer Unsupported!\n" : "");
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// the stride for the data
// stride is the byte amount for each element
// stride is equal to seven because three coordinates per vertex
// and four coordinates per color
int stride = 5 * sizeof(GLfloat);
// the offset for the vertex data
// this is zero because the vertex data starts immediately
void* vertOff = reinterpret_cast<void*>(0);
// the offset for the color data
// this is three because it starts right after the vertex data
// multiplied by the byte size of a float
void* texOff = reinterpret_cast<void*>(3 * sizeof(GLfloat));
// create the quad for rendering this framebuffer
glGenBuffers(1, &m_vbo);
glGenVertexArrays(1, &m_vao);
// bind the vao and vbo
glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
// the vertex and uv data for the quad
const GLfloat quad_data[] = {
// First Triangle
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
// Second Triangle
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f
};
// set the buffer data to the quad data
glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);
// set the first attribute to the vertex data
glVertexAttribPointer(0, 3, GL_FLOAT, false, stride, vertOff);
// set the second attribute to the uv data
glVertexAttribPointer(1, 2, GL_FLOAT, false, stride, texOff);
// unbind the vao and vbo
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_initialized = true;
return true;
}
I render the whole world with the code below.
(the Draw*() functions in the code just call draw on the vbo, nothing else)
void World::Draw() {
// the shaders needed to draw
Shader* framebuffer = vxl::GetShaderManager()->GetShader("framebuffer");
Shader* drawFramebuffer = vxl::GetShaderManager()->GetShader("drawFramebuffer");
Shader* drawBlurFramebuffer = vxl::GetShaderManager()->GetShader("drawBlurFramebuffer");
Shader* water = vxl::GetShaderManager()->GetShader("water");
Shader* normal = vxl::GetShaderManager()->GetShader("normal");
// the camera position to chunk coordinates
int chunkX = static_cast<int>(floor(vxl::GetCameraPosition().x) / 16.0f / 2.0f) >> 4;
int chunkZ = static_cast<int>(floor(-vxl::GetCameraPosition().z) / 16.0f / 2.0f) >> 4;
// the amount of chunks to render, plus the center
const int chunkRenderDistance = 3;
for (int z = chunkZ - chunkRenderDistance; z < chunkZ + chunkRenderDistance; z++) {
for (int x = chunkX - chunkRenderDistance; x < chunkX + chunkRenderDistance; x++) {
m_renderChunks.push_back(m_chunks[Position(x * m_chunkSize, 0, z * m_chunkSize)]);
}
}
// draw each opaque object into the opaque framebuffer
// this just draws all of the geometry with a black transparent clear color
// allowing for blending with other objects in the scene
// this isn't going to be flipped, so the flipped arg should be false
_DrawOpaqueFBO(framebuffer, false);
// draw the opaque objects with the framebuffer quad
_DrawFBOToQuad(&m_opaqueFbo, drawFramebuffer, false);
// redraw the fbo but upside down
// this allows for reflections to actually work correctly
// this is going to be flipped, so the flipped arg should be true
_DrawOpaqueFBO(framebuffer, true);
// draw the water in this scene
_DrawWater(water);
// draw the water in this scene
// draw the objects underwater
// bind the normal shader
normal->Bind();
// draw each underwater part of a chunk
for (size_t i = 0; i < m_renderChunks.size(); i++) {
if (m_renderChunks[i] != nullptr) {
if (!m_renderChunks[i]->GetUnderwaterRenderer()->IsAllocationQueued() && m_renderChunks[i]->GetUnderwaterRenderer()->NeedsAllocation()) {
m_pool.AssignTask(&StaticRenderer::AllocVoxels, m_renderChunks[i]->GetUnderwaterRenderer());
m_renderChunks[i]->GetUnderwaterRenderer()->SetAllocationQueued(true);
}
if (!m_renderChunks[i]->GetUnderwaterRenderer()->IsAllocationQueued() && !m_renderChunks[i]->GetUnderwaterRenderer()->NeedsAllocation())
m_renderChunks[i]->DrawUnderwater(normal);
}
}
normal->Unbind();
// draw the water
_DrawFBOToQuad(&m_waterFbo, drawBlurFramebuffer, true);
// clear all of the render chunks for next frame
m_renderChunks.clear();
}
void World::_DrawFBOToQuad(Framebuffer* fbo, Shader* shader, bool drawBlurred) {
// bind the shader for rendering to a texture
shader->Bind();
// set the active texture to zero
shader->Uniform1f("tex", 0);
if (drawBlurred) {
// the viewport for the quad
shader->Uniform2f("viewport", static_cast<float>(vxl::GetWidth()), static_cast<float>(vxl::GetHeight()));
// the direction for blurring
shader->Uniform2f("blurDir", 0.0f, 1.0f);
// the radius to blur
shader->Uniform1f("blurRadius", 1.0f);
}
// bind the framebuffer's texture id
glBindTexture(GL_TEXTURE_2D, fbo->GetTextureID());
// draw the actual framebuffer quad
fbo->Draw();
// unbind the texture
glBindTexture(GL_TEXTURE_2D, 0);
// unbind the shader for other shaders
shader->Unbind();
}
The Framebuffer::Create method just makes a framebuffer object with a color texture and a depth renderbuffer. I feel like the depth renderbuffer isn't being written to correctly, as if I run a debugger, the depth is just pure white.
The World::Draw method just gets a number of chunks within the render distance, so that it can actually draw the world.
The World::_Draw* methods render the specific piece into its respective FBO. For example, World::_DrawOpaqueFBO just draws the opaque above water terrain to the opaque framebuffer.
The World::_DrawFBOToQuad just draws the render texture to the screen, using the quad built from Framebuffer::Create.
I have no clue how to go about making the depth actually work for each framebuffer quad. Depth testing is enabled, and I also clear the depth and color buffer bits.
Thanks in advance for any help :)