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)));
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 am using MS visual studio 2019 and just learning opengl in c++. I started learning from https://learnopengl.com and it showed many ways to load textures . I just used stb image for loading textures and here's the function for loading a texture :
static unsigned int loadTexture(char const* path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char* data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
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 << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
I tried loading it in a rectangle but somehow it doesn't seem to print properly on it. I'm stuck for a couple of hours and still couldn't find what mistake I've made.
here's the code for initializing the VAO and VBO:
inline void InitTextureBuffer(const char* img_filepath)
{
texture_shader.Bind();
tex_img_id = loadTexture(img_filepath);
glGenVertexArrays(1, &tex_VAO);
glGenBuffers(1, &tex_VBO);
glBindVertexArray(tex_VAO);
glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
texture_shader.Unbind();
}
and function to draw the rect :
inline void Draw_Rectangle_IMG(_Point _min, _Point _max)
{
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(tex_VAO);
texture_shader.Bind();
float vertices[] =
{
_min.x, _min.y, 0.0f, 0.0f ,
_max.x, _min.y, 0.0f, 1.0f ,
_max.x, _max.y, 1.0f, 1.0f ,
_min.x, _min.y, 0.0f, 0.0f ,
_max.x, _max.y, 1.0f, 1.0f ,
_min.x, _max.y, 1.0f, 0.0f ,
};
glBindTexture(GL_TEXTURE_2D, tex_img_id);
glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
texture_shader.Unbind();
}
the shaders I've used:
const std::string texture_shader_vs =
{
"#version 330 core\n"
"layout(location = 0) in vec2 aPos;\n"
"layout(location = 1) in vec2 aTexCoord;\n"
"\n"
"out vec2 TexCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos,0.0f, 1.0f);\n"
" TexCoord = aTexCoord;\n"
"}\n"
};
const std::string texture_shader_fs =
{
"#version 330 core\n"
"out vec4 FragColor;\n"
"\n"
"in vec2 TexCoord;\n"
"\n"
"// texture sampler\n"
"uniform sampler2D texture1;\n"
"\n"
"void main()\n"
"{\n"
" FragColor = texture(texture1, TexCoord);\n"
"}\n"
};
And the function where I did the calls:
_Point p1, p2;
p1 = _Point(-0.5f, -0.25f);
p2 = _Point(0.5f, 0.25f);
ogl.InitTextureBuffer("resources/textures/1.png");
while (!glfwWindowShouldClose(ogl.GetWindow()))
{
glClear(GL_COLOR_BUFFER_BIT);
ogl.Draw_Rectangle_IMG(p1, p2);
glfwSwapBuffers(ogl.GetWindow());
glfwPollEvents();
}
The texture i tried to print is :
but the result I get is
I can't seem to find the error .Any help would be appreciated. Thanks!
The association of the texture coordinates to the vertices is wrong. Change to:
float vertices[] =
{
_min.x, _min.y, 0.0f, 1.0f,
_max.x, _min.y, 1.0f, 1.0f,
_max.x, _max.y, 1.0f, 0.0f,
_min.x, _min.y, 0.0f, 1.0f,
_max.x, _max.y, 1.0f, 0.0f,
_min.x, _max.y, 0.0f, 0.0f,
};
By default OpenGL assumes that the start of each row of an image is aligned to 4 bytes.
This is because the GL_UNPACK_ALIGNMENT parameter by default is 4. When a RGB image with 3 color channels is loaded to a texture object and 3*width is not divisible by 4 this may cause a misalignment.
Change the alignment by setting the GL_UNPACK_ALIGNMENT to 1, before specifying the texture image with glTexImage2D:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
When you remove glGenerateMipmap(GL_TEXTURE_2D);, then you have to change the minifying function (GL_TEXTURE_MIN_FILTER) as well. Since the filter is GL_LINEAR_MIPMAP_LINEAR, the texture would be "Mipmap Incomplete" if you do not change the minimize function to GL_NEAREST or GL_LINEAR.
Hello I've got weird problem with my code, i've been looking for some time on stack and found no answer, there was few similar problems, but they didn't solve anything.
int createTexture(const char* path) {
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
int width, height, nrChannels;
unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0);
int colorMode = nrChannels == 3 ? GL_RGB : GL_RGBA;
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, colorMode, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
} else {
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
return texture;
}
Here i have function loading texture, I choose GL_RGB or GL_RGBA depending on number of channels. I've good results of 3 and 4 channels depending on jpg/png image i use. Anyways i have white background, ( it was black before i edited it in GIMP )
// set the texture wrapping/filtering options (on currently bound 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);
// load and create a texture
// -------------------------
unsigned int texture1 = createTexture("brick.jpg");
unsigned int texture2 = createTexture("grafiti.png");
// Mode
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// Shader Class
Shader currentShader("vertexShader.glsl", "fragmentShader.glsl");
currentShader.use();
currentShader.setInt("texture1", 0);
currentShader.setInt("texture2", 1);
while (!glfwWindowShouldClose(window)) {
processInput(window);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
currentShader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(int), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
Then I use this textures together with this shaders
Fragment
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 1);
}
Vertex
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3,
1, 2, 3,
};
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
I'm sorry if my english is hideous but it's middle of the night and i'm struggling with this for hours right now
I found solution, enabling blend was not satisfying so i wrote fragmentShader in different way
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
vec4 AlphaColor = texture(texture2, TexCoord);
if(AlphaColor.a < 0.1) {
FragColor = texture(texture1, TexCoord);
} else {
FragColor = mix(texture(texture1, TexCoord), AlphaColor, 0.9);
}
}
Right now FragmentShader understands alpha channel and will mix only pixels without alpha
I am attempting to draw a png file using OpenGL and seem to have a problem with how I am setting up the textures.
Main.cpp:
float positions[] = {
-1.0f, -1.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
float texCoords[] = {
-1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unsigned int texBuffer;
glGenBuffers(1, &texBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int w;
int h;
int comp;
unsigned char* image = stbi_load("res/images/background_level.png", &w, &h, &comp, STBI_rgb_alpha);
if (image == nullptr)
throw(std::string("Failed to load texture"));
//std::cout << image << std::endl;
unsigned int m_texture;
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (comp == 3)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
else if (comp == 4)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(image);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(programID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
int uniformLoc = glGetUniformLocation(programID, "tex");
glUniform1i(uniformLoc, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
vertex.shader:
#shader VERTEX
#version 330 core
layout (location=0) in vec2 vert;
layout (location=1) in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
// Pass the tex coord straight through to the fragment shader
fragTexCoord = vertTexCoord;
gl_Position = vec4(vert, 0, 1);
}
fragment.shader:
#shader FRAGMENT
#version 330 core
uniform sampler2D tex; //this is the texture
in vec2 fragTexCoord; //this is the texture coord
out vec4 finalColor; //this is the output color of the pixel
void main() {
//finalColor = vec4(1.0, 1.0, 1.0, 1.0);
finalColor = texture(tex, fragTexCoord);
}
If I swap the line commented out in the fragment shader, I get an all white triangle rendered. However with the line attempting to use the texture, the triangle comes out all black. I am just beginning with OpenGL so I don't necessarily have all of the beginning concepts down pat. Textures may be ahead of my skill level but I figured it couldn't hurt to try and ask here as someone may be able to show me where I have things confused.
You are calling glBindTexture(GL_TEXTURE_2D, 0) instead of glBindTexture(GL_TEXTURE_2D, m_texture) inside the renderloop. With this command, a texture is bound to the currently active texture unit.
Beforehand, sorry for a lot of posted code. I will try to be as straightforward as possible.
My texture is 4x4 texture image in bmp format (if someone interested here it is ->). And as a result of mapping i get color of top leftpixel (0.0, 1.0) (i checked it, it is always color of top left pixel) and my triangle color results in color of that pixel, which is white.
I tried changing GL_NEARESTtoGL_LINEAR in GL_TEXTURE_MAG_FILTER
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
and i get bottom right pixel (1.0, 0.0), which is some kind of green:
I am loading texture using stb_image. So in my Texture.cpp:
Texture::Texture(const std::string& fileName)
{
int width, height, numComponents;
unsigned char* imageData = stbi_load(fileName.c_str(), &width, &height, &numComponents, 4);
if (imageData == NULL)
{
std::cerr << "Error: Texture load failed for texture: " << fileName << std::endl;
}
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
}
Texture::~Texture(void)
{
glDeleteTextures(1, &_texture);
}
void Texture::Bind(unsigned int unit)
{
assert(unit >= 0 && unit <= 31);
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, _texture);
}
In my vertex shader:
#version 150
in vec3 position;
in vec2 texCoord;
out vec2 texCoord0;
void main(void)
{
texCoord0 = texCoord;
gl_Position = vec4(position, 1.0);
}
In my fragment shader:
#version 150
in vec2 textCoord0;
uniform sampler2D texture;
void main(void)
{
gl_FragColor = texture2D(texture, textCoord0);
}
In my main.cpp
#include <iostream>
#include <GL/glew.h>
#include "Display.h"
#include "Shader.h"
#include "Mesh.h"
#include "Texture.h"
int main(int argc, char** argv)
{
Display display(800, 600, " ");
display.Clear(0.0f, 0.15f, 0.3f, 1.0f);
Vertex vertices[] = {
Vertex(glm::vec3(-1.0f, -1.0f, 0.0f), glm::vec2(0.0f, 0.0f)),
Vertex(glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec2(0.5f, 1.0f)),
Vertex(glm::vec3( 1.0f, -1.0f, 0.0f), glm::vec2(1.0f, 0.0f))
};
Texture texture("./res/a.bmp");
Shader shader("./res/testShader");
Mesh mesh(vertices, sizeof(vertices) / sizeof(vertices[0]));
while (display.IsClosed() != true)
{
shader.Bind();
texture.Bind(0);
mesh.Draw();
display.Update();
}
return 0;
}
In Mesh.cpp i am splitting Vertices attributes (glm::vec3 _position and glm::vec2 _texture) into 2 stl vectors and using 2 buffers ("0" - for position of vertex and "1" - for texture) :
Mesh::Mesh(Vertex* vertices, unsigned int numVertices, GLenum usage)
{
_drawCount = numVertices;
glGenVertexArrays(1, &_vertexArrayObject);
glBindVertexArray(_vertexArrayObject);
std::vector<glm::vec3> positions;
std::vector<glm::vec2> texCoords;
positions.reserve(numVertices);
texCoords.reserve(numVertices);
for (unsigned int i = 0; i < numVertices; ++i)
{
positions.push_back(*vertices[i].Position());
texCoords.push_back(*vertices[i].TexCoord());
}
glGenBuffers(NUM_BUFFERS, _vertexArrayBuffers);
glBindBuffer(GL_ARRAY_BUFFER, _vertexArrayBuffers[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(positions[0]), positions.data(), usage);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vertexArrayBuffers[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(texCoords[0]), texCoords.data(), usage);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
Mesh::~Mesh(void)
{
glDeleteVertexArrays(1, &_vertexArrayObject);
}
void Mesh::Draw(GLenum mode)
{
glBindVertexArray(_vertexArrayObject);
glDrawArrays(mode, 0, _drawCount);
glBindVertexArray(0);
}
In Shader.cpp i binded atributes like this:
glBindAttribLocation(_program, 0, "position");
glBindAttribLocation(_program, 1, "texCoord");
----------------------------EDIT---------------------------------
After changing vertex shader to:
#version 330 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 = texCoord;
}
and fragment shader to:
#version 330 core
in vec2 TexCoord;
out vec4 color;
uniform sampler2D ourTexture;
void main()
{
color = texture(ourTexture, TexCoord);
}
texture is mapped correctly.
But i still want to know why my first solution doesn't work.
But i still want to know why my first solution doesn't work.
Because you're using
#version 330 core
and texture2D is deprecated since version 130
The shader compiler should've warned or errored about that. Check your shader logs via glGetShaderInfoLog and glGetProgramInfoLog.