I'm using OpenGL 4.4 with SDL2. I am trying to render a simple triangle with the vertices (-1, -1, 0), (1, -1, 0), (0, 1, 0). However, when I think I'm doing everything correctly, nothing is drawn.
I extracted and reorganized the relevant code from my project:
#include <cerrno>
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <string>
#include <GL/glew.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
void init();
void cleanUp();
std::string loadShader(std::string filepath);
void checkShaderSuccess(GLuint shader);
SDL_Window* win;
SDL_GLContext glContext;
GLuint program, vertShader, fragShader, vao, vbo;
class GenError: public std::exception {
public:
GenError():
exception(), msg("") {}
GenError(const std::string& m):
exception(), msg(m) {}
virtual ~GenError() throw() {}
virtual const char* what() const throw() {
return msg.c_str();
}
private:
std::string msg;
};
int main() {
init();
program = glCreateProgram();
if (program == 0) {
throw GenError("Shader creation failed: "
"Could not find valid memory location in "
"constructor");
}
vertShader = glCreateShader(GL_VERTEX_SHADER);
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
if (vertShader == 0 || fragShader == 0) {
std::string m;
m += "Shader creation failed: "
"Could not find valid memory location when "
"adding shader: ";
m += (char *)gluErrorString(glGetError());
throw GenError(m);
}
std::cout << "Creating vertex shader..." << std::endl;
std::string data = loadShader("./shaders/basicVertex.vs");
const GLchar* data_c = data.c_str();
glShaderSource(vertShader, 1, &data_c, NULL);
glCompileShader(vertShader);
checkShaderSuccess(vertShader);
glAttachShader(program, vertShader);
std::cout << "Vertex shader created" << std::endl;
std::cout << "Creating fragment shader..." << std::endl;
data = loadShader("./shaders/basicFragment.fs");
data_c = data.c_str();
glShaderSource(fragShader, 1, &data_c, NULL);
glCompileShader(fragShader);
checkShaderSuccess(fragShader);
glAttachShader(program, fragShader);
std::cout << "Fragment shader created" << std::endl;
glLinkProgram(program);
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (success == GL_FALSE) {
GLint logLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLen);
GLchar programLog[logLen];
glGetProgramInfoLog(program, logLen, &logLen, programLog);
std::string m;
m += "Failed to link program: ";
m += (char *)gluErrorString(glGetError());
m += ": ";
m += (char *)programLog;
throw GenError(m);
}
glValidateProgram(program);
glGetProgramiv(program, GL_VALIDATE_STATUS, &success);
if (success == GL_FALSE) {
GLint logLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLen);
GLchar programLog[logLen];
glGetProgramInfoLog(program, logLen, &logLen, programLog);
std::string m;
m += "Failed to validate program: ";
m += (char *)gluErrorString(glGetError());
m += ": ";
m += (char *)programLog;
throw GenError(m);
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
const GLfloat verts[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER,
sizeof(verts),
verts,
GL_STATIC_DRAW );
SDL_Event ev;
bool running = true;
while (true) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_WINDOWEVENT &&
ev.window.event == SDL_WINDOWEVENT_CLOSE) {
std::cout << "Closing window..." << std::endl;
running = false;
break;
}
}
if (!running) break;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0,
3,
GL_FLOAT,
GL_FALSE,
3*sizeof(GLfloat),
(GLvoid*)0 );
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
SDL_GL_SwapWindow(win);
}
std::cout << "Window closed" << std::endl;
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
cleanUp();
return 0;
}
void init() {
std::cout << "Initializing..." << std::endl;
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::string m;
m.append("Error initializing SDL2: ");
m.append(SDL_GetError());
throw GenError(m);
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
win = SDL_CreateWindow("Triangle Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600,
SDL_WINDOW_OPENGL );
if (win == NULL) {
throw GenError(SDL_GetError());
}
glContext = SDL_GL_CreateContext(win);
if (glContext == NULL) {
std::string m;
m.append("Error associating window with OpenGL: SDL Error: ");
m.append(SDL_GetError());
throw GenError(m);
}
glewExperimental = GL_TRUE;
GLenum glewErr = glewInit();
if (glewErr != GLEW_OK) {
std::string m;
m.append("Error initializing OpenGL GLEW extension: ");
m.append((const char*)glewGetErrorString(glewErr));
throw GenError(m);
} else {
/* GLEW does not play nice with OpenGL 4.4.
* GLEW thinks OpenGL 4.4 is "pretentious" and
* "entitled". GLEW likes to throw an invalid
* enumerant error the next time glGetError is
* called after GLEW's initialization.
* glGetError must be envoked to discard this
* faulty error. GLEW makes my code look sloppy.
* We do not like GLEW. We tolerate GLEW.
*/
GLenum junk = glGetError();
}
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_FRAMEBUFFER_SRGB);
if(SDL_GL_SetSwapInterval(1) < 0) {
std::cerr << "Warning: Unable to set VSync! "
<< "SDL Error: "
<< SDL_GetError() << std::endl;
}
GLenum error = glGetError();
if (error != GL_NO_ERROR) {
std::string m;
m.append("Error initializing OpenGL: OpenGL Error: ");
m.append(reinterpret_cast<const char*>(gluErrorString(error)));
throw GenError(m);
}
std::cout << "Initialized" << std::endl;
}
void cleanUp() {
std::cout << "Cleaning up..." << std::endl;
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
std::cout << "Cleaned" << std::endl;
}
std::string loadShader(std::string filepath) {
std::ifstream shaderFile(filepath.c_str());
if (!shaderFile.is_open()) {
std::cerr << "Could not load shader: "
<< "Error opening "
<< filepath
<< ": " << std::strerror(errno)
<< std::endl;
return std::string("");
}
std::string content, line;
while (std::getline(shaderFile, line)) {
content += line + '\n';
}
shaderFile.close();
return content;
}
void checkShaderSuccess(GLuint shader) {
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
GLint logLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen);
GLchar shaderLog[logLen];
glGetShaderInfoLog(shader, logLen, &logLen, shaderLog);
std::string m;
m += "Shader compilation failed: ";
m += (char *)gluErrorString(glGetError());
m += ": ";
m += (char *)shaderLog;
glDeleteShader(shader);
throw GenError(m);
}
}
...without error catching (for faster skimming):
#include <cerrno>
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <string>
#include <GL/glew.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
void init();
void cleanUp();
std::string loadShader(std::string filepath);
SDL_Window* win;
SDL_GLContext glContext;
GLuint program, vertShader, fragShader, vao, vbo;
int main() {
init();
program = glCreateProgram();
vertShader = glCreateShader(GL_VERTEX_SHADER);
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
std::cout << "Creating vertex shader..." << std::endl;
std::string data = loadShader("./shaders/basicVertex.vs");
const GLchar* data_c = data.c_str();
glShaderSource(vertShader, 1, &data_c, NULL);
glCompileShader(vertShader);
glAttachShader(program, vertShader);
std::cout << "Vertex shader created" << std::endl;
std::cout << "Creating fragment shader..." << std::endl;
data = loadShader("./shaders/basicFragment.fs");
data_c = data.c_str();
glShaderSource(fragShader, 1, &data_c, NULL);
glCompileShader(fragShader);
glAttachShader(program, fragShader);
std::cout << "Fragment shader created" << std::endl;
glLinkProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
const GLfloat verts[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER,
sizeof(verts),
verts,
GL_STATIC_DRAW );
SDL_Event ev;
bool running = true;
while (true) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_WINDOWEVENT &&
ev.window.event == SDL_WINDOWEVENT_CLOSE) {
std::cout << "Closing window..." << std::endl;
running = false;
break;
}
}
if (!running) break;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0,
3,
GL_FLOAT,
GL_FALSE,
3*sizeof(GLfloat),
(GLvoid*)0 );
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
SDL_GL_SwapWindow(win);
}
std::cout << "Window closed" << std::endl;
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
cleanUp();
return 0;
}
void init() {
std::cout << "Initializing..." << std::endl;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
win = SDL_CreateWindow("Triangle Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600,
SDL_WINDOW_OPENGL );
glContext = SDL_GL_CreateContext(win);
glewExperimental = GL_TRUE;
GLenum glewErr = glewInit();
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_FRAMEBUFFER_SRGB);
std::cout << "Initialized" << std::endl;
}
void cleanUp() {
std::cout << "Cleaning up..." << std::endl;
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
std::cout << "Cleaned" << std::endl;
}
std::string loadShader(std::string filepath) {
std::ifstream shaderFile(filepath.c_str());
std::string content, line;
while (std::getline(shaderFile, line)) {
content += line + '\n';
}
shaderFile.close();
return content;
}
...my vertex shader (GLSL):
#version 440
layout (location = 0) in vec3 position;
void main() {
gl_Position = vec4(0.5 * position, 1.0);
}
...and my fragment shader:
#version 440
out vec4 fragColor;
void main() {
fragColor = vec4(0.0, 1.0, 1.0, 1.0);
}
Now oddly enough, when I change line 148 in my C++ code (with error catching) from this...
3*sizeof(GLfloat),
...to this (in other words, changing the stride)...
3*sizeof(GLdouble),
...compiling and running produces a triangle with the vertices (-1, -1, 0), (0, 0, 0), (0, 1, 0). The second vertex is apparently getting obscured. Instead of an isosceles triangle, I get a scalene triangle.
I would like to 1) figure out how to fix my program so that it displays a triangle with the specified vertices, and 2) understand what I did wrong initially that caused my such an odd result when modifying the aforementioned line of code.
I have been tinkering with this for almost a week. Any insight is appreciated. Thanks!
Your code has a problem with the winding order of the polygons. You specify clockwise winding for the front faces, and enable culling of the back faces:
glFrontFace(GL_CW);
glCullFace(GL_BACK);
But the triangle has counter-clockwise winding order:
const GLfloat verts[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
This means that the triangle will be eliminated by culling.
Using counter-clockwise winding is mostly standard in OpenGL, and is also the default. So the best option is that you simply remove this line of code:
glFrontFace(GL_CW);
This will leave the value at GL_CCW, which matches your geometry.
Disabling backface culling is always one of the first things you should do when polygons don't show up. Having the wrong winding order is one of the most common causes of things not rendering, and it's very easy to triage by simply disabling culling, and checking if that makes the geometry show up.
Related
I am having trouble with my C++ code for an OpenGL program that is supposed to create a 2D triangle and keep receiving this error message:
Error! Fragment shader failed to compile.
ERROR: 0:1: '' : syntax error: #version directive must occur in a shader before anything else.
Error! Shader Program Linker Failure.
I have tried putting the code from lines 13-27 before the const char* APP_TITLE line (line 8) but that doesn't seem to make a difference.
What can I do to generate this 2D triangle?
#include <iostream>
#include <sstream>
#define GLEW_STATIC
#include "GL/glew.h"
#include "GLFW/glfw3.h"
const char* APP_TITLE = "Texturing a Pyramid";
const int gwindowWidth = 800;
const int gwindowHeight = 600;
GLFWwindow* gWindow = NULL;
const GLchar* vertexShaderSrc =
"#version 330 core\n"
"layout (location = 0) in vec3 pos;"
"void main()"
"{"
" gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);"
"}";
const GLchar* fragmentShaderSrc =
"version 330 core\n"
"out vec4 frag_color;"
"void main()"
"{"
" frag_color = vec4(0.35f, 0.96f, 0.3f, 1.0);"
"}";
void glfw_onKey(GLFWwindow* window, int key, int scancode, int action, int mode);
void showFPS(GLFWwindow* window);
bool initOpenGL();
int main()
{
if (!initOpenGL())
{
std::cerr << "GLFW intialization failed." << std::endl;
return false;
}
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f, // Top Vertex
0.5f, -0.5f, 0.0f, // Right Vertex
-0.5f, -0.5f, 0.0f // Left Vertex
};
GLuint vbo, vao;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource (vs, 1, &vertexShaderSrc, NULL);
glCompileShader(vs);
GLint result;
GLchar infoLog[512];
glGetShaderiv(vs, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(vs, sizeof(infoLog), NULL, infoLog);
std::cout << "Error! Vertex shader failed to compile." << infoLog << std::endl;
}
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource (fs, 1, &fragmentShaderSrc, NULL);
glCompileShader(fs);
glGetShaderiv(fs, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(fs, sizeof(infoLog), NULL, infoLog);
std::cout << "Error! Fragment shader failed to compile." << infoLog << std::endl;
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &result);
if (!result)
{
glGetProgramInfoLog(shaderProgram, sizeof(infoLog), NULL, infoLog);
std::cout << "Error! Shader Program Linker Failure" << std::endl;
}
glDeleteShader(vs);
glDeleteShader(fs);
// Main loop
while (!glfwWindowShouldClose(gWindow))
{
showFPS(gWindow);
glfwPollEvents();
glfwSwapBuffers(gWindow);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glfwSetKeyCallback(gWindow, glfw_onKey);
}
glDeleteProgram(shaderProgram);
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glfwTerminate();
return 0;
}
bool initOpenGL()
{
if (!glfwInit())
{
std::cerr << "GLFW initialization failed." << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* gWindow = glfwCreateWindow(gwindowWidth, gwindowHeight, APP_TITLE, NULL, NULL);
if (gWindow == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(gWindow);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
std::cerr << "GLEW initialization failed." << std::endl;
return false;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
return true;
}
void glfw_onKey(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
void showFPS(GLFWwindow* window)
{
static double previousSeconds = 0.0;
static int frameCount = 0;
double elapsedSeconds;
double currentSeconds = glfwGetTime(); // returns # of seconds since GLFW started, as a double
elapsedSeconds = currentSeconds - previousSeconds;
// limit text update 4 times per second
if (elapsedSeconds > 0.25)
{
previousSeconds = currentSeconds;
double fps = (double)frameCount / elapsedSeconds;
double msPerFrame = 1000.0 / fps;
std::ostringstream outs;
outs.precision(3);
outs << std::fixed
<< APP_TITLE << " "
<< "FPS: " << fps << " "
<< "FrameTime: " << msPerFrame << " (ms)";
glfwSetWindowTitle(window, outs.str().c_str());
frameCount = 0;
}
frameCount++;
}
fragmentShaderSrc is missing a # (U+0023 NUMBER SIGN) in front of version:
"version 330 core\n"
^ note lack of #
Should be:
"#version 330 core\n"
^ note the #
So first of all, i am a total beginner in open gl, and i am learning opengl from learnopengl.com. So i understood whats going on in the code in the main method.The code works in main method. But when i tried to create a class for it, it doesn't render anything!! I have absolutely no idea whats going wrong!
Sprite.h
#pragma once
#include"Shader.h"
#include<GL\glew.h>
class Sprite {
GLuint vao;
GLuint vbo;
int vertexCount;
Shader shader;
public:
Sprite(const GLfloat vertices[9], int noOfVertices, Shader s = Shader()) : vertexCount(noOfVertices) , shader(s)
{
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, this->vertexCount, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void draw() {
glBindVertexArray(this->vao);
glDrawArrays(GL_TRIANGLES, 0, this->vertexCount);
glBindVertexArray(0);
}
};
Shader.h
#pragma once
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<GL\glew.h>
class Shader {
GLuint programID;
GLuint vertID;
GLuint fragID;
public:
Shader(std::string vertex = "Shaders/Dvert.vert", std::string fragment = "Shaders/Dfrag.frag")
{
this->programID = glCreateProgram();
this->vertID = glCreateShader(GL_VERTEX_SHADER);
this->fragID = glCreateShader(GL_FRAGMENT_SHADER);
this->CompileShaders(vertex, fragment);
this->LinkProgram();
}
GLuint getProgramId() {
return this->programID;
}
private:
void CompileShaders(std::string vertexShaderPath, std::string FragShaderPath) {
std::string vCode = GetContentsFrom(vertexShaderPath).c_str();
const char * vertexCode = vCode.c_str();
glShaderSource(this->vertID, 1, &vertexCode, NULL);
glCompileShader(this->vertID);
this->HandleShaderErrors(this->vertID);
std::string fCode = GetContentsFrom(FragShaderPath).c_str();
const char * fragCode = fCode.c_str();
glShaderSource(this->fragID, 1, &fragCode, NULL);
glCompileShader(this->fragID);
std::cout << fragCode << std::endl;
this->HandleShaderErrors(this->fragID);
}
void LinkProgram() {
glAttachShader(this->programID, this->vertID);
glAttachShader(this->programID, this->fragID);
glLinkProgram(this->programID);
this->HandleLinkErrors();
}
std::string GetContentsFrom(std::string path) {
std::ifstream file(path);
std::ostringstream stream;
if (!file) {
std::cout << "Specified file path is invalid" << std::endl;
return "";
}
stream << file.rdbuf();
std::cout << stream.str() << std::endl << std::endl;
return stream.str();
}
void HandleLinkErrors() {
int result;
glGetProgramiv(this->programID, GL_LINK_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetProgramiv(this->programID, GL_INFO_LOG_LENGTH, &length);
std::vector<char> error(length);
glGetProgramInfoLog(this->programID, length , &length, &error[0]);
std::cout << &error[0] << std::endl;
glDetachShader(this->programID, this->vertID);
glDetachShader(this->programID, this->fragID);
}
}
void HandleShaderErrors(GLuint shader) {
int status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
int length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::vector<char> error(length);
glGetShaderInfoLog(shader, length, &length, &error[0]);
std::cout << &error[0] << std::endl;
glDeleteShader(shader);
}
}
};
Main.cpp
#include<GL\glew.h>
#include<GLFW\glfw3.h>
#include"Console.h"
#include"Headers\Shader.h"
#include"Headers\Sprite.h"
#include<iostream>
static const GLfloat vertices[] = {
0.5f, -0.5f ,0.0f ,
-0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
int main() {
if (!glfwInit()) {
Console.Log("GLFW could not be initialised!!");
Console.Wait();
}
GLFWwindow *window = glfwCreateWindow(600, 400, "Open GL", nullptr, nullptr);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
Console.Log("GLEW could not be initialised!!");
Console.Wait();
}
Sprite s(vertices, 3);
glClearColor(0, 0, 0, 1);
glfwWindowHint(GLFW_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_VERSION_MINOR, 3);
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwPollEvents();
s.draw();
glfwSwapBuffers(window);
}
}
Please help me out!!
Note:- The code in the main method renders the white triangle without the
shaders,so my graphics card works without shaders.
Also the Console class i have created is just to print to the console and has nothing to do with the opengl stuff. Console.Log isstd::cout<< and Console.Wait is std::cin.get();
There are at least two problems. The first is that your sizeof(vertices) in Sprite produces wrong result, because it gives the size of a pointer, not the size of the array. To fix it, replace it with sizeof(GLfloat) * 9.
The second problem is that you are specifying the OpenGL context version too late, after creating the window and context. To fix it, call these methods before glfwCreateWindow, not after:
glfwWindowHint(GLFW_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_VERSION_MINOR, 3);
I guess this is the millionth question of the same type. I am using OpenGL 3.3 Core Profile with C++ and try to render a triangle.
I have already read the following two pages, including typing AND copy-pasting the code that is being discussed. Below I posted the significant bits. I already had a triangle being rendered, but obviously I changed some minor detail and messed it up. GLFW and GLEW are being initialized and clearing with the glClearColor works just fine.
Frameworks in use: GLFW for windowing, GLEW and GLM.
Question: What is the error in my code and why is nothing being rendered?
Expectation: A white triangle should be visible.
Result: Nothing is being rendered. The window is filled with the glClearColor
Game.cpp
const float vertex_data[9] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
void Game::init()
{
shader = ShaderProgram();
shader.attachShader(readTextFromFile("data/shaders/main.vs"), GL_VERTEX_SHADER);
shader.attachShader(readTextFromFile("data/shaders/main.fs"), GL_FRAGMENT_SHADER);
shader.linkProgram();
mesh = Mesh(vertex_data);
}
void Game::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.bind();
{
mesh.render();
}
shader.unbind();
}
Mesh.cpp
uint32_t vao;
uint32_t vertex_buffer;
Mesh::Mesh(const float vertex_data[])
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
}
void Mesh::render()
{
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
{
// Is this actually necessary for every draw-call?
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
glDisableVertexAttribArray(0);
}
ShaderProgram.cpp
uint32 id = 0;
bool linked = false;
uint32 vertex_shader = 0;
uint32 fragment_shader = 0;
ShaderProgram::~ShaderProgram()
{
unbind();
if (vertex_shader > 0)
{
glDetachShader(id, vertex_shader);
glDeleteShader(vertex_shader);
}
if (fragment_shader > 0)
{
glDetachShader(id, fragment_shader);
glDeleteShader(fragment_shader);
}
if (id > 0 && linked)
{
glDeleteProgram(id);
}
}
void ShaderProgram::attachShader(std::string source, int32 type)
{
assert(type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER);
assert(id == 0);
const char* code = source.c_str();
switch (type)
{
case GL_VERTEX_SHADER:
assert(vertex_shader == 0);
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &code, NULL);
glCompileShader(vertex_shader);
int32 vresult;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vresult);
if (vresult != GL_TRUE)
{
int32 infolength;
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &infolength);
GLchar* infolog = new GLchar[infolength + 1];
glGetShaderInfoLog(vertex_shader, infolength + 1, NULL, infolog);
std::stringstream ss;
ss << "Shader compilation failed for Vertex Shader: " << infolog << std::endl;
std::cout << ss.str() << std::endl;
throw std::runtime_error(ss.str());
}
break;
case GL_FRAGMENT_SHADER:
assert(fragment_shader == 0);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &code, NULL);
glCompileShader(fragment_shader);
int32 fresult;
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fresult);
if (fresult != GL_TRUE)
{
int32 infolength;
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &infolength);
int32 infosize = infolength + 1;
GLchar* infolog = new GLchar[infosize];
glGetShaderInfoLog(fragment_shader, infosize, NULL, infolog);
std::stringstream ss;
ss << "Shader compilation failed for Fragment Shader: " << infolog << std::endl;
std::cout << ss.str() << std::endl;
throw std::runtime_error(ss.str());
}
break;
default:
throw std::invalid_argument("Unknown Shader-Type specified");
}
}
void ShaderProgram::linkProgram()
{
assert(id == 0);
assert(vertex_shader > 0);
assert(fragment_shader > 0);
id = glCreateProgram();
glAttachShader(id, vertex_shader);
glAttachShader(id, fragment_shader);
glLinkProgram(id);
int32 result;
glGetProgramiv(id, GL_LINK_STATUS, &result);
if (result != GL_TRUE)
{
int32 infolength;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infolength);
int32 infosize = infolength + 1;
GLchar* infolog = new GLchar[infosize];
glGetProgramInfoLog(id, infosize, NULL, infolog);
std::stringstream ss;
ss << "Shader Program Linking failed: " << infolog << std::endl;
throw std::runtime_error(ss.str());
}
linked = true;
}
void ShaderProgram::bind()
{
assert(id > 0);
assert(linked);
glUseProgram(id);
}
void ShaderProgram::unbind()
{
int32 current;
glGetIntegerv(GL_CURRENT_PROGRAM, ¤t);
if (current == id)
{
glUseProgram(0);
}
}
bool ShaderProgram::isLinked()
{
return linked;
}
Vertex Shader: "main.vs"
#version 330
layout(location = 0) in vec3 VertexPosition;
void main()
{
gl_Position = vec4(VertexPosition.xyz, 1.0);
}
Fragment Shader "main.fs":
#version 330
out vec4 FinalColor;
void main()
{
FinalColor = vec4(1.0, 1.0, 1.0, 1.0);
}
This line has an error:
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
The second parameter expects the size of the array but you are passing the size of a pointer. To fix it use something like vertex count * sizeof( float )
I am trying to have OpenGL automatically assign an ID to a glsl-attribute, but it is failing.
My main program:
#include <iostream>
#include <GL/glew.h>
#include <GL/glfw3.h>
#include "test.h"
#include "shader_utils.h"
static void error_callback(int error, const char* description) {
std::cout << description << std::endl;
}
static void key_callback(GLFWwindow* window, int a, int b) {
if (a == GLFW_KEY_ESCAPE && b == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
void test()
{
std::cout << "Starting up" << std::endl;
init();
run();
}
GLFWwindow *window;
GLuint shaders;
GLuint vertexBuffer;
int init() {
glfwSetErrorCallback(error_callback);
if(!glfwInit()) {
return -1;
}
window = glfwCreateWindow(640, 480, "GLFW test", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glewExperimental = true;
glewInit();
shaders = LoadShaders("vertex.glsl", "fragment.glsl");
GLuint vao_id;
glGenVertexArrays(1, &vao_id);
glBindVertexArray(vao_id);
static const GLfloat vertex_data[] = {
// Bottom
-.5f, -.5f, -.5f, 1.f, 0.f, 0.f,
-.5f, -.5f, .5f, 1.f, 0.f, 0.f,
.5f, -.5f, .5f, 1.f, 0.f, 0.f,
};
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
}
void checkE() {
std::cout << "Checking for errors: ";
int err;
int a = 0;
while((err = glGetError()) != GL_NO_ERROR) {
std::cout << "Error: " << err << std::endl;
a = 1;
}
if(a == 0) {
std::cout << "no errors" << std::endl;
}
std::cout.flush();
}
int run() {
GLfloat angle = 0;
while(!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaders);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
GLuint attrLocation = glGetAttribLocation(shaders, "location");
GLuint attrColor = glGetAttribLocation(shaders, "color");
std::cout << "AttribLocation('location'): ";
std::cout << glGetAttribLocation(shaders, "location") << std::endl;
std::cout << "AttribLocation('color'): ";
std::cout << glGetAttribLocation(shaders, "color") << std::endl;
checkE();
std::cout << std::endl;
std::cout << "glEnableVertexAttribArray()" << std::endl;
glEnableVertexAttribArray(attrLocation);
glEnableVertexAttribArray(attrColor);
checkE();
std::cout << std::endl;
std::cout << "glVertexAttribPointer();" << std::endl;
glVertexAttribPointer(
glGetAttribLocation(shaders, "location"), // Attribute
3, // Size
GL_FLOAT, // Size
GL_FALSE, // Normalized
24, // Stride
(GLvoid*) 0 // Offset
);
checkE();
std::cout << std::endl;
std::cout << "glVertexAttribPointer();" << std::endl;
glVertexAttribPointer(
glGetAttribLocation(shaders, "color"),
3,
GL_FLOAT,
GL_FALSE,
24,
(GLvoid*) (3*sizeof(GLfloat))
);
checkE();
std::cout << std::endl;
glDrawArrays(GL_TRIANGLES, 0, 3);
checkE();
std::cout << std::endl;
glDisableVertexAttribArray(attrLocation);
glDisableVertexAttribArray(attrColor);
checkE();
std::cout << std::endl;
glfwSwapBuffers(window);
glfwPollEvents();
glfwSetWindowShouldClose(window, GL_TRUE);
}
glfwDestroyWindow(window);
glfwTerminate();
}
Output from program:
Starting up
Compiling shader : vertex.glsl
Compiling shader : fragment.glsl
Linking program
AttribLocation('location'): -1
AttribLocation('color'): -1
Checking for errors: no errors
glEnableVertexAttribArray()
Checking for errors: Error: 1281
glVertexAttribPointer();
Checking for errors: Error: 1281
glVertexAttribPointer();
Checking for errors: Error: 1281
Checking for errors: no errors
Checking for errors: Error: 1281
Shader loader:
#include "shader_utils.h"
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include "GL/glew.h"
#include "GL/glfw3.h"
GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path){
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open())
{
std::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
} else {
std::cout << "could not open\n";
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::string Line = "";
while(getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
// Link the program
fprintf(stdout, "Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
std::cout.flush();
return ProgramID;
}
Vertex shader:
#version 130
in vec4 position;
in vec3 color;
out vec3 f_color;
void main() {
f_color = color;
gl_Position = position * gl_ModelViewProjectionMatrix;
}
Fragment shader:
#version 130
in vec3 color;
void main() {
gl_FragColor = vec4(color, 1);
}
For some reason I get just -1 as the location for both the attributes. Obviously the rest of the errors are caused by invalid location indices?
From OpenGL docs:
If the named attribute variable is not an active attribute in the specified program object or if name starts with the reserved prefix "gl_", a value of -1 is returned.
The names do not begin with gl_ and they are in use in the shaders, so I shouldn't get a value of -1. What am I missing?
You are failing to get an attribute location for color because it is not active. While it is true that color is used to calculate f_color in this example, the fragment shader does not use f_color so the linker determines that the vertex attribute named: color is inactive.
The solution is quite simple, really:
Fragment Shader:
#version 130
in vec3 f_color; // RENAMED from color, so that this matches the output from the VS.
void main() {
gl_FragColor = vec4(f_color, 1);
}
It is not an error to re-use the name color for different purposes in the Vertex Shader (input vertex attribute) and Fragment Shader (input varying) stages so the compiler/linker will not complain. It would be an error if you tried to do something like inout color though, so this is why you have to pass vertex attributes to geometry/tessellation/fragment shaders using a differently named varying. If the input/output names between stages do not match then chances are quite good that the original vertex attribute will be considered inactive.
Also, unless you are transposing your ModelViewProjection matrix, you have the matrix multiplication in your vertex shader backwards. Column-major matrix multiplication, as OpenGL uses, should read right-to-left. That is, you start with an object space position (right-most) and transform to clip space (left-most).
In other words, this is the proper way to transform your vertices...
gl_Position = gl_ModelViewProjectionMatrix * position;
~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~
clip space object space to clip space obj space
I use OpenGL 3.2, GLFW and GLEW. I try to render simple triangle using VAO and simple shader on OS X (10.8.2), but nothing shows, only white screen. Shaders compile ok, GLEW inits ok, glGetString(GL_VERSION) shows 3.2, tried to put glGetError after every line, it didn't report any errors. I don't know what i do wrong. Here's the code:
#include "include/GL/glew.h"
#include "include/GL/glfw.h"
#include <cstdlib>
#include <iostream>
GLuint program;
char *textFileRead(char *fn) {
FILE *fp;
char *content = NULL;
int count=0;
if (fn != NULL) {
fp = fopen(fn,"rt");
if (fp != NULL) {
fseek(fp, 0, SEEK_END);
count = ftell(fp);
rewind(fp);
if (count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
}
}
return content;
}
void checkCompilationStatus(GLuint s) {
GLint status = 0;
glGetShaderiv(s, GL_COMPILE_STATUS, &status);
if (status == 0) {
int infologLength = 0;
int charsWritten = 0;
glGetShaderiv(s, GL_INFO_LOG_LENGTH, &infologLength);
if (infologLength > 0)
{
GLchar* infoLog = (GLchar *)malloc(infologLength);
if (infoLog == NULL)
{
printf( "ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetShaderInfoLog(s, infologLength, &charsWritten, infoLog);
printf( "Shader InfoLog:\n%s", infoLog );
free(infoLog);
}
}
}
void setShaders() {
GLuint v, f;
char *vs = NULL,*fs = NULL;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead("minimal.vert");
fs = textFileRead("minimal.frag");
const char * vv = vs;
const char * ff = fs;
glShaderSource(v, 1, &vv,NULL);
glShaderSource(f, 1, &ff,NULL);
free(vs);free(fs);
glCompileShader(v);
checkCompilationStatus(v);
glCompileShader(f);
checkCompilationStatus(f);
program = glCreateProgram();
glAttachShader(program,v);
glAttachShader(program,f);
GLuint error;
glLinkProgram(program);
glUseProgram(program);
}
int main(int argc, char* argv[]) {
glfwInit();
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwOpenWindow(800, 600, 8, 8, 8, 8, 24, 8, GLFW_WINDOW);
glViewport(0, 0, 800, 600);
glfwSetWindowTitle("Triangle");
glewExperimental = GL_TRUE;
GLenum result = glewInit();
if (result != GLEW_OK) {
std::cout << "Error: " << glewGetErrorString(result) << std::endl;
}
std::cout << "VENDOR: " << glGetString(GL_VENDOR) << std::endl;
std::cout << "RENDERER: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "VERSION: " << glGetString(GL_VERSION) << std::endl;
std::cout << "GLSL: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
setShaders();
GLfloat vertices[] = {
1.0f, 1.0f, 0.f,
-1.f, -1.f, 0.f,
1.f, -1.f, 0.f
};
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint pos = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(pos);
glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, 0);
glClearColor(1.0, 1.0, 1.0, 1.0);
while (glfwGetWindowParam(GLFW_OPENED)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers();
glfwSleep(0.001);
}
}
And here are the shaders, vertex shader:
#version 150
in vec3 position;
void main()
{
gl_Position = vec4(position, 0);
}
fragment shader:
#version 150
out vec4 out_color;
void main()
{
out_color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
The w parameter in your vertex shader should be set to 1, not 0.
gl_Position = vec4(position, 1)
For more information see the section titled "Normalized Coordinates" under "Rasterization Overview" on this page
... The X, Y, and Z of each vertex's position
is divided by W to get normalized device coordinates...
So your coordinates were being divided by 0. A number divided by 0 is undefined.