I've started messing around with textures in opengl, and when rendering my first texture, I saw a black screen. Then I realized that the screen in't black, rather the texture was very dim. Why is this happening? Here is the code:
Texture class (.cpp):
Texture::Texture(void* data, unsigned int width, unsigned int height)
:texture(0), curslot(32), width(width), height(height)
{
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, this->width, this->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0);
}
Texture::~Texture(){
glDeleteTextures(1, &texture);
}
void Texture::bind(unsigned char slot){
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, texture);
curslot = slot;
}
Texture class declaration (if you need it):
class Texture{
private:
unsigned int texture;
unsigned char curslot;
unsigned int width;
unsigned int height;
public:
Texture(void* data, unsigned int width, unsigned int height);
~Texture();
void bind(unsigned char slot=0);
};
Shaders:
Vertex Shader:
#version 330 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texpos;
out vec2 texCoord;
void main(){
gl_Position = position;
texCoord = texpos;
}
Fragment Shader:
#version 330 core
layout(location=0) out vec4 color;
uniform sampler2D u_Texture;
in vec2 texCoord;
void main(){
vec4 texColor = texture(u_Texture, texCoord);
color = texColor;
}
Renderer class declaration (you won't need the implementation although if you want it, I'll be happy to add it, just ask):
class Renderer{
private:
Renderer(){}
public:
static Renderer* renderer;
Renderer(const Renderer& r) = delete;
void draw(VertexArray* va, IndexBuffer* ib, Shader* shader, void (*uniformCallback)(Shader*, void*), void* uniformCallbackParams) const; //Fourth parameter is a function pointer that executes every time the draw function is called. It enables the user of the class to declare their uniforms. First three parameters are abstracted classes. Final parameter is a void pointer that is passed into the uniform function
};
Main Application (simplified):
typedef struct{
float x;
float y;
float texCoord_x;
float texCoord_y;
} vertex_t;
static GLFWwindow* window;
static void uniformCallback(Shader* program, void* params){
program->useUniform1i("u_Texture", 0); //Setting the sampler2D uniform for the texture slot
}
int main(){
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(500, 500, "OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
glewInit();
VertexArray* va = new VertexArray(); //Abstracted vertex array
va->bind();
VertexBuffer* vb = new VertexBuffer(); //Abstracted vertex buffer
IndexBuffer* ib = new IndexBuffer(); //Abstracted index buffer
unsigned char t[16] = { //Texture pixels, RGBA form. Made this simple 'image' just for testing purposes
1, 0, 0, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 0, 0, 1
};
Texture* texture = new Texture(t, 2, 2); //Texture class (abstracted)
texture->bind();
Shader* program = new Shader(2, "vs.glsl", "fs.glsl"); //Abstracted shader
vertex_t data[4] = {
{-0.5, 0.5, 0.0f, 1.0f},
{ 0.5, 0.5, 1.0f, 1.0f},
{-0.5, -0.5, 0.0f, 0.0f},
{ 0.5, -0.5, 1.0f, 0.0f}
};
unsigned int indicies[6] = {
0, 1, 2,
1, 2, 3
};
vb->setBufferData(data, 4*sizeof(vertex_t));
ib->setBufferData(indicies, 6);
vb->bind();
ib->bind();
va->addAttrib(GL_FLOAT, 2); //equivalent of glEnableAttribArray and glVertexAttribPointer
va->addAttrib(GL_FLOAT, 2);
while(!glfwWindowShouldClose(window)){
glClear(GL_COLOR_BUFFER_BIT);
Renderer::renderer->draw(va, ib, program, uniformCallback, NULL); //Refer to renderer class declaration
glfwSwapBuffers(window);
glfwPollEvents();
}
//Clean-up code (freeing pointers, etc.)
glfwTerminate();
return 0;
}
Each color channel of the texture is coded in a byte. Hence, the color values are in range [0, 255]. Change the values of t[16]:
unsigned char t[16] = {
255, 0, 0, 255,
255, 255, 255, 255,
255, 255, 255, 255,
255, 0, 0, 255
};
Note that when specifying the two-dimensional texture image, the data type of the pixel data is specified by GL_UNSIGNED_BYTE:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, this->width, this->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
Related
I get a seemingly random color when I try to load a 16x16 png as Texture instad of the texture.
The Colors are alomst always something like light blue, dark blue, red, pink.
Here is the texture if it helps
DirtTexture
here is the code of the Texture class
TextureClass::TextureClass(const std::string& path)
{
int w, h, bpp;
stbi_set_flip_vertically_on_load(1);
unsigned char* data = stbi_load(path.c_str(), &w, &h, &bpp, 0);
glGenTextures(1, &ID);
glBindTexture(GL_TEXTURE_2D, ID);
glEnable(GL_TEXTURE_2D);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, &data);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
if (data)
{
stbi_image_free(data);
}
}
void TextureClass::Bind(unsigned int slot) const
{
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, ID);
}
void TextureClass::Delete()
{
glDeleteTextures(1, &ID);
}
here is the code of my vertex and fragment shader
#shader vertex
#version 330 core
layout (location = 0) in vec2 aPosition;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
out vec3 color;
void main()
{
gl_Position = vec4(aPosition.x, aPosition.y, 1.0, 1.0);
texCoord = aTexCoord;
color = vec3(1.0, 0.0, 1.0);
};
#shader fragment
#version 330 core
out vec4 FragColor;
in vec2 texCoord;
uniform sampler2D tex0;
void main()
{
FragColor = texture(tex0, texCoord);
}
Here is my main part
#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <string>
#include "VAO.h"
#include "VBO.h"
#include "IBO.h"
#include "ShaderClass.h"
#include "Texture.h"
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
static ShaderProgramSource ParseShader(const std::string& filepath)
{
std::ifstream stream(filepath);
enum class ShaderType
{
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
std::string line;
std::stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line))
{
if (line.find("#shader") != std::string::npos)
{
if (line.find("vertex") != std::string::npos)
type = ShaderType::VERTEX;
else if (line.find("fragment") != std::string::npos)
type = ShaderType::FRAGMENT;
}
else
{
ss[(int)type] << line << '\n';
}
}
return{ ss[0].str(), ss[1].str() };
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 800, "pp", NULL, NULL);
if (window == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
gladLoadGL();
glViewport(0, 0, 800, 800);
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.0f, 0.0f,//unten Links
0.5f, -0.5f, 1.0f, 0.0f,//untenRechts
0.5f, 0.5f, 1.0f, 1.0f,//open Rechts
-0.5f, 0.5f, 0.0f, 1.0f,//open links
};
unsigned int indices[] =
{
0,1,2,
2,3,0,
};
ShaderProgramSource source = ParseShader("Basic.shader");
const char* vertexShader = source.VertexSource.c_str();
const char* fragmentShader = source.FragmentSource.c_str();
Shader ShaderProgramm(vertexShader, fragmentShader);
TextureClass DirtTexture("Dirt.png");
DirtTexture.Bind(0);
int Loc1 = ShaderProgramm.GetUniformId("tex0");
glUniform1i(Loc1, 0);
VAO vao;
VBO vbo(vertices, sizeof(vertices));
IBO ibo(indices, sizeof(indices));
vbo.Bind();
vao.Bind();
ibo.Bind();
glEnableVertexAttribArray(0);
vao.LinkAttrib(vbo, 0, 2, GL_FLOAT, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
vao.LinkAttrib(vbo, 1, 2, GL_FLOAT, 4 * sizeof(float), (void*)1);
//Main Loop
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
glUniform1i(Loc1, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
DirtTexture.Delete();
ShaderProgramm.Delete();
vbo.Delete();
vao.Delete();
ibo.Delete();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
And here is my VAO class
#pragma once
#include<glad/glad.h>
#include "VAO.h"
VAO::VAO()
{
glGenVertexArrays(1, &ID);
glBindVertexArray(ID);
}
void VAO::enable()
{
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
}
void VAO::LinkAttrib(VBO& VBO, GLuint layout, GLuint numComponents, GLenum type, GLsizeiptr stride, void* offset)
{
VBO.Bind();
glVertexAttribPointer(layout, numComponents, type, GL_FALSE, stride, offset);
glEnableVertexAttribArray(layout);
VBO.Unbind();
}
void VAO::Bind()
{
glBindVertexArray(ID);
}
void VAO::Delete()
{
glDeleteVertexArrays(1, &ID);
}
It's not clear how your VAO class works internally, but this looks really broken:
vao.LinkAttrib(vbo, 1, 2, GL_FLOAT, 4 * sizeof(float), (void*)1);
glVertexAttribPointer uses the offset in bytes, so the correct offset matching your vertex data is 2*sizeof(GLfloat), not 1.
I bind a texture to both a texture unit and a image unit, write to it via imageStore() in the compute shader, and sample it with a sampler2D in the fragment shader.
This works when the pixel format is floating point, but stops working with integers. glGetError() yields nothing.
glew and glm are used; should be irrelevant to the problem though.
main.cpp:
constexpr glm::vec2 TEX_DIM = { 2048.0f, 2048.0f / ASPECT_RATIO };
constexpr int LOCAL_WORKGROUP_SIZE = 32;
// After setting up vbo, etc //////////
// Texture
const unsigned int texSlot = 0;
unsigned int texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + texSlot);
glBindTexture(GL_TEXTURE_2D, texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, int(TEX_DIM.x), int(TEX_DIM.y), 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
// Binding to image unit
const unsigned int imageSlot = 0;
glBindImageTexture(imageSlot, texId, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R8);
// Shaders
unsigned int computeShader;
unsigned int graphicsShader;
// After creating shaders //////////
// Graphics shader
glUseProgram(graphicsShader);
glUniform1i(glGetUniformLocation(graphicsShader, "uTexture"), texSlot);
glUniformMatrix4fv(glGetUniformLocation(graphicsShader, "uMVP"), 1, GL_FALSE, &mvp);
auto mvp = glm::ortho(0.0f, (float)WINDOW_WIDTH, 0.0f, (float)WINDOW_HEIGHT, -1.0f, 1.0f);
// Compute shader
glUseProgram(computeShader);
glUniform1i(glGetUniformLocation(computeShader, "uImage"), imageSlot);
// After validating shaders //////////
while (true)
{
// Compute
glUseProgram(computeShader);
glDispatchCompute(TEX_DIM.x / LOCAL_WORKGROUP_SIZE, TEX_DIM.y / LOCAL_WORKGROUP_SIZE, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
// Draw
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(graphicsShader);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
glfwSwapBuffers(window);
}
Compute Shader:
# version 430 core
layout(local_size_x = 32, local_size_y = 32) in;
layout(r8) uniform image2D uImage;
void main()
{
// Writing all to red, for testing purpose
imageStore(uImage, ivec2(gl_GlobalInvocationID.xy), vec4(1.0, 0.0, 0.0, 0.0));
}
Vertex Shader:
# version 430 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 texCoord;
out vec2 vTexCoord;
uniform mat4 uMVP;
void main()
{
gl_Position = uMVP * vec4(position, 0.0, 1.0);
vTexCoord = texCoord;
}
Fragment Shader:
# version 430 core
in vec2 vTexCoord;
out vec4 color;
uniform sampler2D uTexture;
void main()
{
color = vec4(
texture(uTexture, vTexCoord).x,
0.0, 0.0, 1.0
);
}
Below is my attempt to convert the minimal program to be using integers instead; gives me a black screen but no errors otherwize.
main.cpp:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, int(TEX_DIM.x), int(TEX_DIM.y), 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr);
glBindImageTexture(imageSlot, texId, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R8UI);
Compute Shader:
layout(r8ui) uniform uimage2D uImage;
void main()
{
// Writing all to red, for testing purpose
imageStore(uImage, ivec2(gl_GlobalInvocationID.xy), uvec4(255, 0, 0, 0));
}
Fragment Shader:
uniform usampler2D uTexture;
void main()
{
color = vec4(
float(texture(uTexture, vTexCoord).x) / 256.0,
0.0, 0.0, 1.0
);
}
I've thought about GL_R8UI being incompatable but the wiki says both GL_R8 and GL_R8UI are fine to use.
I'm trying to render an video through OpenGL in GTK3 on linux. These Vertex and Fragment shaders were used with succes on QT. Actually all the opengl function calls are the same from working examples on Qt.
Anyone knows why? Is it possible that GLEW coordinates are different from coordinates in QT OpenGL?
The video is in YUV420P format, so that's why the fragment shader does matrix multiplication. Is it possible that my fragment coordinates are wrong?
Anyways, here's the video:
My Vertex Shader:
#version 130
attribute vec4 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;
void main(void)
{
gl_Position = vertexIn;
textureOut = textureIn;
}
My Fragment Shader:
#version 130
varying vec2 textureOut;
uniform sampler2D tex_y;
uniform sampler2D tex_u;
uniform sampler2D tex_v;
void main(void)
{
vec3 yuv;
vec3 rgb;
yuv.x = texture2D(tex_y, textureOut).r;
yuv.y = texture2D(tex_u, textureOut).r - 0.5;
yuv.z = texture2D(tex_v, textureOut).r - 0.5;
rgb = mat3(1.0, 1.0, 1.0,
0.0, -0.39465, 2.03211,
1.13983, -0.58060, 0.0) * yuv;
gl_FragColor = vec4(rgb, 1.0);
}
My rendering code:
static const GLfloat ver[] = {
-1.0f,-1.0f,
1.0f,-1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
};
static const GLfloat tex[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
void OpenGLArea::init()
{
std::cout << "OpenGLArea init" << std::endl;
set_size_request(640, 360);
Singleton::instance()->getStream("cam1").mediaStream->ffmpegDecoder->setVideoReceiver(this);
}
void OpenGLArea::receiveVideo(unsigned char **videoBuffer, int frameWidth, int frameHeight)
{
this->frameWidth = frameWidth;
this->frameHeight = frameHeight;
//Before first render, datas pointer isn't even created yet
if (!firstFrameReceived)
{
buffer[0] = new unsigned char[frameWidth * frameHeight]; //Y
buffer[1] = new unsigned char[frameWidth * frameHeight / 4]; //U
buffer[2] = new unsigned char[frameWidth * frameHeight / 4]; //V
firstFrameReceived = true;
}
else
{
memcpy(buffer[0], videoBuffer[0], frameWidth * frameHeight);
memcpy(buffer[1], videoBuffer[1], frameWidth * frameHeight / 4);
memcpy(buffer[2], videoBuffer[2], frameWidth * frameHeight / 4);
}
//glDraw();
}
void OpenGLArea::glInit()
{
int frameWidth = 640;
int frameHeight = 360;
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
Shader vertex_shader(ShaderType::Vertex, "vertex.shader");
Shader fragment_shader(ShaderType::Fragment, "fragment.shader");
program = new Program();
program->attach_shader(vertex_shader);
program->attach_shader(fragment_shader);
program->link();
glGenTextures(3, texs);//TODO: delete texture
//Y
glBindTexture(GL_TEXTURE_2D, texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth, frameHeight, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//U
glBindTexture(GL_TEXTURE_2D, texs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth / 2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//V
glBindTexture(GL_TEXTURE_2D, texs[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth / 2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void OpenGLArea::glDraw()
{
program->use();
glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
glEnableVertexAttribArray(A_VER);
glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
glEnableVertexAttribArray(T_VER);
unis[0] = glGetAttribLocation(program->get_id(), "tex_y");
unis[1] = glGetAttribLocation(program->get_id(), "tex_u");
unis[2] = glGetAttribLocation(program->get_id(), "tex_v");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texs[0]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth, frameHeight, GL_RED, GL_UNSIGNED_BYTE, buffer[0]);
glUniform1i(unis[0], 0);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texs[1]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth / 2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, buffer[1]);
glUniform1i(unis[1], 1);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, texs[2]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth / 2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, buffer[2]);
glUniform1i(unis[2], 2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
class GLWindow : public Gtk::Window
{
public:
GLWindow()
{
vbox = new Gtk::VBox;
drawing_area = new OpenGLArea();
vbox->pack_start(*drawing_area, true, true);
add(*vbox);
}
private:
Gtk::Button *button;
Gtk::VBox *vbox;
OpenGLArea *drawing_area;
};
Also, I'm only getting image updates when I resize or refocus on the screen. It's possible that I'm forgetting to call some function when the video is updated. Anyone knows which function is this?
ps: OpenGLArea is subclass of Gtk::DrawingArea
UPDATE:
I just noticed that in the lines
unis[0] = glGetAttribLocation(program->get_id(), "tex_y");
unis[1] = glGetAttribLocation(program->get_id(), "tex_u");
unis[2] = glGetAttribLocation(program->get_id(), "tex_v");
unis[i] always have the same value: 4294967295, so glGetAttribLocation isn't returning anything
GLEW is a library that is used for retrieving the function pointers to OpenGL functions. It's needed for OGL version > 1.1.
So, don't think of Glew as the culprit of your vertices issue. If you need to change the order of vertices is due to Winding order.
The order also may be the cause of drawing a texture upside-down.
glGetAttribLocation is used for attributes. In your VS these are vertexIn and textureIn.
For uniforms (your tex_XXX) you must use glGetUniformLocation
For the resizing issue, this question may be useful.
In short, you must connect a callback for the "configure-event" and use glViewport
I'm fairly new to OpenGL and have run into a problem that I can't seem to crack. I'm trying to add a simple 2D texture to a triangle, the texture seems to be loading fine but it's getting displayed grainy and in black and white.
texture
result
Here's my related code:
main.cxx
#include <iostream>
#include "display.h"
#include "shader.h"
#include "texture.h"
#include "mesh.h"
#include <glm/glm.hpp>
#include <GLFW/glfw3.h>
int main()
{
Display display(800, 600, "project2");
Vertex vertices[] = {
Vertex(glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec2(0.0f, 0.0f)),
Vertex(glm::vec3(0.5f, -0.5f, 0.0f), glm::vec2(1.0f, 0.0f)),
Vertex(glm::vec3(0.0f, 0.5f, 0.0f), glm::vec2(0.5f, 1.0f)),
};
Mesh mesh(vertices, sizeof(vertices)/sizeof(vertices[0]));
Shader shader("./shaders/shader");
Texture texture("./textures/container.jpg");
while (!display.IsClosed())
{
display.ProcessInput();
display.Clear(0.0f, 0.15f, 0.3f, 1.0f);
texture.Bind(0);
shader.Bind();
mesh.Draw();
display.Update();
}
return 0;
}
texture.cxx
#include "texture.h"
Texture::Texture(const std::string &filePath)
{
int width, height, numComponents;
unsigned char* imageData = stbi_load(filePath.c_str(), &width, &height, &numComponents, 4);
if (!imageData) {
std::cerr << "Failed to load texture: " << filePath << std::endl;
return;
}
stbi_set_flip_vertically_on_load(true);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
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, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(imageData);
}
Texture::~Texture()
{
glDeleteTextures(1, &texture);
}
void Texture::Bind(unsigned int unit)
{
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, texture);
}
fragment shader
#version 330 core
out vec4 FragColor;
uniform sampler2D diffuse;
in vec2 texCoord0;
void main() {
FragColor = texture(diffuse, texCoord0);
}
vertex shader
#version 330 core
layout (location=0) in vec3 position;
layout (location=1) in vec2 texCoord;
out vec2 texCoord0;
void main() {
gl_Position = vec4(position, 1.0);
texCoord0 = texCoord;
}
I had textures working before in another project and my code looks almost identical, if anyone could help me out that would be much appreciated.
When a RGB image with 3 color channels is loaded to a texture object, then GL_UNPACK_ALIGNMENT has to be set to 1:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
GL_UNSIGNED_BYTE, imageData);
GL_UNPACK_ALIGNMENT specifies the alignment requirements for the start of each pixel row in memory. By default GL_UNPACK_ALIGNMENT is set to 4.
This means the start of each line of the image is assumed to be aligned to an address which is a multiple of 4. Since the image data are tightly packed and each pixel has a size of 3 bytes, the alignment has to be changed.
To proper read the image the last parameter of stbi_load has to be 0 (since the jpg format provides 3 color channesl) or 3 (to force 3 color channels):
unsigned char* imageData = stbi_load(filePath.c_str(),
&width, &height, &numComponents, 0);
stbi_load can be forced to generate an image with 4 color channels, by explicitly pass 4 to the last parameter:
See stb_image.h:
Basic usage (see HDR discussion below for HDR usage):
int x,y,n;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// ... process data if not NULL ...
// ... x = width, y = height, n = # 8-bit components per pixel ...
// ... replace '0' with '1'..'4' to force that many components per pixel
// ... but 'n' will always be the number that it would have been if you said 0
stbi_image_free(data)
In this case the format parameter has to be changed from GL_RGB to GL_RGBA when loading the image:
unsigned char* imageData = stbi_load(filePath.c_str(),
&width, &height, &numComponents, 0);
// [...]
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, imageData);
im trying to load a texture to an object in Modern NVIDIA openGL
i have a square that i want to load the texture to , i use stb_image as my loader
here is the main code :
float position1[16]{
0.0f , 0.0f, 0.0f , 0.0f,
0.8f , 0.0f, 1.0f , 0.0f,
0.0f , 0.8f, 0.0f , 1.0f,
0.8f , 0.8f, 1.0f , 1.0f ,
};
unsigned int Indexs[6]{
0 , 1 , 2 ,
2 , 1 , 3
};
VertexBuffer buffer(position1, sizeof(position1));
IndexBuffer Index(Indexs, 6);
Texture Tex("Smile.png");
Tex.Bind();
buffer.Bind();
Index.Bind();
Shader BasicShader("basic.shader");
Renderer renderer;
glfwSwapInterval(0);
//! MAIN LOOP !!!
BasicShader.Uniform1i("u_Texture ", 0);
BasicShader.Uniform4f("u_Color", 0.0f, 1.0f, 1.0f, 1.0f );
while (!glfwWindowShouldClose(window) )
{
//! RENDER
renderer.Clear();
glEnable(GL_TEXTURE_2D);
BasicShader.Uniform1i("u_Texture ", 0);
BasicShader.Uniform4f("u_Color", 0.f, 1.0f, 1.0f, 1.0f);
Tex.Bind();
BasicShader.Bind();
renderer.Draw(buffer, Index, Layout::D4Vertex, BasicShader);
//! FRAME
glfwSwapBuffers(window);
//! EVENTS
glfwPollEvents();
}
glfwTerminate();
return 0;
};
here is my shader its of course being compiled the right way as expected with no errors :
#shader vertex
#version 410 core
layout(location = 0 ) in vec4 position;
layout(location = 1) in vec2 texCoord;
out vec2 v_TexCoord;
void main()
{
gl_Position = position;
v_TexCoord = texCoord;
};
#shader fragment
#version 410 core
layout(location = 0 ) out vec4 color;
uniform vec4 u_Color;
uniform sampler2D u_Texture;
in vec2 v_TexCoord;
void main()
{
vec4 texColor = texture2D(u_Texture, v_TexCoord);
color = texColor;
};
here is my draw call :
void Renderer::Draw(VertexBuffer& vb, IndexBuffer& iv,
Layout layout,Shader& shader)
{
BufferLayout bufferLayout;
shader.Bind();
vb.Bind();
iv.Bind();
bufferLayout.SetLayout(layout);
glDrawElements(GL_TRIANGLES, iv.GetCount(), GL_UNSIGNED_INT, nullptr);
}
this is how i set the buffer layout:
void BufferLayout::SetLayout(Layout l)
{
switch (l) {
case Layout::NONE :
glEnableVertexAttribArray(0);
case Layout::D2Vertex :
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) *
2,0);
case Layout::D4Vertex:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) *
4,0);
}
}
here is my texture class (handels loading parameters and binding ) :
#include "Texture.h"
#include "stb_image.h";
#include "Renderer.h"
Texture::Texture(string path)
: m_RendererID(0) , m_BPP(0) , m_Height (0) , m_Width (0),
m_LocalBuffer(nullptr) , m_FilePath(path)
{
stbi_set_flip_vertically_on_load(1);
m_LocalBuffer = stbi_load(path.c_str(), &m_Width, &m_Height, &m_BPP, 4);
//seems like the image is there
glEnable(GL_TEXTURE_2D);
glGenTextures(1, & m_RendererID);
glBindTexture(GL_TEXTURE_2D, m_RendererID);
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);
GLenum temp = glGetError();
if (temp != GL_NO_ERROR) throw std::invalid_argument("OPENGL ERROR");
// I Get no erros
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, m_LocalBuffer);
}
Texture::~Texture()
{
glDeleteTextures(1, &m_RendererID);
}
void Texture::Bind(unsigned int slot)
{
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, m_RendererID);
}
void Texture::Unbind()
{
glBindTexture(GL_TEXTURE_2D, 0);
}
and my texture.h file :
#pragma once
#include "Renderer.h"
class Texture {
private :
unsigned int m_RendererID;
string m_FilePath;
unsigned char * m_LocalBuffer;
int m_Width, m_Height, m_BPP;
public:
Texture(string path);
~Texture();
void Bind(unsigned int slot = 0);
void Unbind();
inline int GetWidth()const { return m_Width; }
inline int GetHeight()const { return m_Height; }
};
basicaly im pretty sure the problem must be somewhere in the code i have posted and all the other code works as expected .
Can anyone spot the problem ?
The result should be a square with the texture "Smile.png" on it and i get a white texture . I do have the file "Smile.png" in my project directory and it seems to me like stb_image can find and load it .
*no erros from glGetError();
In the code sample, the setup code for attribut 1 (texCoord) is missing. For each attribute used by a shader, a buffer has to be bound, the attribute has to be enabled and the relation between attribute and shader has to be specified.
As said, this is done for attribute 0 but not for attribute 1. The code in the SetLayout method could look somehow like this:
//Attribute 0: uses first two floats
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
//Attribute 1: uses 3rd and 4th float
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(2 * sizeof(float)));