Any idea, why decoded YUV -> RGB(shader conversion) has that extra green edge on the right side?
Almost any 1080X1920 video seems to have this issue.
A screen recording of the issue is uploaded here https://imgur.com/a/JtUZq4h
Once I manually scale up the texture width, I can see it fills up to the viewport, but it would be nice if I could fix the actual cause. Is it some padding that's part of YUV colorspace? What else could it be?
My model is -1 to 1, filling the entire width
The texture coordinates are also 0 to 1 ratio
float vertices[] = {
-1.0, 1.0f, 0.0f, 0.0, // top left
1.0f, 1.0f, 1.0, 0.0, // top right
-1.0f, -1.0f, 0.0f, 1.0f, // bottom left
1.0f, -1.0f, 1.0f, 1.0f // bottom right
};
Fragment Shader
#version 330 core
in vec2 TexCoord;
out vec4 FragColor;
precision highp float;
uniform sampler2D textureY;
uniform sampler2D textureU;
uniform sampler2D textureV;
uniform float alpha;
uniform vec2 texScale;
void main()
{
float y = texture(textureY, TexCoord / texScale).r;
float u = texture(textureU, TexCoord / texScale).r - 0.5;
float v = texture(textureV, TexCoord / texScale).r - 0.5;
vec3 rgb;
//yuv - 709
rgb.r = clamp(y + (1.402 * v), 0, 255);
rgb.g = clamp(y - (0.2126 * 1.5748 / 0.7152) * u - (0.0722 * 1.8556 / 0.7152) * v, 0, 255);
rgb.b = clamp(y + (1.8556 * u), 0,255);
FragColor = vec4(rgb, 1.0);
}
Texture Class
class VideoTexture {
public:
VideoTexture(Decoder *dec) : decoder(dec) {
glGenTextures(1, &texture1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, texture1);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, decoder->frameQueue.first().linesize[0], decoder->frameQueue.first().height, 0, format, GL_UNSIGNED_BYTE, 0);
glGenerateMipmap(GL_TEXTURE_2D);
glGenTextures(1, &texture2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, texture2);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, decoder->frameQueue.first().linesize[1], decoder->frameQueue.first().height / 2, 0, format, GL_UNSIGNED_BYTE, 0);
glGenerateMipmap(GL_TEXTURE_2D);
glGenTextures(1, &texture3);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, texture3);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, decoder->frameQueue.first().linesize[2], decoder->frameQueue.first().height / 2, 0, format, GL_UNSIGNED_BYTE, 0);
glGenerateMipmap(GL_TEXTURE_2D);
}
void Render(Shader *shader, Gui *gui) {
if (decoder->frameQueue.isEmpty()) {
return;
}
glActiveTexture(GL_TEXTURE0);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, decoder->frameQueue.first().linesize[0], decoder->frameQueue.first().height, format, GL_UNSIGNED_BYTE, decoder->frameQueue.at(currentFrame).data[0]);
glBindTexture(GL_TEXTURE_2D, texture1);
shader->setInt("textureY", 0);
glActiveTexture(GL_TEXTURE1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, decoder->frameQueue.first().linesize[1], decoder->frameQueue.first().height / 2, format, GL_UNSIGNED_BYTE, decoder->frameQueue.at(currentFrame).data[1]);
glBindTexture(GL_TEXTURE_2D, texture2);
shader->setInt("textureU", 1);
glActiveTexture(GL_TEXTURE2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, decoder->frameQueue.first().linesize[2], decoder->frameQueue.first().height / 2, format, GL_UNSIGNED_BYTE, decoder->frameQueue.at(currentFrame).data[2]);
glBindTexture(GL_TEXTURE_2D, texture3);
shader->setInt("textureV", 2);
}
~VideoTexture() {
printf("\nVideo texture destructor");
glDeleteTextures(1, &texture1);
glDeleteTextures(1, &texture2);
glDeleteTextures(1, &texture3);
}
private:
GLuint texture1;
GLuint texture2;
GLuint texture3;
GLint internalFormat = GL_RG8;
GLint format = GL_RED;
int currentFrame = 0;
Decoder *decoder;
}
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 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.
I'm trying to load an image using FreeImage and then generate an OpenGL texture. It loads the image and generates a texture, but there's an issue with the colors.
Here's the original image:
and here's the result:
Texture loading code:
void TextureManager::LoadTexture(std::string id, std::string filePath){
Texture tex;
tex.TextureId = 0;
FIBITMAP* image = FreeImage_Load(FreeImage_GetFileType(filePath.c_str(), 0), filePath.c_str());
if (FreeImage_GetBPP(image) != 32) {
image = FreeImage_ConvertTo32Bits(image);
}
FreeImage_FlipVertical(image);
tex.Width = FreeImage_GetWidth(image);
tex.Height = FreeImage_GetHeight(image);
glGenTextures(1, &tex.TextureId);
glBindTexture(GL_TEXTURE_2D, tex.TextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,tex.Width, tex.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(image));
AddTextureToMap(id, tex);
FreeImage_Unload(image);
}
Here's the code that's drawing it:
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, TextureManager.TextureMap[textureSelector].TextureId);
glBegin(GL_TRIANGLES);
glTexCoord2d(0, 0);
glVertex3f(-0.75, 0.75, 0);//top left
glTexCoord2d(1, 0);
glVertex3f(0.75, 0.75, 0);//top right
glTexCoord2d(0, 1);
glVertex3f(-0.75, -0.75, 0);//bottom left
glTexCoord2d(1, 0);
glVertex3f(0.75, 0.75, 0);//top right
glTexCoord2d(1, 1);
glVertex3f(0.75, -0.75, 0);//bottom right
glTexCoord2d(0, 1);
glVertex3f(-0.75, -0.75, 0);//bottom left
glEnd();
glFinish();
I'm pretty sure it's an issue with the internal format in glTexImage2D, but I'm not sure which format I'd use if that's the case. My question is: Is it the format, if so, what should I use; or is there another issue that's causing this?
Try to use this instead
The difference is because many image formats use reverse byte order, and you should use GL_BGR_EXT or GL_BGRA_EXT image formats instead GL_RGB or GL_RGBA
void TextureManager::LoadTexture(std::string id, std::string filePath){
Texture tex;
tex.TextureId = 0;
FIBITMAP* image = FreeImage_Load(FreeImage_GetFileType(filePath.c_str(), 0), filePath.c_str());
if (FreeImage_GetBPP(image) != 32) {
image = FreeImage_ConvertTo32Bits(image);
}
FreeImage_FlipVertical(image);
tex.Width = FreeImage_GetWidth(image);
tex.Height = FreeImage_GetHeight(image);
glGenTextures(1, &tex.TextureId);
glBindTexture(GL_TEXTURE_2D, tex.TextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,tex.Width, tex.Height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(image));
AddTextureToMap(id, tex);
FreeImage_Unload(image);
}
If the RGBA order is not correct, you can change the color in fragment shader like
#version 130
uniform sampler2D tex;
in vec2 texCoordsVarying;
out vec4 color;
void main() {
vec4 c2 = texture(tex, texCoordsVarying);
color = vec4(c2.g, c2.b, c2.a, c2.r);
}
When compiled with vs2010, the fragment shader works, but when I compiled and run in vs 2013, it's grey.
My fragment shader converts the yuv texture into rgb
Below is my fragment code
const char *FProgram =
"uniform sampler2D Ytex;\n"
"uniform sampler2D Utex;\n"
"uniform sampler2D Vtex;\n"
"void main(void) {\n"
" vec4 c = vec4((texture2D(Ytex, gl_TexCoord[0]).r - 16./255.) * 1.164);\n"
" vec4 U = vec4(texture2D(Utex, gl_TexCoord[0]).r - 128./255.);\n"
" vec4 V = vec4(texture2D(Vtex, gl_TexCoord[0]).r - 128./255.);\n"
" c += V * vec4(1.596, -0.813, 0, 0);\n"
" c += U * vec4(0, -0.392, 2.017, 0);\n"
" c.a = 1.0;\n"
" gl_FragColor = c;\n"
"}\n";
glClearColor(0, 0, 0, 0);
PHandle = glCreateProgram();
FSHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(FSHandle, 1, &FProgram, NULL);
glCompileShader(FSHandle);
glAttachShader(PHandle, FSHandle);
glLinkProgram(PHandle);
glUseProgram(PHandle);
glDeleteProgram(PHandle);
glDeleteProgram(FSHandle);
This is my texture code, I receive linesize and yuv frame data from ffmpeg and make into texture. Everything works fine in VS 2010 computer, but when compiled and run in vs2013 computer, it is grey (black n white), no colour
/* Select texture unit 1 as the active unit and bind the U texture. */
glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize1);
glActiveTexture(GL_TEXTURE1);
i = glGetUniformLocation(PHandle, "Utex");
glUniform1i(i, 1); /* Bind Utex to texture unit 1 */
glBindTexture(GL_TEXTURE_2D, 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width / 2, height / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
/* Select texture unit 2 as the active unit and bind the V texture. */
glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize2);
glActiveTexture(GL_TEXTURE2);
i = glGetUniformLocation(PHandle, "Vtex");
glUniform1i(i, 2); /* Bind Vtext to texture unit 2 */
glBindTexture(GL_TEXTURE_2D, 2);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width / 2, height / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame2);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
/* Select texture unit 0 as the active unit and bind the Y texture. */
glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize0);
glActiveTexture(GL_TEXTURE0);
i = glGetUniformLocation(PHandle, "Ytex");
glUniform1i(i, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glClear(GL_COLOR_BUFFER_BIT);
/* Draw image (again and again). */
glBegin(GL_QUADS);
glTexCoord2i(0, 0);
glVertex2i(-w / 2, h / 2);
glTexCoord2i(1, 0);
glVertex2i(w / 2, h / 2);
glTexCoord2i(1, 1);
glVertex2i(w / 2, -h / 2);
glTexCoord2i(0, 1);
glVertex2i(-w / 2, -h / 2);
glEnd();
I am writing a deferred shader and as one of the first steps, to get familiar with GLSL and using shaders and the framebuffer I am trying to change the color of a mesh through a shader.
I have it linked to one of the buffers by calling glDrawBuffers with an array that holds the attachement and then binding the texture to my framebuffer:
glReadBuffer(GL_NONE);
GLint color_loc = glGetFragDataLocation(pass_prog,"out_Color");
GLenum draws [1];
draws[color_loc] = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, draws);
glBindTexture(GL_TEXTURE_2D, diffuseTexture);
glFramebufferTexture(GL_FRAMEBUFFER, draws[color_loc], diffuseTexture, 0);
I have an out_Color variable in my fragment shader (otherwise it wouldn't even compile), but I can't manage to change the color of the mesh by setting it through that variable inside the shader.
Does anyone has any idea why and could explain that to me?
Thanks
Edit:
My shaders:
Vertex Shader
#version 330
uniform mat4x4 u_Model;
uniform mat4x4 u_View;
uniform mat4x4 u_Persp;
uniform mat4x4 u_InvTrans;
in vec3 Position;
in vec3 Normal;
out vec3 fs_Normal;
out vec4 fs_Position;
void main(void) {
fs_Normal = (u_InvTrans*vec4(Normal,0.0f)).xyz;
vec4 world = u_Model * vec4(Position, 1.0);
vec4 camera = u_View * world;
fs_Position = camera;
gl_Position = u_Persp * camera;
}
Fragment shader
#version 330
uniform float u_Far;
in vec3 fs_Normal;
in vec4 fs_Position;
out vec4 out_Normal;
out vec4 out_Position;
out vec4 out_Color;
void main(void)
{
out_Normal = vec4(normalize(fs_Normal),0.0f);
out_Position = vec4(fs_Position.xyz,1.0f); //Tuck position into 0 1 range
out_Color = vec4(1.0f, 0.0f, 0.0f, 1.0f);//first three diffuse, last specular
}
And I am not doing a deferred shader in order to learn GLSL. I am learning GLSL in order to make
a deferred shader. =)
More source code from setting up the textures:
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &depthTexture);
glGenTextures(1, &normalTexture);
glGenTextures(1, &positionTexture);
glGenTextures(1, &diffuseTexture);
//DEPTH TEXTURE
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
//NORMAL TEXTURE
glBindTexture(GL_TEXTURE_2D, normalTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F , w, h, 0, GL_RGBA, GL_FLOAT,0);
//POSITION TEXTURE
glBindTexture(GL_TEXTURE_2D, positionTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F , w, h, 0, GL_RGBA, GL_FLOAT,0);
//DIFFUSE TEXTURE
glBindTexture(GL_TEXTURE_2D, diffuseTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F , w, h, 0, GL_RGBA, GL_FLOAT,0);
//create a framebuffer object
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
//Instruct openGL that we won't bind a color texture with the currently binded FBO
glReadBuffer(GL_NONE);
GLint normal_loc = glGetFragDataLocation(pass_prog,"out_Normal");
GLint position_loc = glGetFragDataLocation(pass_prog,"out_Position");
GLint color_loc = glGetFragDataLocation(pass_prog,"out_Color");
GLenum draws [3];
draws[normal_loc] = GL_COLOR_ATTACHMENT0;
draws[position_loc] = GL_COLOR_ATTACHMENT1;
draws[color_loc] = GL_COLOR_ATTACHMENT2;
glDrawBuffers(3, draws);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0);
glBindTexture(GL_TEXTURE_2D, normalTexture);
glFramebufferTexture(GL_FRAMEBUFFER, draws[normal_loc], normalTexture, 0);
glBindTexture(GL_TEXTURE_2D, positionTexture);
glFramebufferTexture(GL_FRAMEBUFFER, draws[position_loc], positionTexture, 0);
glBindTexture(GL_TEXTURE_2D, diffuseTexture);
glFramebufferTexture(GL_FRAMEBUFFER, draws[color_loc], diffuseTexture, 0);
check FBO status
FBOstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(FBOstatus != GL_FRAMEBUFFER_COMPLETE) {
printf("GL_FRAMEBUFFER_COMPLETE failed, CANNOT use FBO\n");
checkFramebufferStatus(FBOstatus);
}
switch back to window-system-provided framebuffer
glClear(GL_DEPTH_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
Edit:
I solved it. Thanks.
You should do something like this. I assume that out_color is declared as out vec4 out_Color:
Compile shaders and attach them to the program.
glBindFragDataLocation(program, 0, "out_Color");
glLinkProgram(program);
glUseProgram(program);
GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 }
glDrawBuffers(1, drawBuffers);
Setup FBO.
The it should work, if it doesn't, post your fragment shader and more source code. By the way, i should also say that creating a deferred renderer to learn GLSL is not a good idea. There are easier ways to learn GLSL.