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);
}
Related
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);
It says "an array cannot be initialized with a parenthesized initializer", which I'm not quiet sure I understand... So, can someone explain what is causing it, why and how I fix it? Please?
(By the way, I'm sort of new to memory c++, so be gentle please?)
What I'm trying to accomplish is for a mesh to be generated by an obj file. And to be honest I'm not that great at it. So sorry!
Mesh.h --------------------------------------------------------------
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <vector>
#include "../Shader/Shader.h"
struct Vertex
{
float Position[3];
float Uv[2];
float Normal[3];
};
class Mesh
{
private:
unsigned int VAO, VBO; // Vertex Array Object ID
unsigned int TextureID; // Texture ID
unsigned int size;
const char* objFilePath;
const char* textureFilePath;
Shader& shader;
public:
Mesh(const char* objFilePath, const char* textureFilePath, Shader& shader);
void draw();
};
Mesh.cpp --------------------------------------------------------------
#include "Mesh.h"
void fillVerticesWithData(std::vector<float> data, std::vector<Vertex> info);
Mesh::Mesh(const char* objFilePath, const char* textureFilePath, Shader& shader)
: objFilePath(objFilePath), textureFilePath(textureFilePath), shader(shader)
{
{
// Load Vertices from File!
std::vector<Vertex> vertices;
{
std::vector<float[3]> filePos; // Position(s)
std::vector<float[2]> fileUV; // Uv(s)
std::vector<float[3]> fileNorm; // Normal(s)
std::ifstream file;
file.open(objFilePath);
std::string line;
while (std::getline(file, line))
{
std::string text;
std::istringstream iss(line);
iss >> text;
// Easy part!
if (text == "v")
{
float currectPos[3];
iss >> currectPos[0];
iss >> currectPos[1];
iss >> currectPos[2];
filePos.push_back(currectPos);
}
if (text == "vt")
{
float currectUV[2];
iss >> currectUV[0];
iss >> currectUV[1];
fileUV.push_back(currectUV);
}
if (text == "vn")
{
float currectNorm[3];
iss >> currectNorm[0];
iss >> currectNorm[1];
iss >> currectNorm[2];
fileNorm.push_back(currectNorm);
}
// Last part, hard part!
if (text == "f")
{
int x, y, z;
int x2, y2, z2;
int x3, y3, z3;
char e;
// First Vertex!
iss >> x;
iss >> e;
iss >> y;
iss >> e;
iss >> z;
iss >> x2;
iss >> e;
iss >> y2;
iss >> e;
iss >> z2;
iss >> x3;
iss >> e;
iss >> y3;
iss >> e;
iss >> z3;
Vertex temp_Vertex;
for (int i = 0; i < 3; i++)
{
temp_Vertex.Position[i] = filePos.at(x - 1)[i];
temp_Vertex.Normal[i] = fileNorm.at(y - 1)[i];
}
for (int i = 0; i < 2; i++)
{
temp_Vertex.Uv[i] = fileUV.at(z - 1)[i];
}
vertices.push_back(temp_Vertex);
std::cout << "Vertex 1 -----------" << std::endl;
std::cout << "Position: " << temp_Vertex.Position[0] << " " << temp_Vertex.Position[1] << " " << temp_Vertex.Position[2] << std::endl;
std::cout << "UV: " << temp_Vertex.Uv[0] << " " << temp_Vertex.Uv[1] << std::endl;
std::cout << "Normal: " << temp_Vertex.Normal[0] << " " << temp_Vertex.Normal[1] << temp_Vertex.Normal[2] << std::endl;
// Second Vertex!
Vertex temp_Vertex2;
for (int i = 0; i < 3; i++)
{
temp_Vertex2.Position[i] = filePos.at(x2 - 1)[i];
temp_Vertex2.Normal[i] = fileNorm.at(y2 - 1)[i];
}
for (int i = 0; i < 2; i++)
{
temp_Vertex2.Uv[i] = fileUV.at(z2 - 1)[i];
}
vertices.push_back(temp_Vertex2);
std::cout << "Vertex 1 -----------" << std::endl;
std::cout << "Position: " << temp_Vertex2.Position[0] << " " << temp_Vertex2.Position[1] << " " << temp_Vertex2.Position[2] << std::endl;
std::cout << "UV: " << temp_Vertex2.Uv[0] << " " << temp_Vertex2.Uv[1] << std::endl;
std::cout << "Normal: " << temp_Vertex2.Normal[0] << " " << temp_Vertex2.Normal[1] << temp_Vertex2.Normal[2] << std::endl;
// Third Vertex
Vertex temp_Vertex3;
for (int i = 0; i < 3; i++)
{
temp_Vertex3.Position[i] = filePos.at(x3 - 1)[i];
temp_Vertex3.Normal[i] = fileNorm.at(y3 - 1)[i];
}
for (int i = 0; i < 2; i++)
{
temp_Vertex3.Uv[i] = fileUV.at(z3 - 1)[i];
}
vertices.push_back(temp_Vertex3);
std::cout << "Vertex 1 -----------" << std::endl;
std::cout << "Position: " << temp_Vertex3.Position[0] << " " << temp_Vertex3.Position[1] << " " << temp_Vertex3.Position[2] << std::endl;
std::cout << "UV: " << temp_Vertex3.Uv[0] << " " << temp_Vertex3.Uv[1] << std::endl;
std::cout << "Normal: " << temp_Vertex3.Normal[0] << " " << temp_Vertex3.Normal[1] << temp_Vertex3.Normal[2] << std::endl;
// Face!!! :O
// This one here I am having trouble with
// How do I read it?
}
}
}
// Load Texture from File!
// Last step:
std::vector<float> vertexArray;
fillVerticesWithData(vertexArray, vertices);
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexArray.size() * sizeof(float), &vertexArray[0], GL_STATIC_DRAW);
// Position Pointer:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)3);
glEnableVertexAttribArray(1);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)5);
glEnableVertexAttribArray(3);
// Unbinding everything:
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
size = vertexArray.size();
}
}
void Mesh::draw()
{
shader.use();
glBindVertexArray(VAO);
// glBindTexture(GL_TEXTURE_2D, TextureID);
// Later:
// Draw Elements
// For now:
glDrawArrays(GL_TRIANGLES, 0, size);
}
// data is the data we wanna fill with information!
// The info has the information we want to put into data!
void fillVerticesWithData(std::vector<float> data, std::vector<Vertex> info)
{
for (int i = 0; i < info.size(); i++)
{
// Position:
for (int posI = 0; posI < 3; posI++)
{
float temp[3];
temp[posI] = info.at(i).Position[posI];
data.push_back(temp[posI]);
}
// Uv:
for (int uvI = 0; uvI < 2; uvI++)
{
float temp[2];
temp[uvI] = info.at(i).Uv[uvI];
data.push_back(temp[uvI]);
}
// Normal:
for (int norI = 0; norI < 3; norI++)
{
float temp[3];
temp[norI] = info.at(i).Normal[norI];
data.push_back(temp[norI]);
}
}
}
Anyway, thanks for checking out this post/question, even if it just reading.
I appreciate any help I can get! (And I've been working on loading this mesh thing for a long time and I just want to be done with it)
I hope you're having a nice day! (Or night, lol) :)
The elements of a std::vector have to be copyable and assignable. Arrays are not copyable and assignable.
I recommend to use std::array:
std::vector<std::array<float, 3>> filePos; // Position(s)
std::vector<std::array<float, 2>> fileUV; // Uv(s)
std::vector<std::array<float, 3>> fileNorm; // Normal(s)
std::array<float, 3> currectPos;
std::array<float, 2> currectUV;
std::array<float, 3> currectNorm;
Furthermore, if a named buffer object is bound, then the last parameter of glVertexAttribPointer is treated as a byte offset into the buffer object's data store:
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)3);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float)*3));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)5);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float)*5));
You can't use a native c array as the template argument for std::vector<>.
Use a std::array<3> instead
Like so: std::vector<std::array<float,3>>
You can also use a pointer to three float that's fine.
This was my vertex shader before it was corrupt:
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 m;
uniform mat4 v;
uniform mat4 p;
out vec2 texPos;
void main() {
gl_Position = p * v * m * vec4(aPos, 1.0);
texPos = vec2(0, 0);
}
And this is my vertex shader after it was corrupt:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexPos;
uniform mat4 m;
uniform mat4 v;
uniform mat4 p;
out vec2 texPos;
void main() {
gl_Position = p * v * m * vec4(aPos, 1.0);
texPos = vec2(0, 0);
}
The difference between them is just a layout (location = 1) in vec2 aTexPos. How and why did this 'corruption' happen?
EDIT: here's the loadProgram function that is used to load the shaders:
GLuint Framework::loadProgram(string vpath, string fpath) {
GLuint v, f;
stringstream ss;
char log[512];
v = glCreateShader(GL_VERTEX_SHADER);
fstream vf(vpath);
if (vf.good()) {
ss << vf.rdbuf();
const GLchar* g = ss.str().c_str();
glShaderSource(v, 1, &g, nullptr);
glCompileShader(v);
glGetShaderInfoLog(v, 512, nullptr, log);
cout << "Vertex Shader: " << log << endl;
} else {
cout << "Bad path " << vpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
ss.str("");
f = glCreateShader(GL_FRAGMENT_SHADER);
fstream ff(fpath);
if (ff.good()) {
ss << ff.rdbuf();
const GLchar* g = ss.str().c_str();
glShaderSource(f, 1, &g, nullptr);
glCompileShader(f);
glGetShaderInfoLog(f, 512, nullptr, log);
cout << "Fragment Shader: " << log << endl;
} else {
cout << "Bad path " << fpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
GLuint prog;
prog = glCreateProgram();
glAttachShader(prog, v);
glAttachShader(prog, f);
glLinkProgram(prog);
glGetProgramInfoLog(prog, 512, nullptr, log);
cout << "Program: " << log;
glDeleteShader(v);
glDeleteShader(f);
return prog;
}
It just says it's corrupted... And I have no idea where it had gone wrong.
Here's what I got when I run the program:
Vertex Shader:
Fragment Shader:
Program: ERROR: Compiled vertexshader was corrupt.
Problem solved.
It's the problem of the loadProgram function, that vertex shader's ss.str().c_str() return a single '\0' character. I have no idea why fragment shader's string stream works well, though.
So here's the code now:
GLuint Framework::loadProgram(string vpath, string fpath) {
GLuint v, f;
stringstream ss;
char log[512];
v = glCreateShader(GL_VERTEX_SHADER);
fstream vf(vpath);
if (vf.good()) {
ss << vf.rdbuf();
string str = ss.str();
const GLchar* g = str.c_str();
glShaderSource(v, 1, &g, nullptr);
glCompileShader(v);
glGetShaderInfoLog(v, 512, nullptr, log);
cout << "Vertex Shader: " << log << endl;
} else {
cout << "Bad path " << vpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
ss.str("");
f = glCreateShader(GL_FRAGMENT_SHADER);
fstream ff(fpath);
if (ff.good()) {
ss << ff.rdbuf();
string str = ss.str();
const GLchar* g = str.c_str();
glShaderSource(f, 1, &g, nullptr);
glCompileShader(f);
glGetShaderInfoLog(f, 512, nullptr, log);
cout << "Fragment Shader: " << log << endl;
} else {
cout << "Bad path " << fpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
GLuint prog;
prog = glCreateProgram();
glAttachShader(prog, v);
glAttachShader(prog, f);
glLinkProgram(prog);
glGetProgramInfoLog(prog, 512, nullptr, log);
cout << "Program: " << log;
glDeleteShader(v);
glDeleteShader(f);
return prog;
}
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;
}
}