I recently started following an OpenGL tutorial series by TheCherno on youtube.
Here is my code:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
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() };
}
static unsigned int CompileShader(unsigned int type, const std::string& source) {
std::cout << "Compiling " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader..." << std::endl;
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
std::cout << glGetError() << std::endl;
glCompileShader(id);
std::cout << glGetError() << std::endl;
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
std::cout << glGetError() << std::endl;
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
std::cout << glGetError() << std::endl;
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << glGetError() << std::endl;
std::cout << "Failed to compile" << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
std::cout << glGetError() << std::endl;
return 0;
}
std::cout << "Successfully compiled " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl << std::endl;
return id;
}
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader) {
std::cout << "Creating shader..." << std::endl << std::endl;
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
std::cout << glGetError() << std::endl;
std::cout << "Attached vertex shader" << std::endl;
glAttachShader(program, fs);
std::cout << glGetError() << std::endl;
std::cout << "Attached fragment shader" << std::endl;
glLinkProgram(program);
std::cout << glGetError() << std::endl;
glValidateProgram(program);
std::cout << glGetError() << std::endl;
std::cout << "Linked and validated program" << std::endl;
glDeleteShader(vs);
std::cout << glGetError() << std::endl;
std::cout << "Deleted vertex shader" << std::endl;
glDeleteShader(fs);
std::cout << glGetError() << std::endl;
std::cout << "Deleted fragment shader" << std::endl;
std::cout << "Succesfully created shader!" << std::endl << std::endl;
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
std::cout << "Error!" << std::endl;
}
std::cout << glGetString(GL_VERSION) << std::endl;
float positions[6] = {
-0.5f, -0.5f,
0.0f, 0.5f,
0.5f, -0.5f
};
unsigned int buffer;
glGenBuffers(1, &buffer);
std::cout << glGetError() << std::endl;
glBindBuffer(GL_ARRAY_BUFFER, buffer);
std::cout << glGetError() << std::endl;
glBufferData(GL_ARRAY_BUFFER, 6*sizeof(float), positions, GL_STATIC_DRAW);
std::cout << glGetError() << std::endl;
glDisableVertexAttribArray(0);
std::cout << glGetError() << std::endl;
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*2, 0);
std::cout << glGetError() << std::endl;
glBindBuffer(GL_ARRAY_BUFFER, 0);
std::cout << glGetError() << std::endl;
ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
std::cout << "VERTEX" << std::endl;
std::cout << source.VertexSource << std::endl;
std::cout << "FRAGMENT" << std::endl;
std::cout << source.FragmentSource << std::endl;
//unsigned int shader = CreateShader(vertexShader, fragmentShader);
///glUseProgram(shader);
// render loop
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
//glDeleteProgram(shader);
glfwTerminate();
return 0;
}
Here's the Basic.shader file:
#shader vertex
#version 330 core
layout(location = 0) in vec4 position;
void main()
{
gl_Position = position;
}
#shader fragment
#version 330 core
layout(location = 0) out vec4 color;
void main()
{
color = vec4(1.0, 0.0, 0.0, 1.0);
}
I have tried using glGetError and it doesn't output any errors.
You need to enable the generic vertex attribute array instead of disabling it (see glEnableVertexAttribArray):
glDisableVertexAttribArray(0);
glEnableVertexAttribArray(0);
Furthermore, the code which compiles, linkes and installs the sahder is commented out:
//unsigned int shader = CreateShader(vertexShader, fragmentShader);
///glUseProgram(shader);
unsigned int shader = CreateShader(source.VertexSource, source.FragmentSource);
glUseProgram(shader);
I believe #Rabbid76's answer is correct. If it still does not work, make sure you are using compatible OpenGL context or create a VAO to hold the state.
Compatible OpenGL context can be set with:
//Before glfwCreateWindow call, after glfwInit
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
The default value is GLFW_OPENGL_ANY_PROFILE and this could mean CORE if COMPAT is not available. This ensures that a default VAObject always exist and is bound. Meaning that your glVertexAttribPointer calls actually have a place to store that information. I did not see these Cherno's tutorials, it's quite possible that VAOs are covered in the future tutorials. In CORE there will not be one and it might not draw anything.
While we are here, it is not a bad idea to set minimal OpenGL version required precisely. If for some reason it is not available on the target machine, the window creation will fail. This is more preferable than getting "random" seg faults when calling unsupported functions.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
My preferred way would be to create an actual VAO and go with GLFW_OPENGL_CORE_PROFILE. But feel free to go with tutorials, the ones I've seen from him are really high-quality.
//Put these before the vertex buffer initialization
int VAO;
glGenVertexArrays(1,&VAO);
glBindVertexArray(VAO);
Related
Using the normalized [-1,1] points A = (0.5, 0.5), B = (0.5, -0.5), C = (-0.5, -0.5), and D = (-0.5, 0.5), I'm drawing these points as pixels with glDrawArrays(GL_POINTS, 0, 4). I found that when I also call glDrawArrays(GL_LINES, 0, 4) to draw the 2 lines AB and CD there's a 1 pixel difference in the x-direction between the points and the endpoints of the 2 lines. Here's a screenshot of what I'm seeing:
I was also able to get this problem to go away if I changed the window size from 800x600 to 850x600. I'm thinking this might have to do with odd or even size window width, but I'm not sure. In my code, you can comment out #define SHOW_PROBLEM to change the window size where the problem doesn't occur. Any ideas would be greatly appreciated!
Here's my complete code for reference:
#include <bits/stdc++.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
void framebuffer_size_callback(GLFWwindow * window, int width, int height);
void processInput(GLFWwindow * window);
#define SHOW_PROBLEM
#ifdef SHOW_PROBLEM
// These dimensions show the problem
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#else
// These dimensions DO NOT show the problem
#define WINDOW_WIDTH 850
#define WINDOW_HEIGHT 600
#endif
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(WINDOW_WIDTH, WINDOW_HEIGHT, "OpenGLDemo", nullptr, nullptr);
if (!window)
{
std::cout << std::unitbuf
<< "[ERROR] " << __FILE__ << ':' << __LINE__ << ' ' << __PRETTY_FUNCTION__
<< "\n[ERROR] " << "Failed to create GLFW window!"
<< std::nounitbuf << std::endl;
glfwTerminate();
std::abort();
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
{
std::cout << std::unitbuf
<< "[ERROR] " << __FILE__ << ':' << __LINE__ << ' ' << __PRETTY_FUNCTION__
<< "\n[ERROR] " << "Failed to initialize GLAD!"
<< std::nounitbuf << std::endl;
std::abort();
}
// vertex shader
const char * vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
std::cout << std::unitbuf
<< "[ERROR] " << __FILE__ << ':' << __LINE__ << ' ' << __PRETTY_FUNCTION__
<< "\n[ERROR] " << "Vertex shader compilation failed!"
<< "\n[ERROR] " << infoLog
<< std::nounitbuf << std::endl;
std::abort();
}
// fragment shader
const char * fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\0";
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
glCompileShader(fragmentShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
std::cout << std::unitbuf
<< "[ERROR] " << __FILE__ << ':' << __LINE__ << ' ' << __PRETTY_FUNCTION__
<< "\n[ERROR] " << "Fragment shader compilation failed!"
<< "\n[ERROR] " << infoLog
<< std::nounitbuf << std::endl;
std::abort();
}
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
std::cout << std::unitbuf
<< "[ERROR] " << __FILE__ << ':' << __LINE__ << ' ' << __PRETTY_FUNCTION__
<< "\n[ERROR] " << "Shader program linking failed!"
<< "\n[ERROR] " << infoLog
<< std::nounitbuf << std::endl;
std::abort();
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), reinterpret_cast<void *>(0));
glEnableVertexAttribArray(0);
// 6. render loop
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
while (!glfwWindowShouldClose(window))
{
processInput(window);
// background
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glDrawArrays(GL_POINTS, 0, 4);
glDrawArrays(GL_LINES, 0, 4);
// check and call events and swap the buffers
glfwPollEvents();
glfwSwapBuffers(window);
}
// de-allocate all resources once they've outlived their purpose:
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow * window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow * window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
}
This may also be useful:
OpenGL vendor string: Intel
OpenGL renderer string: Mesa Intel(R) UHD Graphics 620 (KBL GT2)
OpenGL core profile version string: 4.6 (Core Profile) Mesa 20.0.8
OpenGL core profile shading language version string: 4.60
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL core profile extensions:
OpenGL version string: 4.6 (Compatibility Profile) Mesa 20.0.8
OpenGL shading language version string: 4.60
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile
OpenGL extensions:
OpenGL ES profile version string: OpenGL ES 3.2 Mesa 20.0.8
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
OpenGL ES profile extensions:
for GL_LINES the rasterizer would have to interpolate across two vertices, and with any other interpolated values from the vertex to fragment shaders, you should not rely on some kind of equality between hardcoded values and the interpolated. The resizing of windows tells you that the difference is just due to this interpolation/float error. If you goal is to color the vertices, try adding logic in your shader to check whether the current pixel fragment is very close to the 2 vertices it's interpolated from and color accordingly.
I am trying to upload volumetric data as a 3D texture via OpenGL. However, when specifying the formats and data itself through glTexImage3D, an GL_INVALID_OPERATION error is thrown.
The code (including the debugging code I added to find out where the error was comming from) is the following:
void Texture3D::upload()
{
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glGenTextures(1, &_textureId);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glBindTexture(GL_TEXTURE_3D, _textureId);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glTexStorage3D(GL_TEXTURE_3D, 6, GL_R8, _width, _height, _depth);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glTexImage3D(GL_TEXTURE_3D, 0, GL_R8, _width, _height, _depth, 0, GL_RED, GL_UNSIGNED_BYTE, _data);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glGenerateMipmap(GL_TEXTURE_3D);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
}
I thought it might be an GL_INVALID_VALUE for any of the format, internal format, or pixel format I am specifying in the glTexImage3D, however I have checked with the documentation of glTexImage3D and everything seems correct.
I have created a minimal, verifiable example (using GLFW and GLEW)
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
GLFWwindow * _window = nullptr;
unsigned int _textureId = GL_INVALID_VALUE;
void initGLFWContext()
{
if (!glfwInit())
{
std::cerr << "GLFW: Couldnt initialize" << std::endl;
exit(-1);
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
_window = glfwCreateWindow(1024, 1024, "Test Window", NULL, NULL);
if (!_window)
{
std::cerr << "GLFW Error: Couldnt create window" << std::endl;
glfwTerminate();
exit(-1);
}
//glfwSetKeyCallback(_window, kbCb);
//glfwSetCursorPosCallback(_window, mmCb);
//glfwSetMouseButtonCallback(_window, mCb);
//glfwSetFramebufferSizeCallback(_window, resizeCb);
glfwMakeContextCurrent(_window);
glfwSetWindowPos(_window, 0, 0);
glfwSwapInterval(1);
// Initializes glew
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
std::cerr << "GLEW Error: " << glewGetErrorString(err) << std::endl;
exit(-1);
}
}
void initOpenGL()
{
glEnable(GL_DEPTH_TEST);
//glEnable(GL_BLEND);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glFrontFace(GL_CCW);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_CULL_FACE);
}
void minimalVerifiableExample()
{
initGLFWContext();
initOpenGL();
const unsigned int volSide = 256;
const unsigned int volumeSize = volSide * volSide * volSide;
unsigned char * volumeData = new unsigned char[volumeSize]();
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glGenTextures(1, &_textureId);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glBindTexture(GL_TEXTURE_3D, _textureId);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glTexStorage3D(GL_TEXTURE_3D,
6,
GL_R8,
volSide,
volSide,
volSide);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glTexImage3D(GL_TEXTURE_3D,
0,
GL_R8,
volSide,
volSide,
volSide,
0,
GL_RED,
GL_UNSIGNED_BYTE,
volumeData);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
glGenerateMipmap(GL_TEXTURE_3D);
std::cout << "TEX GL ERROR: " << glGetError() << std::endl;
while(!glfwWindowShouldClose(_window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwPollEvents();
glfwSwapBuffers(_window);
}
glfwDestroyWindow(_window);
glfwTerminate();
delete[] volumeData;
}
int main(int argc, char ** argv)
{
(void) argc;
(void) argv;
minimalVerifiableExample();
return 0;
}
And this is the output I get:
TEX GL ERROR: 0
TEX GL ERROR: 0
TEX GL ERROR: 0
TEX GL ERROR: 0
TEX GL ERROR: 1282
TEX GL ERROR: 0
Am I doing something wrong when uploading the texture or anywhere else?
1282 is a GL_INVALID_OPERATION and is caused by the combination of
glTexStorage3D
glTexImage3D
It is not allowed to recreate the storage for an immutable storage texture object. After calling glTexStorage3D, the texture uses immutable storage. glTexImage3D requests a new storage which is not allowed anymore.
If you try to upload data to the immutable storage texture object, you'll have to use glTexSubImage3D instead which will upload data but not request new storage.
I am trying to load a orthographic projection matrix into a shader, but when I go to run the code and I click around in the window I end up with all the points going to (0,0,0) which I'm guessing is being caused by the uniform matrix never being setup and as a result everything is being multiplied by 0. I am using Qt, OpenGL and GLM for this. Any ideas why this would be happening?
I have been debugging it a little and it seems to be having issues at the point where I'm loading the matrix into the shader in resizeGL and initializeGL, not sure of the cause though.
Thanks in advance!
My Class handling all of the OpenGL Stuff:
GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent), outline(false), drawMode(0) {
num_pts = 0;
drawMode = GL_POINTS;
next = 1;
ortho = glm::ortho(0.0f, 640.0f, 480.0f, 0.0f);
}
GLWidget::~GLWidget() {
}
void GLWidget::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_C:
cout << "Cleared all the points." << endl;
num_pts = 0;
pts.clear();
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_DYNAMIC_DRAW);
break;
case Qt::Key_W:
outline = !outline;
if (outline) {
cout << "Displaying outlines." << endl;
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else {
cout << "Displaying filled polygons." << endl;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
break;
case Qt::Key_Space:
switch (next) {
case(0):
drawMode = GL_POINTS;
cout << "drawMode is GL_POINTS" << endl;
next = 1;
break;
case(1):
drawMode = GL_LINES;
cout << "drawMode is GL_LINES" << endl;
next = 2;
break;
case(2):
drawMode = GL_LINE_STRIP;
cout << "drawMode is GL_LINE_STRIP" << endl;
next = 3;
break;
case(3):
drawMode = GL_LINE_LOOP;
cout << "drawMode is GL_LINE_LOOP" << endl;
next = 4;
break;
case(4):
drawMode = GL_TRIANGLES;
cout << "drawMode is GL_TRIANGLES" << endl;
next = 5;
break;
case(5):
drawMode = GL_TRIANGLE_STRIP;
cout << "drawMode is GL_TRIANGLE_STRIP" << endl;
next = 6;
break;
case(6):
drawMode = GL_TRIANGLE_FAN;
cout << "drawMode is GL_TRIANGLE_FAN" << endl;
next = 0;
break;
}
break;
case Qt::Key_P:
cout << "Projection Location: " << projectionMatrixLoc << endl << endl;
cout << "Projection Matrix:" << endl << endl;
cout << "------------" << endl;
cout << ortho[0][0] << " ";
cout << ortho[1][0] << " ";
cout << ortho[2][0] << " ";
cout << ortho[3][0] << endl;
cout << "------------" << endl;
cout << ortho[0][1] << " ";
cout << ortho[1][1] << " ";
cout << ortho[2][1] << " ";
cout << ortho[3][1] << endl;
cout << "------------" << endl;
cout << ortho[0][2] << " ";
cout << ortho[1][2] << " ";
cout << ortho[2][2] << " ";
cout << ortho[3][2] << endl;
cout << "------------" << endl;
cout << ortho[0][3] << " ";
cout << ortho[1][3] << " ";
cout << ortho[2][3] << " ";
cout << ortho[3][3] << endl;
cout << "------------" << endl << endl << endl;
break;
}
update();
}
void GLWidget::mousePressEvent(QMouseEvent *event) {
glm::vec2 temp = glm::vec2(0.0);
temp.x = event->x();
temp.y = event->y();
pts.push_back(temp);
cout << "Added point (" << pts.back().x << ", " << pts.back().y << ") " << endl;
cout << "Number of points: " << pts.size() << endl;
num_pts++;
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, pts.size(), &pts, GL_DYNAMIC_DRAW);
update();
}
void GLWidget::initializeGL() {
initializeOpenGLFunctions();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glPointSize(4.0f);
// Create a new Vertex Array Object on the GPU which
// saves the attribute layout of our vertices.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create a buffer on the GPU for position data
glGenBuffers(1, &positionBuffer);
// Upload the position data to the GPU, storing
// it in the buffer we just allocated.
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_DYNAMIC_DRAW);
// Load our vertex and fragment shaders into a program object
// on the GPU
program = loadShaders(":/vert.glsl", ":/frag.glsl");
// Bind the attribute "position" (defined in our vertex shader)
// to the currently bound buffer object, which contains our
// position data for a single triangle. This information
// is stored in our vertex array object.
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
GLint positionIndex = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(positionIndex);
glVertexAttribPointer(positionIndex, 2, GL_FLOAT, GL_FALSE, 0, 0);
glUseProgram(program);
projectionMatrixLoc = glGetUniformLocation(program, "ProjectionMatrix");
glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, glm::value_ptr(ortho));
}
void GLWidget::resizeGL(int w, int h) {
glViewport(0, 0, w, h);
ortho = glm::ortho(0.0f, (float)w, (float)h, 0.0f);
glUseProgram(program);
// problem area?
glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, glm::value_ptr(ortho));
}
void GLWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
// draw primitives based on the current draw mode
glDrawArrays(drawMode, 0, num_pts);
// draw points so we can always see them
// glPointSize adjusts the size of point
// primitives
glDrawArrays(GL_POINTS, 0, num_pts);
}
// Copied from LoadShaders.cpp in the the oglpg-8th-edition.zip
// file provided by the OpenGL Programming Guide, 8th edition.
const GLchar* GLWidget::readShader(const char* filename) {
#ifdef WIN32
FILE* infile;
fopen_s(&infile, filename, "rb");
#else
FILE* infile = fopen(filename, "rb");
#endif // WIN32
if (!infile) {
#ifdef _DEBUG
std::cerr << "Unable to open file '" << filename << "'" << std::endl;
#endif /* DEBUG */
return NULL;
}
fseek(infile, 0, SEEK_END);
int len = ftell(infile);
fseek(infile, 0, SEEK_SET);
GLchar* source = new GLchar[len + 1];
fread(source, 1, len, infile);
fclose(infile);
source[len] = 0;
return const_cast<const GLchar*>(source);
}
GLuint GLWidget::loadShaders(const char* vertf, const char* fragf) {
GLuint program = glCreateProgram();
// read vertex shader from Qt resource file
QFile vertFile(vertf);
vertFile.open(QFile::ReadOnly | QFile::Text);
QString vertString;
QTextStream vertStream(&vertFile);
vertString.append(vertStream.readAll());
std::string vertSTLString = vertString.toStdString();
const GLchar* vertSource = vertSTLString.c_str();
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertShader, 1, &vertSource, NULL);
glCompileShader(vertShader);
{
GLint compiled;
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLsizei len;
glGetShaderiv(vertShader, GL_INFO_LOG_LENGTH, &len);
GLchar* log = new GLchar[len + 1];
glGetShaderInfoLog(vertShader, len, &len, log);
std::cout << "Shader compilation failed: " << log << std::endl;
delete[] log;
}
}
glAttachShader(program, vertShader);
// read fragment shader from Qt resource file
QFile fragFile(fragf);
fragFile.open(QFile::ReadOnly | QFile::Text);
QString fragString;
QTextStream fragStream(&fragFile);
fragString.append(fragStream.readAll());
std::string fragSTLString = fragString.toStdString();
const GLchar* fragSource = fragSTLString.c_str();
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShader, 1, &fragSource, NULL);
glCompileShader(fragShader);
{
GLint compiled;
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLsizei len;
glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &len);
GLchar* log = new GLchar[len + 1];
glGetShaderInfoLog(fragShader, len, &len, log);
std::cerr << "Shader compilation failed: " << log << std::endl;
delete[] log;
}
}
glAttachShader(program, fragShader);
glLinkProgram(program);
{
GLint linked;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (!linked) {
GLsizei len;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
GLchar* log = new GLchar[len + 1];
glGetProgramInfoLog(program, len, &len, log);
std::cout << "Shader linker failed: " << log << std::endl;
delete[] log;
}
}
return program;
}
The Header File:
#ifndef __GLWIDGET__INCLUDE__
#define __GLWIDGET__INCLUDE__
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QMouseEvent>
#include <glm/glm.hpp>
#include <vector>
// glm by default uses degrees, but that functionality
// is deprecated so GLM_FORCE_RADIANS turns off some
// glm warnings
#define GLM_FORCE_RADIANS
using glm::vec2;
class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core {
Q_OBJECT
public:
GLWidget(QWidget *parent = 0);
~GLWidget();
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
void mousePressEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
private:
GLuint loadShaders(const char* vertf, const char* fragf);
static const GLchar* readShader(const char* filename);
GLuint vao;
GLuint program;
GLuint positionBuffer;
GLint projectionMatrixLoc;
bool outline;
GLenum drawMode;
glm::mat4 ortho;
int next;
std::vector<vec2> pts;
int num_pts;
};
#endif
My Vertex Shader:
#version 330
in vec2 position;
uniform mat4 ProjectionMatrix;
void main() {
gl_Position = vec4(position.x, position.y, 0, 1)*ProjectionMatrix;
}
My Fragment Shader:
#version 330
out vec4 color_out;
void main() {
color_out = vec4(1.0,1.0,1.0,1.0);
}
I wrote this little function to init a shader while trying to get the hang of GLSL.
void createShader(string code, GLuint type) {
GLint success;
GLuint errorLogSize = 1024;
vector<GLchar> errorLog(errorLogSize);
cout << "trying to add shader, shader version is " << glGetString(GL_SHADING_LANGUAGE_VERSION) << " and opengl version is " << glGetString(GL_VERSION) << endl;
GLuint program = glCreateProgram();
GLuint obj = glCreateShader(type);
if (obj == 0) {
cout << "failed to create shader" << endl;
return;
} else {
cout << "created shader" << endl;
}
const GLchar* p = code.c_str();
GLint length = strlen(code.c_str());
cout << "trying to compile shader:" << endl << p << endl << "length: " << length << endl;
glShaderSource(obj, 1, &p, &length);
glCompileShader(obj);
glGetShaderiv(obj, GL_COMPILE_STATUS, &success);
if (success == 0) {
glGetProgramInfoLog(program, errorLogSize, NULL, &errorLog[0]);
cout << "error in shader compiling" << endl;
for (auto c : errorLog) cout << c;
cout << endl;
glGetShaderInfoLog(program, errorLogSize, NULL, &errorLog[0]);
for (auto c : errorLog) cout << c;
cout << endl;
}
glAttachShader(program, obj);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (success == 0) {
glGetProgramInfoLog(program, errorLogSize, NULL, &errorLog[0]);
cout << "error in shader linking" << endl;
for (auto c : errorLog) cout << c;
cout << endl;
glGetShaderInfoLog(program, errorLogSize, NULL, &errorLog[0]);
for (auto c : errorLog) cout << c;
cout << endl;
}
glValidateProgram(program);
glGetProgramiv(program, GL_VALIDATE_STATUS, &success);
if (success == 0) {
glGetProgramInfoLog(program, errorLogSize, NULL, &errorLog[0]);
cout << "error in shader validating" << endl;
for (auto c : errorLog) cout << c;
cout << endl;
glGetShaderInfoLog(program, errorLogSize, NULL, &errorLog[0]);
for (auto c : errorLog) cout << c;
cout << endl;
}
glUseProgram(program);
}
I call it like this:
createShader("#version 150 out vec4 colorOut; void main() { colorOut = vec4(1.0, 0.0, 0.0, 1.0); }", GL_FRAGMENT_SHADER);
When I run the program it outputs this:
trying to add shader, shader version is 4.30 and opengl version is 4.4.12874 Compatibility Profile Context 14.100.0.0
created shader
trying to compile shader:
#version 150 out vec4 colorOut; void main() { colorOut = vec4(1.0, 0.0, 0.0, 1.0); }
length: 84
error in shader compiling
error in shader linking
Fragment shader(s) were not successfully compiled before glLinkProgram() was called. Link failed.
Fragment shader(s) were not successfully compiled before glLinkProgram() was called. Link failed.
error in shader validating
Fragment shader(s) were not successfully compiled before glLinkProgram() was called. Link failed.
Fragment shader(s) were not successfully compiled before glLinkProgram() was called. Link failed.
So pretty much all this tells me is that it can't compile. But I can't seem to find out why. I tried searching for similar situations (error in compilation but nothing in the log), but couldn't find anything relevant.
I expected this code to at least compile the shader. I used this guide as a guideline. The code I'm using is almost 1 on 1 copied from that guide. The only difference is they implemented it in two different functions and I added some extra error handling while trying to find out what's wrong with my code.
I'm using freeglut to init my window and I included, linked and initialized glew.
You need a newline character (\n) at the end of the #version 150. Everything starting with a # is a preprocessor directive, and the preprocessor operates line by line.
Change it to this, and it should work:
createShader("#version 150\n out vec4 colorOut; void main() { colorOut = vec4(1.0, 0.0, 0.0, 1.0); }", GL_FRAGMENT_SHADER);
You probably would have seen a more or less meaningful error message from the shader compiler, if there wasn't a minor mistake in the code that gets the shader info log:
glGetShaderInfoLog(program, errorLogSize, NULL, &errorLog[0]);
The first argument to glGetShaderInfoLog() is the shader, not the program. With the variable naming in the provided code, this should be:
glGetShaderInfoLog(obj, errorLogSize, NULL, &errorLog[0]);
I am trying to hide the marker im artoolkit and in my research i found this code for alvar, it's a free AR toolkit made by a research technical center in finland.
This code helps hiding the marker but its in opencv, but i want to do the same in simpleVRML example.
Any help how can i change this code for the artoolkit example?
#include "CvTestbed.h"
#include "MarkerDetector.h"
#include "GlutViewer.h"
#include "Shared.h"
using namespace alvar;
using namespace std;
#define GLUT_DISABLE_ATEXIT_HACK // Needed to compile with Mingw?
#include <GL/gl.h>
const double margin = 1.0;
std::stringstream calibrationFilename;
// Own drawable for showing hide-texture in OpenGL
struct OwnDrawable : public Drawable {
unsigned char hidingtex[64*64*4];
virtual void Draw() {
glPushMatrix();
glMultMatrixd(gl_mat);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glEnable(GL_TEXTURE_2D);
int tex=0;
glBindTexture(GL_TEXTURE_2D, tex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,64,64,0,GL_RGBA,GL_UNSIGNED_BYTE,hidingtex);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3d(-margin,-margin,0);
glTexCoord2d(0.0,1.0);
glVertex3d(-margin,margin,0);
glTexCoord2d(1.0,1.0);
glVertex3d(margin,margin,0);
glTexCoord2d(1.0,0.0);
glVertex3d(margin,-margin,0);
glEnd();
glPopAttrib();
glPopMatrix();
}
};
void videocallback(IplImage *image)
{
static bool init=true;
static const int marker_size=15;
static Camera cam;
static OwnDrawable d[32];
static IplImage *hide_texture;
bool flip_image = (image->origin?true:false);
if (flip_image) {
cvFlip(image);
image->origin = !image->origin;
}
static IplImage* bg_image = 0;
if(!bg_image) bg_image = cvCreateImage(cvSize(512, 512), 8, 3);
if(image->nChannels == 3)
{
bg_image->origin = 0;
cvResize(image, bg_image);
GlutViewer::SetVideo(bg_image);
}
if (init) {
init = false;
cout<<"Loading calibration: "<<calibrationFilename.str();
if (cam.SetCalib(calibrationFilename.str().c_str(), image->width, image->height)) {
cout<<" [Ok]"<<endl;
} else {
cam.SetRes(image->width, image->height);
cout<<" [Fail]"<<endl;
}
double p[16];
cam.GetOpenglProjectionMatrix(p,image->width,image->height);
GlutViewer::SetGlProjectionMatrix(p);
hide_texture = CvTestbed::Instance().CreateImage("hide_texture", cvSize(64, 64), 8, 4);
}
static MarkerDetector<MarkerData> marker_detector;\
marker_detector.Detect(image, &cam, false, false);
GlutViewer::DrawableClear();
for (size_t i=0; i<marker_detector.markers->size(); i++) {
if (i >= 32) break;
GlutViewer::DrawableAdd(&(d[i]));
}
for (size_t i=0; i<marker_detector.markers->size(); i++) {
if (i >= 32) break;
// Note that we need to mirror both the y- and z-axis because:
// - In OpenCV we have coordinates: x-right, y-down, z-ahead
// - In OpenGL we have coordinates: x-right, y-up, z-backwards
// TODO: Better option might be to use OpenGL projection matrix that matches our OpenCV-approach
Pose p = (*(marker_detector.markers))[i].pose;
BuildHideTexture(image, hide_texture, &cam, d[i].gl_mat, PointDouble(-margin, -margin), PointDouble(margin, margin));
//DrawTexture(image, hide_texture, &cam, d[i].gl_mat, PointDouble(-0.7, -0.7), PointDouble(0.7, 0.7));
p.GetMatrixGL(d[i].gl_mat);
for (int ii=0; ii<64*64; ii++) {
d[i].hidingtex[ii*4+0] = hide_texture->imageData[ii*4+2];
d[i].hidingtex[ii*4+1] = hide_texture->imageData[ii*4+1];
d[i].hidingtex[ii*4+2] = hide_texture->imageData[ii*4+0];
d[i].hidingtex[ii*4+3] = hide_texture->imageData[ii*4+3];
}
}
if (flip_image) {
cvFlip(image);
image->origin = !image->origin;
}
}
int main(int argc, char *argv[])
{
try {
// Output usage message
std::string filename(argv[0]);
filename = filename.substr(filename.find_last_of('\\') + 1);
std::cout << "SampleMarkerHide" << std::endl;
std::cout << "================" << std::endl;
std::cout << std::endl;
std::cout << "Description:" << std::endl;
std::cout << " This is an example of how to detect 'MarkerData' markers, similarly" << std::endl;
std::cout << " to 'SampleMarkerDetector', and hide them using the 'BuildHideTexture'" << std::endl;
std::cout << " and 'DrawTexture' classes." << std::endl;
std::cout << std::endl;
std::cout << "Usage:" << std::endl;
std::cout << " " << filename << " [device]" << std::endl;
std::cout << std::endl;
std::cout << " device integer selecting device from enumeration list (default 0)" << std::endl;
std::cout << " highgui capture devices are prefered" << std::endl;
std::cout << std::endl;
std::cout << "Keyboard Shortcuts:" << std::endl;
std::cout << " q: quit" << std::endl;
std::cout << std::endl;
// Initialise GlutViewer and CvTestbed
GlutViewer::Start(argc, argv, 640, 480, 15);
CvTestbed::Instance().SetVideoCallback(videocallback);
// Enumerate possible capture plugins
CaptureFactory::CapturePluginVector plugins = CaptureFactory::instance()->enumeratePlugins();
if (plugins.size() < 1) {
std::cout << "Could not find any capture plugins." << std::endl;
return 0;
}
// Display capture plugins
std::cout << "Available Plugins: ";
outputEnumeratedPlugins(plugins);
std::cout << std::endl;
// Enumerate possible capture devices
CaptureFactory::CaptureDeviceVector devices = CaptureFactory::instance()->enumerateDevices();
if (devices.size() < 1) {
std::cout << "Could not find any capture devices." << std::endl;
return 0;
}
// Check command line argument for which device to use
int selectedDevice = defaultDevice(devices);
if (argc > 1) {
selectedDevice = atoi(argv[1]);
}
if (selectedDevice >= (int)devices.size()) {
selectedDevice = defaultDevice(devices);
}
// Display capture devices
std::cout << "Enumerated Capture Devices:" << std::endl;
outputEnumeratedDevices(devices, selectedDevice);
std::cout << std::endl;
// Create capture object from camera
Capture *cap = CaptureFactory::instance()->createCapture(devices[selectedDevice]);
std::string uniqueName = devices[selectedDevice].uniqueName();
// Handle capture lifecycle and start video capture
// Note that loadSettings/saveSettings are not supported by all plugins
if (cap) {
std::stringstream settingsFilename;
settingsFilename << "camera_settings_" << uniqueName << ".xml";
calibrationFilename << "camera_calibration_" << uniqueName << ".xml";
cap->start();
if (cap->loadSettings(settingsFilename.str())) {
std::cout << "Loading settings: " << settingsFilename.str() << std::endl;
}
std::stringstream title;
title << "SampleMarkerHide (" << cap->captureDevice().captureType() << ")";
CvTestbed::Instance().StartVideo(cap, title.str().c_str());
if (cap->saveSettings(settingsFilename.str())) {
std::cout << "Saving settings: " << settingsFilename.str() << std::endl;
}
cap->stop();
delete cap;
}
else if (CvTestbed::Instance().StartVideo(0, argv[0])) {
}
else {
std::cout << "Could not initialize the selected capture backend." << std::endl;
}
return 0;
}
catch (const std::exception &e) {
std::cout << "Exception: " << e.what() << endl;
}
catch (...) {
std::cout << "Exception: unknown" << std::endl;
}
}