I'm currently working in a deferred shading and I created a class which manages the FBOs and draw the buffers on the screen.
This is how it looks so far:
FBORender::FBORender(float screenWidth, float screenHeight) :
_screenWidth(screenWidth),
_screenHeight(screenHeight),
ProgramManager("defVertexShader.txt", "defFragShader.txt")
{
CreateProgram();
_vbo[0] = 0;
_vbo[1] = 0;
_vao = 0;
BuildQuad();
BuildVAO();
glGenFramebuffers(1, &_fbo);
glGenRenderbuffers(1, &_depthBuffer);
// Bind the depth buffer
glBindRenderbuffer(GL_RENDERBUFFER, _depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, (int)_screenWidth, (int)_screenHeight);
// Generate and bind the texture for diffuse
glGenTextures(1, &_diffuseBuffer);
glBindTexture(GL_TEXTURE_2D, _diffuseBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)_screenWidth, (int)_screenWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Generate and bind the texture for positions
glGenTextures(1, &_positionBuffer);
glBindTexture(GL_TEXTURE_2D, _positionBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, (int)_screenWidth, (int)_screenWidth, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Generate and bind the texture for normals
glGenTextures(1, &_normalBuffer);
glBindTexture(GL_TEXTURE_2D, _normalBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, (int)_screenWidth, (int)_screenWidth, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Bind the FBO so that the next operations will be bound to it.
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
// Attach the textures to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _diffuseBuffer, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _positionBuffer, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, _normalBuffer, 0);
GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
{
printf("DeferredLighting::Init: FrameBuffer incomplete: 0x%x\n", fboStatus);
exit(1);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
FBORender::~FBORender()
{
glDeleteTextures(1, &_normalBuffer);
glDeleteTextures(1, &_positionBuffer);
glDeleteTextures(1, &_diffuseBuffer);
glDeleteFramebuffers(1, &_fbo);
glDeleteVertexArrays(1, &_vao);
glDeleteBuffers(2, _vbo);
}
void FBORender::Start()
{
// Bind the FBO and set the viewport to the proper size
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
glViewport(0, 0, (int)_screenWidth, (int)_screenWidth);
// Clear the render targets
GLenum windowBuffClear[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, windowBuffClear);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLenum windowBuffOpaque[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, windowBuffOpaque);
}
void FBORender::Draw(const glm::mat4 &Projection, const glm::mat4 &ModelView)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_ModelViewProjection = Projection * ModelView;
_ModelView = ModelView;
glDisable(GL_DEPTH_TEST);
Bind();
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _normalBuffer);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _positionBuffer);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _diffuseBuffer);
glBindVertexArray(_vao);
LoadUniformVariables();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
UnBind();
}
void FBORender::Stop()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void FBORender::BuildQuad()
{
_coordinates[0] = 1.0f;
_coordinates[1] = 1.0f;
_coordinates[2] = 0.0f;
_coordinates[3] = -1.0f;
_coordinates[4] = 1.0f;
_coordinates[5] = 0.0f;
_coordinates[6] = 1.0;
_coordinates[7] = -1.0f;
_coordinates[8] = 0.0f;
_coordinates[9] = -1.0f;
_coordinates[10] = -1.0f;
_coordinates[11] = 0.0f;
_uv[0] = 1.0f;
_uv[1] = 1.0f;
_uv[2] = 0.0f;
_uv[3] = 1.0f;
_uv[4] = 1.0f;
_uv[5] = 0.0f;
_uv[6] = 0.0f;
_uv[7] = 0.0f;
}
void FBORender::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(2, _vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), _coordinates, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), _uv, GL_STATIC_DRAW);
LoadAttributeVariables();
glBindVertexArray(0);
}
void FBORender::LoadUniformVariables()
{
// OpenGL Matrices
GLuint ModelViewProjection_location = glGetUniformLocation(GetProgramID(), "mvMatrix");
glUniformMatrix4fv(ModelViewProjection_location, 1, GL_FALSE, glm::value_ptr(_ModelView));
// Texture buffers
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _diffuseBuffer);
GLint Diffuse_location = glGetUniformLocation(GetProgramID(), "tDiffuse");
glUniform1i(Diffuse_location, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _positionBuffer);
GLint Position_location = glGetUniformLocation(GetProgramID(), "tPosition");
glUniform1i(Position_location, 0);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _normalBuffer);
GLint Normal_location = glGetUniformLocation(GetProgramID(), "tNormals");
glUniform1i(Normal_location, 0);
}
void FBORender::LoadAttributeVariables()
{
// Vertex Attributes
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "uvCoord");
printf("%d \n", TextureCoord_Location);
glEnableVertexAttribArray(TextureCoord_Location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
}
And those are my shaders:
#version 410 core
uniform mat4 mvMatrix;
in vec4 vPosition;
in vec2 uvCoord;
smooth out vec2 texCoord;
void main(void)
{
texCoord = uvCoord;
gl_Position = vPosition * mvMatrix;
}
#version 410 core
uniform sampler2D tDiffuse;
uniform sampler2D tPosition;
uniform sampler2D tNormals;
in vec2 texCoord;
out vec4 fragColor;
void main( void )
{
vec4 image = texture( tDiffuse, texCoord.st );
vec4 position = texture( tPosition, texCoord.st );
vec4 normal = texture( tNormals, texCoord.st );
fragColor.xyz = vec3(0.5f, 0.5f, 0.5f);
}
The problems is that when I try to set the attribute variables the one called uvCoord is not found. I think this may be due to an optimization, however, if that's so, what am I'm doing wrong or how should I do it? The uvCoord is used in the fragment shader.
The uvCoord is used in the fragment shader.
No it is not. Your output is a constant color. As a result, the texture fetches before are all eliminated by a decent compiler, as is the texCoord varying. This ultimately results in the elimination of the input attribute, which simply does not affect the output of the program in any way. This is allowed by the GL spec. Your attribute is just not considered active, but only active attributes have locations.
Related
I'm trying to create an opengl program that creates a 2d square, and applies 2 textures on it.
I followed this tutorial: https://learnopengl.com/Getting-started/Textures
This is my fragment shader:
#version 330 core
//in vec3 Color;
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D Texture1;
uniform sampler2D Texture2;
void main()
{
FragColor = mix(texture(Texture1, TexCoord), texture(Texture2, TexCoord), 0.5);
}
This is the code that sends the textures and the uniforms:
GLuint Tex1, Tex2;
int TexWidth, TexHeight, TexNrChannels;
unsigned char* TexData = stbi_load("container.jpg", &TexWidth, &TexHeight, &TexNrChannels, 0);
glGenTextures(1, &Tex1);
glBindTexture(GL_TEXTURE_2D, Tex1);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TexWidth, TexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, TexData);
glGenerateMipmap(GL_TEXTURE_2D);
glUniform1i(glGetUniformLocation(Program, "Texture1"), 0);
stbi_image_free(TexData);
TexData = stbi_load("awesomeface.png", &TexWidth, &TexHeight, &TexNrChannels, 0);
glGenTextures(1, &Tex2);
glBindTexture(GL_TEXTURE_2D, Tex2);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexWidth, TexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, TexData);
glGenerateMipmap(GL_TEXTURE_2D);
glUniform1i(glGetUniformLocation(Program, "Texture2"), 1);
stbi_image_free(TexData);
And this is the render loop:
while (!glfwWindowShouldClose(window))
{
processInput(window);
// GL render here
glClearColor(0.05f, 0.0f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Tex1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Tex2);
glUseProgram(Program);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
When I run it, only the first texture shows up on the square, and the a argument (last argument) of the mix function in the shader won't make a difference for any value.
I tried activating (glActiveTexture + GlBindTexture) the second texture first in the render loop, and it caused the second texture to be shown exclusively.
How can I make the textures mix together like in the tutorial?
If this approach is wrong, I would like to learn about another way to accomplish the same result.
glUniform1i set a value in the default uniform block of the currently installed program. You have to install the program with glUseProgram, before you can set the value of a uniform variable:
GLint t1_loc = glGetUniformLocation(Program, "Texture1");
GLint t2_loc = glGetUniformLocation(Program, "Texture2");
glUseProgram(Program);
glUniform1i(t1_loc, 0);
glUniform1i(t2_loc, 1);
Alternatively you can use glProgramUniform1i:
glProgramUniform1i(Program, t1_loc, 0);
glProgramUniform1i(Program, t2_loc, 1);
I'm trying to make a skybox that can change with a button.
My solution for this is to bind my skyboxes and load my textures in the following way:
//SkyBox
GLuint skyboxVBO, skyboxVAO;
glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *)0);
// Load textures
vector<const GLchar*> facesN;
facesN.push_back("SkyBox/night/right.tga");
facesN.push_back("SkyBox/night/left.tga");
facesN.push_back("SkyBox/night/top.tga");
facesN.push_back("SkyBox/night/bottom.tga");
facesN.push_back("SkyBox/night/back.tga");
facesN.push_back("SkyBox/night/front.tga");
GLuint cubemapTextureN = TextureLoading::LoadCubemap(facesN);
vector<const GLchar*> faces;
faces.push_back("SkyBox/day/right.tga");
faces.push_back("SkyBox/day/left.tga");
faces.push_back("SkyBox/day/top.tga");
faces.push_back("SkyBox/day/bottom.tga");
faces.push_back("SkyBox/day/back.tga");
faces.push_back("SkyBox/day/front.tga");
GLuint cubemapTexture = TextureLoading::LoadCubemap(faces);
Then, in the program loop I draw the skybox with the following:
// Draw skybox as last
glDepthFunc(GL_LEQUAL); // Change depth function so depth test passes when values are equal to depth buffer's content
SkyBoxshader.Use();
view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // Remove any translation component of the view matrix
glUniformMatrix4fv(glGetUniformLocation(SkyBoxshader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(SkyBoxshader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
// skybox cube
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE1);
if (daytime == 1.0f) {
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
}
else {
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTextureN);
}
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS); // Set depth function back to default
In theory, whenever I press the button that changes the value of daytime, the skybox should change its textures to cubemapTextureN and, with another press of the button, change back to cubemapTexture. Instead, it just draws the texture that was loaded last, cubemapTexture in this case.
I already tested daytime and it does change, so it's not that.
Also, I tried loading cubemapTextureN after cubemapTexture and by doing so cubemapTextureN gets drawn instead, but still no change. I'm assuming somehow while loading the second textures, the first ones get updated, which shouldn't happen since they have different names, unless i'm understanding it wrong.
Easy solution would be to just make models of the entire skyboxes and work with that, but if possible I want to see if I can use this solution.
Edit:
These are the Shaders for the skybox.
Fragment shader:
#version 330 core
in vec3 TexCoords;
out vec4 color;
uniform samplerCube skybox;
void main()
{
color = texture(skybox, TexCoords);
}
Vertex shader:
#version 330 core
layout (location = 0) in vec3 position;
out vec3 TexCoords;
uniform mat4 projection;
uniform mat4 view;
void main()
{
vec4 pos = projection * view * vec4(position, 1.0);
gl_Position = pos.xyww;
TexCoords = position;
}
And their use:
Shader SkyBoxshader("Shaders/SkyBox.vs", "Shaders/SkyBox.frag");
Also, if this is usefull, this is the header with the definition of TextureLoading, which contains LoadCubemap
#pragma once
// GLEW
#include <GL/glew.h>
// Other Libs
#include "stb_image.h"
// Other includes
#include "Model.h"
#include <vector>
class TextureLoading
{
public:
static GLuint LoadTexture(GLchar *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);
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);
stbi_image_free(data);
}
else
{
std::cout << "Failed to load texture" << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
static GLuint LoadCubemap(vector<const GLchar * > faces)
{
GLuint textureID;
glGenTextures(1, &textureID);
int width, height, nrChannels;
for (unsigned int i = 0; i < faces.size(); i++)
{
unsigned char *data = stbi_load(faces[i], &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
else
{
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return textureID;
}
};
So I have an fbo and trying to output a depth texture from the light source perspective. Unfortunately the depth texture is coming out pure white even if I hard code black in the frag shader.
This is my frame buffer initialization
//Render frame to a texture
m_FrameBuffer = 0;
glGenFramebuffers(1, &m_FrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_FrameBuffer); // once frame buffer is bound, must draw to it or black screen
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &m_depthTexture);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_depthTexture, 0);
glDrawBuffer(GL_NONE);
//Always check that our framebuffer is ok
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
printf("frame buffer binding error");
glBindTexture(GL_TEXTURE_2D, 0);
this is my rendering of frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, m_FrameBuffer);
glViewport(0, 0, 1024, 1024);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
glDisableVertexAttribArray(0);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
This is my fragment shader
#version 330 core
// Ouput data
layout(location = 0) out float fragmentdepth;
void main()
{
//fragmentdepth = gl_FragCoord.z;
fragmentdepth = 0;
}
This is my main loop
while (!window.closed())
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glDepthFunc(GL_LESS);
window.clear();
CameraControls();
depth.enable();
//depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;
depth.setUniformMat4("projection", projection);
depth.setUniformMat4("view", camera);
depth.setUniformMat4("model", shape1->modelMatrix);
shape1->RenderToTexture();
depth.disable();
window.clear();
basic.enable();
basic.setUniformMat4("proj", projection);
//basic.setUniform3f("light_Pos", lightPos);
basic.setUniformMat4("view", camera);
basic.setUniformMat4("model", shape1->modelMatrix);
basic.setUniformMat4("DepthBiasMVP", biasMatrix);
//NEED TO CHANGE THIS TO BIAS MATRIX X DEPTHMVP
//MVP = projection * camera * shape1->modelMatrix;
//basic.setUniformMat4("MVP", MVP);
shape1->Render(basic);
basic.disable();
window.update();
}
I am following this tutorial http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/
Just answering my own question after looking at my old questions that weren't resolved. If anyone is wondering, my problem was that I had fused two tutorials into one and one of them had different near and far values for the frustum. The framebuffer was black because the object was too far from the camera.
I am having trouble sending two textures to my fragment shader via uniform sampler2Ds. My fragment shader has two uniforms but it appears that my code sends the same image to both samplers. The texture bound first seems to be automatically bound to both uniforms.
The full C++ code is below:
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SOIL/SOIL.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
int main(int argc, const char* argv[])
{
GLFWwindow* display;
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
display = glfwCreateWindow(1280, 720, "Game Engine", nullptr, nullptr);
glfwMakeContextCurrent(display);
glewExperimental = GL_TRUE;
GLenum success = glewInit();
GLint height, width;
glfwGetFramebufferSize(display, &width, &height);
glViewport(0, 0, width, height);
glEnable(GL_DEPTH_TEST);
GLuint program;
std::string vertexCode, fragmentCode;
std::ifstream vShaderFile, fShaderFile;
std::string vertexPath = "Basic.vert";
std::string fragmentPath = "Basic.frag";
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
vShaderFile.close();
fShaderFile.close();
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch(std::ifstream::failure error)
{
std::cout << "Error: Shader file not successfully read." << std::endl;
}
GLuint vertex, fragment;
GLchar infoLog[512];
const GLchar* vertShaderCode = vertexCode.c_str();
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertShaderCode, NULL);
glCompileShader(vertex);
const GLchar* fragShaderCode = fragmentCode.c_str();
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragShaderCode, NULL);
glCompileShader(fragment);
program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
glDeleteShader(vertex);
glDeleteShader(fragment);
GLfloat vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
};
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
(GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
GLuint texture0, texture1;
glGenTextures(1, &texture0);
glBindTexture(GL_TEXTURE_2D, texture0);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
unsigned char* image = SOIL_load_image("container.jpg",
&width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
GLint uniform = glGetUniformLocation(program, "texture0");
glUniform1i(uniform, 0);
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
image = SOIL_load_image("awesomeface.png",
&width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
uniform = glGetUniformLocation(program, "texture1");
glUniform1i(uniform, 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture1);
while (!glfwWindowShouldClose(display))
{
glClearColor(0.761f, 0.698f, 0.502f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(display);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
return EXIT_SUCCESS;
}
The associated GLSL shader files are below:
The vertex shader:
#version 400 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(position, 1.0f);
TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
}
The fragment shader:
#version 400 core
in vec2 TexCoord;
out vec4 fragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
void main()
{
vec4 color1 = texture(texture0, TexCoord);
vec4 color2 = texture(texture1, TexCoord);
fragColor = mix(color1, color2, 0.4f);
}
glUniform1i(uniform, 0);
This function acts on the program that is currently in use. You don't call glUseProgram until the render loop. So it should give you a GL_INVALID_OPERATION error and therefore does nothing.
You should either use glProgramUniform from GL 4.1+ (which takes the program it acts on) or call glUseProgram before setting the uniform value.
In this section of your code:
GLuint texture0, texture1;
glGenTextures(1, &texture0);
glBindTexture(GL_TEXTURE_2D, texture0);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
unsigned char* image = SOIL_load_image("container.jpg",
&width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
//GLint uniform = glGetUniformLocation(program, "texture0");
//glUniform1i(uniform, 0);
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
image = SOIL_load_image("awesomeface.png",
&width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
//uniform = glGetUniformLocation(program, "texture1");
//glUniform1i(uniform, 1);
//glActiveTexture(GL_TEXTURE0);
//glBindTexture(GL_TEXTURE_2D, texture0);
//glActiveTexture(GL_TEXTURE1);
//glBindTexture(GL_TEXTURE_2D, texture1);
Remove the commented lines from the section above. Just load the images first;
don't worry about the uniforms yet and don't bind them here. You will need to active your shader/program first before setting any uniforms.
This section should now look like this:
GLuint texture0, texture1;
// Setup Texture1
glGenTextures(1, &texture0);
glBindTexture(GL_TEXTURE_2D, texture0);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
unsigned char* image = SOIL_load_image("container.jpg",
&width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
// Setup Texture 2
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
image = SOIL_load_image("awesomeface.png",
&width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
Now after you have setup your two textures and after you have freed the resources from SOIL what you will need to do next is to use or activate your shader-program.
glUseProgram( program );// Need to activate your shader before setting any uniforms
Then after that you can acquire your uniforms before your render loop:
// After activating the shader set your uniforms here before your
// render loop. You don't want to do this on every iteration.
glUniform1i( glGetUniformLocation( program, "texture1" ), 0 );
glUniform1i( glGetUniformLocation( program, "texture2" ), 1 );
Then within the render loop after you handle or process any time & input information and after you set the clear color and clear the color buffer is where and when you want to bind your textures.
while ( !glfwWindowShouldClose( display ) ) {
// time
...
// input
...
// color buffer
...
// Bind textures
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, texture1 );
glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, texture2 );
// now render the container using the shader
glUseProgram( program );
glBindVertexArray( VAO );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
// Swap buffers
} // end loop
Also as a side note you can do this in your fragement shader:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;
void main() {
// linearly interpolate between both textures
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.4);
}
This is basically the same as what you have above but is written in a single line of code and it doesn't resort to using 2 local variables. Remember fragment shaders are expensive because they run for each and every pixel or fragment for each iteration of your render loop. It looks more convoluted in what I've shown than yours but it is more efficient. Compliments of www.learnopengl.com.
There's some Artifacts on my FrameBuffer Depth Texture I can't get rid off:
The Code used to init the FrameBuffer:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color, 0);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, depth, 0);
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, attachments);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "FBO FEHLER" << std::endl;
}
Code used to draw the FrameBuffer:
shader->bind();
// Bind Textures
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, color);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depth);
glUniform1i(shader->getUniform("tex"), 0);
glUniform1i(shader->getUniform("depth"), 1);
glUniformMatrix4fv(shader->getUniform("matrix"), 1, GL_FALSE, glm::value_ptr(ortho));
// Draw Call
glBindBuffer(GL_ARRAY_BUFFER,fbovbo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, (void*)12);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Unbind
shader->unbind();//*/
FragmentShader of the actual rendering:
#version 330 core
layout(location = 0) out vec4 out_color;
layout(location = 1) out vec4 out_depth;
in float temp;
void main(void){
out_color = vec4(1,0.0,0.0,1.0);
out_depth = vec4(gl_FragCoord.z);
}
FragmentShader of the FrameBuffer rendering:
#version 330 core
in vec2 fuv;
out vec4 color;
uniform sampler2D tex;
uniform sampler2D depth;
void main(){
vec4 d = texture2D(depth, fuv);
gl_FragDepth = d.a;
vec4 c = texture2D(tex,fuv);
if(c.a<0.1){
discard;
}
color = c;
//color = vec4(texture2D(depth, fuv).zzz,1.0);
//color.a = 0.8;
//color = vec4(1,0,0,0.5);
}
The red "Mesh" is behind the brown surface, but its borders still appear. thats the problem
The problem might come from the limited precision of the depth buffer. Basically, the range between near and farplane has to be represented by the depth-buffer. In your case, the depth-buffer has 8 bit, thus there are only 256 different depth values that can be represented. When two objects are closer together than this, they will be mapped to the same value in the depth buffer.
To overcome this, you can try to increase the precision of the depth buffer, for example, by using
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL);
Side-note: I'm not sure why the depth texture has four channels. If you don't need them, I would change this to a one channel format.