I'm having issues rendering a 2D object in the 3D space in OpenGL. Whenever I compile my code I get a purple background, which is what I set it to. However, I do not see the object that I should be able to see. I think it's something wrong with the vertex shader, however, I am not completely sure.
Here is my code:
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#ifndef STBI_INCLUDE_STB_IMAGE_H
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#endif
#include "Shader.h"
class Render3D {
private:
GLFWwindow* window;
const int windowWidth = 1920;
const int windowHeigth = 1080;
Render3D(Render3D& render){}
Render3D operator=(Render3D& render) {}
void processInput(GLFWwindow* window) {
}
void privateInit() {
if (!glfwInit()) {
throw(-1);
std::cout << "Error: GLFW Init Failed" << std::endl;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(windowWidth, windowHeigth, "HAHAH BRRR", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW Window \n";
glfwTerminate();
throw (-1);
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
std::cout << "GLEW INIT FAILED\n";
exit(1);
}
//The first two parameters set the position of the lower left corner
glViewport(0, 0, windowWidth, windowHeigth);
}
void render() {
float positions[] = {
// positions // colors // texture
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
};
const char* vertexShader =
"#version 330 core\n"
"\n"
"layout (location = 0) vec3 aPos;\n"
"layout (location = 1) vec3 aColors;\n"
"layout (location = 2) vec2 aTex;\n"
"\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"\n"
"out vec3 Colors;\n"
"out vec2 TextureCoords;\n"
"\n"
"void main(){\n"
"\n"
"gl_Position = projection * view * model * vec4(aPos, 1.0f);\n"
"Colors = aColors;\n"
"TextureCoords = aTex;\n"
"\n"
"}\0";
const char* fragmentShader =
"#version 330 core\n"
"\n"
"out vec4 ourFrag;\n"
"\n"
"in vec3 Colors;\n"
"in vec2 TextureCoords;\n"
"\n"
"uniform sampler2D texture1;\n"
"uniform sampler2D texture2;\n"
"\n"
"void main(){\n"
"\n"
"ourFrag = mix(texture(texture1, TextureCoords), texture(texture2, TextureCoords), 0.2) * vec4(Colors, 1.0f);;\n"
"\n"
"\n"
"}\0";
unsigned int VAO, VBO, EBO;
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
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);
glBindVertexArray(0);
unsigned int Texture1, Texture2;
glGenTextures(1, &Texture1);
glGenTextures(1, &Texture2);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
int width, height, nrChannels;
unsigned char* data = stbi_load("src/Images/woodblock.jpg", &width, &height, &nrChannels, 4);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "TEXTURE FAILED:";
std::cout << stbi_failure_reason() << std::endl;
}
glBindTexture(GL_TEXTURE_2D, Texture2);
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);
stbi_set_flip_vertically_on_load(1);
data = stbi_load("src/Images/awesomeface.png", &width, &height, &nrChannels, 4);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "TEXTURE FAILED:";
std::cout << stbi_failure_reason() << std::endl;
}
Shader render3D_Program(vertexShader, fragmentShader, 1);
render3D_Program.use();
glUniform1i(glGetUniformLocation(render3D_Program.ID, "texture1"), 0);
glUniform1i(glGetUniformLocation(render3D_Program.ID, "texture2"), 1);
while (!glfwWindowShouldClose(window)) {
processInput(window);
glClearColor(0.5f, 0.2f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Texture2);
render3D_Program.use();
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view1 = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
view1 = glm::translate(view1, glm::vec3(0.0f, 0.0f, -3.0f));
projection = glm::perspective(glm::radians(45.0f), (float)windowWidth / (float)windowHeigth, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(render3D_Program.ID, "model"), 1, GL_FALSE, value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(render3D_Program.ID, "view"), 1, GL_FALSE, value_ptr(view1));
glUniformMatrix4fv(glGetUniformLocation(render3D_Program.ID, "projection"), 1, GL_FALSE, value_ptr(projection));
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &VBO);
glfwTerminate();
}
public:
Render3D(){}
void Init() {
privateInit();
}
void Run() {
render();
}
};
Additionally, here is the Shader class:
#ifndef SHADER_H
#define SHADER_H
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
Shader(const char* VertexShader, const char* FragmentShader, bool Specifier) {
unsigned int vertex = glCreateShader(GL_VERTEX_SHADER);
unsigned int fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertex, 1, &VertexShader, NULL);
glShaderSource(fragment, 1, &FragmentShader, NULL);
glCompileShader(vertex);
int successVertex;
char infoLogVertex[512];
glGetShaderiv(vertex, GL_COMPILE_STATUS, &successVertex);
if (!successVertex) {
glGetShaderInfoLog(vertex, 512, NULL, infoLogVertex);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLogVertex << std::endl;
}
glCompileShader(fragment);
int successFragment;
glGetShaderiv(fragment, GL_COMPILE_STATUS, &successFragment);
if (!successFragment){
glGetShaderInfoLog(fragment, 512, NULL, infoLogVertex);
std::cout << "ERROR::SHADER:FRAGMENT::COMPILATION_FAILED\n" << infoLogVertex << std::endl;
}
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string& name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string& name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string& name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
#endif
Your vertex shader fails to compiled because you missed the in type qualifier for the vertex shader inputs (attributes):
layout (location = 0) vec3 aPos;
layout (location = 1) vec3 aColors;
layout (location = 2) vec2 aTex;
It has to be:
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColors;
layout (location = 2) in vec2 aTex;
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 trying to display a texture, but for some reason it's not shown correctly it's distorted.
This is my source code:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
void processInput(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
int main(void)
{
int success;
char infoLog[512];
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, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"TexCoord = aTexCoord;"
"}\0";
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
"FragColor = texture(ourTexture, TexCoord);\n"
"}\0";
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
}
float vertices[] = {
//positions //texture coords
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,// top right
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,// bottom right
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,// bottom left
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f// top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int VBO;
unsigned int EBO;
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &EBO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
unsigned int texture;
glGenTextures(1, &texture);
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_S);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_T);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(1);
unsigned char *data = stbi_load("../asd.jpg", &width, &height,&nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
if(stbi_failure_reason())
std::cout << stbi_failure_reason();
}
while(!glfwWindowShouldClose(window))
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
processInput(window);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glfwTerminate();
return 0;
}
Result:
Expected result:
I checked all coordinates and positions and everything looks correct. I have no idea why the texture is not shown correctly.
The vertex and fragment shaders also seems to be correct.
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. Since the image has 3 color channels (GL_RGB), and is tightly packed the size of a row of the image may not be aligned to 4 bytes.
When a RGB image with 3 color channels is loaded to a texture object and 3*width is not divisible by 4, GL_UNPACK_ALIGNMENT has to be set to 1, before specifying the texture image with glTexImage2D:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
I'm trying to render JPG image using "stb_image.h" library. Im using GLEW and GLFW, here is the code:
#include "glew.h"
#include "glfw3.h"
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define WIDTH 800
#define HEIGHT 600
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
int main(){
GLFWwindow *window;
if (!glfwInit())
{
std::cout << "Failed to Init GLFW" << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL CPP", NULL, NULL);
if (!window)
{
std::cout << "Failed to create GLFW Window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
GLenum err = glewInit();
if (GLEW_OK != err)
{
std::cout << "Failed to Init GLEW" << std::endl;
glfwTerminate();
return -1;
}
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
};
float indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"layout (location = 2) in vec2 aTexCoord;\n"
"out vec3 ourColor;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
" ourColor = aColor;\n"
" TexCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
" FragColor = texture(ourTexture, TexCoord);\n"
"}\n\0";
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR COMPILING VERTEX SHADER" << infoLog << std::endl;
}
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR COMPILING FRAGMENT SHADER" << infoLog << std::endl;
}
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height, nrChannels;
unsigned char *data = stbi_load("C:/Users/user3/Documents/cppopengl/res/container.jpg", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
std::cout << "data loaded successfully"<< std::endl;
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
glUseProgram(shaderProgram);
//std::cout << glGetUniformLocation(shaderProgram, "ourTexture") << std::endl;
glUniform1i(glGetUniformLocation(shaderProgram, "ourTexture"), 0);
while (!glfwWindowShouldClose(window))
{
err = glGetError();
glClearColor(0.5, 0.5, 0.5, 1);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwPollEvents();
if (((err = glGetError()) != GL_NO_ERROR))
{
std::cout << err << std::endl;
}
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteProgram(shaderProgram);
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
Code compiles just fine, without errors and warnings. When I start the executable it shows white screen. Both vertex shader and fragment shader compile and link without errors. stbi_load() does not return error and glGetError() does not return error, glGetUniformLocation() returns uniform location just fine. Can you please help me out? Thanks in advance.
EDIT:
indices must be unsigned int instead of float, thanks #Rabbid76
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
The following code draws a white square to the screen. If I uncomment the line that uses the program, the square disappears.
When I debug the program with GLIntercept, the texture appears in a folder called Images, and the log says that the shaders compiled. However, it also says that the program links, but doesn't validate.
I've been poring over this for hours and I have no idea where to go from here.
// Vertex.vert
#version 150 core
in vec3 in_position;
in vec2 in_texture;
out vec2 Texture;
uniform mat4 in_model;
uniform mat4 in_view;
uniform mat4 in_projection;
void main()
{
gl_Position = in_projection * in_view * in_model * vec4(in_position, 1.0);
Texture = in_texture;
}
// Fragment.frag
#version 150 core
in vec2 Texture;
out vec4 Colour;
uniform sampler2D Sampler2D;
void main()
{
Colour = texture(Sampler2D, Texture);
}
// Source.cpp
#include <cfloat>
#include <iostream>
#include <string>
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include "Archive.h"
using namespace glm;
using namespace sf;
using namespace std;
struct Camera
{
vec3 Position = { 0.0f, 0.0f, 1.0f };
vec3 Target = { 0.0f, 0.0f, 0.0f };
vec3 Up = { 0.0f, 1.0f, 0.0f };
float Fovy = 74.0f;
float Aspect = 16.0f / 9.0f;
float ZNear = FLT_MIN;
float ZFar = FLT_MAX;
mat4 View;
mat4 Projection;
};
struct Actor
{
vec3 Scale = { 1.0f, 1.0f, 1.0f };
vec3 Rotation = { 0.0f, 0.0f, 0.0f };
vec3 Position = { 0.0f, 0.0f, 0.0f };
vector<GLfloat> Vertices;
vector<GLuint> Elements;
GLuint Texture;
Actor(string fileName)
{
Image image;
if (!image.loadFromFile(fileName + ".png"))
{
cerr << "ERROR: Unable to load texture" << endl;
}
glGenTextures(1, &Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
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);
glGenerateMipmap(GL_TEXTURE_2D);
// Draw a square instead of the actual model
Vertices.push_back(-1.0f); Vertices.push_back(-1.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f);
Vertices.push_back(1.0f); Vertices.push_back(-1.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f); Vertices.push_back(0.0f);
Vertices.push_back(1.0f); Vertices.push_back(1.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f); Vertices.push_back(1.0f);
Vertices.push_back(-1.0f); Vertices.push_back(1.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f);
Elements.push_back(0); Elements.push_back(1); Elements.push_back(2);
Elements.push_back(2); Elements.push_back(3); Elements.push_back(0);
}
};
GLuint CreateShader(GLenum shaderType, string fileName, Archive& archive)
{
string source;
archive.open(fileName);
source.resize(archive.getSize());
archive.read(&source[0], archive.getSize());
GLuint shader = glCreateShader(shaderType);
const char* pointer = source.c_str();
glShaderSource(shader, 1, &pointer, nullptr);
glCompileShader(shader);
GLsizei length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
GLchar* infoLog = new GLchar[length];
glGetShaderInfoLog(shader, length, &length, infoLog);
cerr << infoLog << endl;
delete[] infoLog;
}
return shader;
}
GLuint CreateProgram(GLuint vertex, GLuint fragment)
{
GLuint program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
GLsizei length;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
GLchar* infoLog = new GLchar[length];
glGetProgramInfoLog(program, length, &length, infoLog);
cerr << infoLog << endl;
delete[] infoLog;
}
return program;
}
int main(int argc, char* argv[])
{
Window window(VideoMode(1920, 1080), "");
window.setVerticalSyncEnabled(true);
if (!window.setActive(true))
{
cerr << "ERROR: Unable to set the window as the current target for OpenGL rendering" << endl;
return 1;
}
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
cerr << "ERROR: Unable to initialise GLEW" << endl;
return 1;
}
Archive shaders("Shaders.lea");
Archive models("Models.lea");
Actor actor("tree01");
GLuint vertex = CreateShader(GL_VERTEX_SHADER, "Vertex.vert", shaders);
GLuint fragment = CreateShader(GL_FRAGMENT_SHADER, "Fragment.frag", shaders);
GLuint program = CreateProgram(vertex, fragment);
GLuint vertexArray;
GLuint vertexBuffer;
GLuint elementBuffer;
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
// glUseProgram(program);
GLint position = glGetAttribLocation(program, "in_position");
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, 0);
glEnableVertexAttribArray(position);
GLint texture = glGetAttribLocation(program, "in_texture");
glVertexAttribPointer(texture, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(sizeof(GLfloat) * 3));
glEnableVertexAttribArray(texture);
GLint projection = glGetUniformLocation(program, "in_projection");
GLint view = glGetUniformLocation(program, "in_view");
GLint model = glGetUniformLocation(program, "in_model");
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Camera camera;
while (window.isOpen())
{
// Input handling code omitted
camera.View = lookAt(camera.Position, camera.Target, camera.Up);
camera.Projection = perspective(radians(camera.Fovy), camera.Aspect, camera.ZNear, camera.ZFar);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniformMatrix4fv(projection, 1, GL_FALSE, value_ptr(camera.Projection));
glUniformMatrix4fv(view, 1, GL_FALSE, value_ptr(camera.View));
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * actor.Vertices.size(), &actor.Vertices[0], GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * actor.Elements.size(), &actor.Elements[0], GL_STATIC_DRAW);
mat4 transform = translate(mat4(), actor.Position);
transform *= rotate(transform, actor.Rotation.z, vec3(0.0f, 0.0f, 1.0f));
transform *= rotate(transform, actor.Rotation.y, vec3(0.0f, 1.0f, 0.0f));
transform *= rotate(transform, actor.Rotation.x, vec3(1.0f, 0.0f, 0.0f));
transform *= scale(transform, actor.Scale);
glUniformMatrix4fv(model, 1, GL_FALSE, value_ptr(transform));
glBindTexture(GL_TEXTURE_2D, actor.Texture);
glDrawElements(GL_TRIANGLES, actor.Elements.size(), GL_UNSIGNED_INT, 0);
window.display();
}
glUseProgram(0);
glDisableVertexAttribArray(texture);
glDisableVertexAttribArray(position);
glDeleteBuffers(1, &elementBuffer);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(1, &vertexArray);
glDetachShader(program, fragment);
glDetachShader(program, vertex);
glDeleteShader(fragment);
glDeleteShader(vertex);
glDeleteProgram(program);
return 0;
}
It was a combination of two things.
When I last used this code, it was with GLM 0.9.7.6, and mat4() generated an identity matrix. However, at some point between that version of GLM and the one I'm currently using (0.9.9.5), mat4() started generating an empty matrix. Instead, you need mat4(1.0f).
Also, I used bad values for the near and far planes. I did think that the values I had would work, but clearly I don't quite understand what's going on behind the scenes.
I'm currently trying to learn OpenGL. I've successfully rendered rainbow triangles to the screen, and I've successfully moved them about the screen.
However, I can not seem to properly render a texture to two triangles.
Whenever I run this program, I am greeted with a black screen with nothing rendering. I've checked, and the image file is definately in the correct directory (it wouldn't run otherwise!)
define STB_IMAGE_IMPLEMENTATION
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <stb/stb_image.h>
int main()
{
//Initialize glfw
if (!glfwInit())
{
fprintf(stderr, "ERROR: Could not start GLFW3.\n");
return 1;
}
//Create the rendering context
GLFWwindow* window = glfwCreateWindow(480, 600, "Hello Rendering",
nullptr, nullptr);
if(!window)
{
fprintf(stderr, "ERROR: Could not create a rendering context with "
"GLFW3.\n");
return 1;
}
glfwMakeContextCurrent(window);
//Start GLEW
glewExperimental=GL_TRUE;
GLenum err=glewInit();
if(err!=GLEW_OK)
{
//Problem: glewInit failed, something is seriously wrong.
std::cout<<"glewInit failed, aborting."<<std::endl;
}
////////////////////////
//Loading PNG
////////////////////////
int x = 0;
int y = 0;
int n = 0;
int force_channels = 4;
unsigned char* image_data = stbi_load("spooky.png", &x, &y, &n,
force_channels);
if(!image_data)
{
fprintf(stderr, "ERROR: Could not load spooky.png\n.");
return 1;
}
//NPOT Check
if((x & (x - 1)) != 0 || (y & (y - 1)) != 0)
{
fprintf(stderr, "ERROR: Image is not a power of 2.\n");
fprintf(stderr, "h: %d w: %d", y, x);
return 1;
}
//Flip the image
int width_in_bytes = x * 4;
unsigned char* top = nullptr;
unsigned char* bottom = nullptr;
unsigned char temp = 0;
int half_height = y / 2;
for(int row = 0; row < half_height; row++)
{
top = image_data + row * width_in_bytes;
bottom = image_data + (y - row - 1) * width_in_bytes;
for(int col = 0; col < width_in_bytes; col++)
{
temp = *top;
*top = *bottom;
*bottom = temp;
top++;
bottom++;
}
}
GLuint tex = 0;
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA,
GL_UNSIGNED_BYTE, image_data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//////////////////////////////////
//Vertex shader
//////////////////////////////////
const char* vertShader =
"#version 330 core"
"layout(location = 0) in vec3 vertexPosition_modelspace;"
"layout(location = 1) in vec2 vt;"
"out vec2 texture_coordinates;"
"void main() {"
" texture_coordinates = vt;"
" gl_Position.xyz = vertexPosition_modelspace;"
" gl_Position.w = 1.0;"
"}";
///////////////////////////////////
//Frag shader
///////////////////////////////////
const char* fragShader =
"#version 330 core"
"uniform sampler2D basic_texture;"
"out vec4 frag_color;"
"void main() {"
" vec4 texel = texture(basic_texture, texture_coordinates);"
" frag_color = texel;"
"}";
////////////////////////////////////
//Create shader program
///////////////////////////////////
GLuint vsp = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vsp, 1, &vertShader, nullptr);
glCompileShader(vsp);
GLuint fsp = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fsp, 1, &fragShader, nullptr);
glCompileShader(fsp);
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, fsp);
glAttachShader(shader_program, vsp);
glLinkProgram(shader_program);
glUseProgram(shader_program);
////////////////////////////////////
//Texture coordinates
////////////////////////////////////
GLfloat texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
GLuint vt_vbo;
glGenBuffers(1, &vt_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof( texcoords), texcoords,
GL_STATIC_DRAW);
GLuint vao;;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
int dimensions = 2;
glVertexAttribPointer(1, dimensions, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(1);
while(!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Use the shader
glUseProgram(shader_program);
//Draw the two triangles (6 points)
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwPollEvents();
glfwSwapBuffers(window);
if(GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE))
{
glfwSetWindowShouldClose(window, 1);
}
}
std::cout << "Hello, World!" << std::endl;
return 0;
}
First of all, you should retrieve the error messages when compiling and linking your shader:
GLint status = GL_TRUE;
char error_msg[1024];
GLsizei read;
GLuint vsp = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vsp, 1, &vertShader, nullptr);
glCompileShader(vsp);
glGetShaderiv( vsp, GL_COMPILE_STATUS, &status );
if ( status != GL_TRUE )
{
glGetShaderInfoLog( vsp, 1024, &read, error_msg );
std::cout << "compile error:" << std::endl << error_msg << std::endl;
}
GLuint fsp = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fsp, 1, &fragShader, nullptr);
glCompileShader(fsp);
glGetShaderiv( fsp, GL_COMPILE_STATUS, &status );
if ( status != GL_TRUE )
{
glGetShaderInfoLog( fsp, 1024, &read, error_msg );
std::cout << "compile error:" << std::endl << error_msg << std::endl;
}
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, fsp);
glAttachShader(shader_program, vsp);
glLinkProgram(shader_program);
glGetProgramiv( shader_program, GL_LINK_STATUS, &status );
if ( status != GL_TRUE )
{
glGetProgramInfoLog( shader_program, 1024, &read, error_msg );
std::cout << "compile error:" << std::endl << error_msg << std::endl;
}
The first error message you will get is somehow like this:
0(1) : error C0205: invalid profile "corelayout"
0(1) : error C0206: invalid token "" in version line
This is because you did not write the line ending "\n" after the first line of the shader code ("#version 330 core").
When you fixe this then you get the next error message:
0(2) : error C1008: undefined variable "texture_coordinates"
You have to add the declaration of the in variable texture_coordinates to the fragment shader.
in vec2 texture_coordinates;
The final code looks like this:
const char* vertShader =
"#version 330 core\n"
"layout(location = 0) in vec3 vertexPosition_modelspace;"
"layout(location = 1) in vec2 vt;"
"out vec2 texture_coordinates;"
"void main() {"
" texture_coordinates = vt;"
" gl_Position.xyz = vertexPosition_modelspace;"
" gl_Position.w = 1.0;"
"}";
const char* fragShader =
"#version 330 core\n"
"uniform sampler2D basic_texture;"
"out vec4 frag_color;"
"in vec2 texture_coordinates;"
"void main() {"
" vec4 texel = texture(basic_texture, texture_coordinates);"
" frag_color = texel;"
"}";
Of course you have to provide vertex data for the vertex attribute vertexPosition_modelspace:
GLfloat texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
GLfloat vertex[] = {
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f
};
GLuint vert_vbo;
glGenBuffers(1, &vert_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vert_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof( vertex ), vertex, GL_STATIC_DRAW);
GLuint vt_vbo;
glGenBuffers(1, &vt_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof( texcoords ), texcoords, GL_STATIC_DRAW);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vert_vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(1);
Finally you should set the index of the texture unit, wher the texture is bound to, to the texture sampler uniform variable basic_texture:
int texture_unit_index = 0;
GLuint tex = 0;
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0 + texture_unit_index );
glBindTexture(GL_TEXTURE_2D, tex);
.....
// to do after glLinkProgram(shader_program);
int tex_sampler_loc = glGetUniformLocation( shader_program, "basic_texture" );
.....
// to do after glUseProgram(shader_program);
glUniform1i( tex_sampler_loc, texture_unit_index );