I have a program like below:
#include <iostream>
#include <fstream>
#include <sstream>
#include <gl/glew.h>
#include <gl/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
GLuint prog, verShader, fragShader;
GLint attrPos, attrNor;
GLint uniModelView, uniProjection, uniModelViewTransposeInverse;
glm::mat4 modelMatrix, viewMatrix, projectionMatrix, MV, MVP;
glm::mat3 MVI;
const string loadFile(string name)
{
ifstream in(name.c_str(), ios::in);
if (in.fail()) {
cout << "File: '" << name << "' could not exist!!" << endl;
return "";
}
stringstream data;
data << in.rdbuf();
in.close();
return data.str();
}
GLuint createShader(GLenum type, const string name)
{
GLint isCompileOk;
GLuint shader;
string shaderText, shaderType;
const char *shaderSource;
switch(type)
{
case GL_VERTEX_SHADER:
shaderType = "GL_VERTEX_SHADER";
break;
case GL_FRAGMENT_SHADER:
shaderType = "GL_FRAGMENT_SHADER";
break;
}
shaderText = loadFile(name);
shaderSource = shaderText.c_str();
shader = glCreateShader(type);
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompileOk);
if (isCompileOk == GL_FALSE) {
char *shaderErr;
int errLength, errRetrieve;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &errLength);
shaderErr = new char [errLength + 1];
glGetShaderInfoLog(shader, errLength, &errRetrieve, shaderErr);
cout << "Compile '" << shaderType << "' error:" << endl;
cout << shaderErr << endl;
delete [] shaderErr;
return 0;
} else {
cout << "Compile '" << shaderType << "' ok!" << endl;
}
return shader;
}
bool makeShader()
{
GLint isLinkOk;
verShader = createShader(GL_VERTEX_SHADER, "vert.glsl");
fragShader = createShader(GL_FRAGMENT_SHADER, "frag.glsl");
prog = glCreateProgram();
glAttachShader(prog, verShader);
glAttachShader(prog, fragShader);
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &isLinkOk);
if (isLinkOk == GL_FALSE) {
char *progErr;
int errLenght, errRetrieve;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &errLenght);
progErr = new char[errLenght + 1];
glGetProgramInfoLog(prog, errLenght, &errRetrieve, progErr);
cout << "Link program error:" << endl;
cout << progErr << endl;
delete [] progErr;
return false;
} else {
cout << "Link program Ok!" << endl;
}
attrPos = glGetAttribLocation(prog, "position");
uniModelView = glGetUniformLocation(prog, "ModelViewMatrix");
uniProjection = glGetUniformLocation(prog, "ProjectionMatrix");
uniModelViewTransposeInverse = glGetUniformLocation(prog, "ModelViewTransposeInverseMatrix");
return true;
}
float vertexs[] = {
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f
};
unsigned short indicates[] = {
0, 1, 2,
2, 3, 0
};
GLuint vao, vbo, ibo;
void display()
{
MV = viewMatrix * modelMatrix;
MVP = projectionMatrix * MV;
MVI = glm::transpose(glm::inverse(glm::mat3(MV)));
glUseProgram(prog);
glUniformMatrix4fv(uniModelView, 1, GL_FALSE, glm::value_ptr(MV));
glUniformMatrix3fv(uniModelViewTransposeInverse, 1, GL_FALSE, glm::value_ptr(MVI));
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, sizeof(indicates)/sizeof(unsigned short), GL_UNSIGNED_SHORT, 0);
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
projectionMatrix = glm::perspective(45.0f, float(w)/h, 0.1f, 1000.0f);
glUseProgram(prog);
glUniformMatrix4fv(uniProjection, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
}
void idle()
{
glutPostRedisplay();
}
void Init()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
modelMatrix = glm::mat4(1.0f);
viewMatrix = glm::lookAt(
glm::vec3(0.0f, 5.0f, 10.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)
);
projectionMatrix = glm::mat4(1.0f);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs), vertexs, GL_STATIC_DRAW);
glVertexAttribPointer(attrPos, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0);
glEnableVertexAttribArray(attrPos);
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicates), indicates, GL_STATIC_DRAW);
glBindVertexArray(0);
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutCreateWindow("Rectangle!");
if (glewInit() != GLEW_OK) {
cout << "glewInit() fail!" << endl;
return -1;
}
if (!makeShader()) {
cout << "makeShader() error!!" << endl;
return -1;
}
Init();
reshape(WINDOW_WIDTH, WINDOW_HEIGHT);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}
when i adds VAO buffer, freeglut going to crash in glutMainLoop(), if i removes glGenVertexArrays call (of couse, removed what relatives to VAO too), it run ok, so my guess is problem in freeglut with glGenVertexArrays.
Question: What is my problem?
ps: My graphic cal support opengl 2.1, i use Visual Studio 2008.
Update: With VAO, above program work well but only crash when i close freeglut window.
Update shader: My shaders is very simple:
Vertex shader:
#version 120
attribute vec3 position;
// attribute vec3 normal;
uniform mat4 ModelViewMatrix;
uniform mat3 ModelViewTransposeInverseMatrix;
uniform mat4 ProjectionMatrix;
void main(void)
{
gl_Position = ProjectionMatrix * ModelViewMatrix * vec4(position, 1.0);
}
Fragment shader:
#version 120
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
glVertexAttribPointer(attrPos, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0);
Your vertex data is tightly packed. Use a stride of 0 instead of sizeof(float) * 3.
My graphic cal support opengl 2.1
Also, VAOs only became core in 3.0. You should check for ARB_vertex_array_object support before using that functionality.
Related
I divide my code to two cpp files, one cpp contains main()function and another one contains model loading codes.
here's the first part
#define STB_IMAGE_IMPLEMENTATION
//OpenGL relations
#include "stb_image.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
//math and time
#include <math.h>
#include <cstdio>
#include <time.h>
#include <iostream>
//matrix
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
//
#include "modelload.h"
// const values here //
const char* defaultpath = "woodenbox.jpeg";
const char* cottagetex = "cottage.fbx";
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position = transform * vec4(aPos.x, aPos.y, aPos.z, 1.0f);\n"
" TexCoord = aTexCoord;\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
" FragColor = texture(ourTexture, TexCoord);\n"
"}\n\0";
// functions here //
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void loadtexture(unsigned int& texture, const char* path = defaultpath) {
int width, height, nrChannels;
unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 4);
glGenTextures(1, &texture);
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
}
void renderInit(unsigned int& shaderProgram) {
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
}
// main function //
int main(int argc, char* argv[])
{
//初始化glfw
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL-1", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//渲染初始化,生成着色器程序、VAO、顶点初始数据
clock_t start, ends;
start = clock();
//build shader
unsigned int shaderProgram;
renderInit(shaderProgram);
unsigned int texture;
glGenTextures(1, &texture);
// 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
loadtexture(texture);
model* ct1 = new model(cottagetex);
glm::mat4 ori_trans = glm::mat4(1.0f);
glm::mat4 view_trans = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));//glm::translate(ori_trans, glm::vec3(0.0f, 0.0f, -3.0f));
glm::mat4 proj_trans = glm::perspective(glm::radians(45.0f), (float)(800 / 600), 0.1f, 100.0f);
glm::mat4 rotate_trans = glm::mat4(1.0f);
unsigned int count = 0;
float radius = 10.0f;
glEnable(GL_DEPTH_TEST);
// initialization completed
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
view_trans = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
//glEnableVertexAttribArray(0);
glUseProgram(shaderProgram);
rotate_trans = proj_trans * view_trans * glm::rotate(ori_trans, glm::radians((float)((clock() - start) - cos(clock() - start) * 4) / 40), glm::vec3(1.0, 1.0, -1.0));
unsigned int transformLoc = glGetUniformLocation(shaderProgram, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(rotate_trans));
ct1->draw();
//glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
rotate_trans = glm::translate(proj_trans * view_trans, glm::vec3(1.0f, 1.0f, -3.0f));
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(rotate_trans));
ct1->draw();
//glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
//std::cout << count << " frame updated" << (float)-(0.25 + sin(clock() - start) / 4) << std::endl;
count++;
glfwSwapBuffers(window);
glfwPollEvents();
}
/*
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
*/
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
and the second part
//OpenGL relations
#include <glad/glad.h>
#include <GLFW/glfw3.h>
//math and time
#include <math.h>
#include <vector>
#include <time.h>
#include <iostream>
//matrix
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
//assets
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
struct Vertex {
glm::vec3 Position;
glm::vec2 TexCoords;
glm::vec3 Normal;
};
class Mesh {
public:
/* 网格数据 */
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
//std::vector<unsigned int> textures;// materials
/* 函数 */
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices) {
this->vertices = vertices;
this->indices = indices;
}//, std::vector<unsigned int> textures
void Draw();
void setupMesh();
private:
/* 渲染数据 */
unsigned int VAO, VBO, EBO;
/* 函数 */
};
class model {
public:
model(const char* path);
void draw();
private:
std::vector<Mesh> meshes;
void processnode(aiNode* node, const aiScene* scene);
Mesh processmesh(aiMesh* mesh, const aiScene* scene);
// loadmaterials
};
#include "modelload.h"
//STL vector in namespace std
void Mesh::setupMesh() {
/*
for (int i = 0; i < vertices.size(); i++) {
std::cout<<vertices[i].Position.x<<std::endl;
}
*/
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//std::cout << sizeof(Vertex) << std::endl;
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(5 * sizeof(float)));
//glEnableVertexAttribArray(2);
//glBindVertexArray(0);// reload VAO before rendering
}
void Mesh::Draw() {
//std::cout << vertices.size() << std::endl; //vertices:988 indices:1434
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
}
model::model(const char* path) {
Assimp::Importer import;
const aiScene* scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
std::cout << "ERROR::ASSIMP::" << import.GetErrorString() << std::endl;
return;
}
processnode((scene->mRootNode), scene);
}
void model::processnode(aiNode* node, const aiScene* scene) {
for (int i = 0; i < node->mNumMeshes; i++) {
meshes.push_back(processmesh(scene->mMeshes[node->mMeshes[i]], scene));
meshes.back().setupMesh();
}
for (int i = 0; i < node->mNumChildren; i++) {
processnode(node->mChildren[i], scene);
}
}
Mesh model::processmesh(aiMesh* mesh, const aiScene* scene) {
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
for (int i = 0; i < (mesh->mNumVertices); i++) {
Vertex tvertex;
tvertex.Position.x = mesh->mVertices[i].x/3;
tvertex.Position.y = mesh->mVertices[i].y/3;
tvertex.Position.z = mesh->mVertices[i].z/3;
tvertex.Normal.x = mesh->mNormals[i].x;
tvertex.Normal.y = mesh->mNormals[i].y;
tvertex.Normal.z = mesh->mNormals[i].z;
tvertex.TexCoords.x = mesh->mTextureCoords[0][i].x;
tvertex.TexCoords.y = mesh->mTextureCoords[0][i].y;
vertices.push_back(tvertex);
//std::cout << tvertex.Position.x<<" "<< tvertex.Position.y<<" "<< tvertex.Position.z << std::endl;
//std::cout << tvertex.TexCoords.x << " " << tvertex.TexCoords.y << std::endl;
}
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (unsigned int j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
return Mesh(vertices, indices);
}
void model::draw() {
for (int i = 0; i < meshes.size(); i++) {
//std::cout << i << std::endl;
meshes[i].Draw();
}
}
It can only draw the background color, but it works when I draw a model I made by myself like:
-0.5, -0.5f, 0.5f, 0.0f,0.0f,//left bottom front 0
-0.5, 0.5f, 0.5f, 0.0f,1.0f,//left ceil front 1
0.5, 0.5f, 0.5f, 1.0f,1.0f,//right ceil front 2
0.5, -0.5f, 0.5f, 1.0f,0.0f,//right bottom front 3
-0.5, -0.5f, -0.5f, 1.0f,0.0f,//left bottom behind 4
-0.5, 0.5f, -0.5f, 1.0f,1.0f,//left ceil behind 5
0.5, 0.5f, -0.5f, 0.0f,1.0f,//right ceil behind 6
0.5, -0.5f, -0.5f, 0.0f,0.0f//right bottom behind 7
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 2,
0, 2, 3,
0, 4, 1,
1, 4, 5,
1, 2, 6,
1, 6, 5,
4, 5, 6,
4, 6, 7,
2, 3, 7,
2, 7, 6,
0, 3, 4,
4, 7, 3
};
I checked memory where the model data is, it seems like many same points was loaded.
enter image description here
Here is my code:
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
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";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.8f, 0.3f, 0.02f, 1.0f);\n"
"}\n\0";
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;
int windowWidth, windowHeight, resAnswer, aspectRatFirst, aspectRatSecond, aspectRatDeformation;
do {
std::cout << "Choose the preset for window resolution:" << std::endl;
std::cout << " 1. 800x800 (1:1)" << std::endl;
std::cout << " 2. 1024x768 (16:9)" << std::endl;
std::cout << "Answer: "; std::cin >> resAnswer;
} while (resAnswer != 1 && resAnswer != 2);
switch (resAnswer)
{
case 1:
windowWidth = 800;
windowHeight = 800;
aspectRatFirst = 1;
aspectRatSecond = 1;
break;
case 2:
windowWidth = 1024;
windowHeight = 768;
aspectRatFirst = 16;
aspectRatSecond = 9;
break;
}
aspectRatDeformation = aspectRatSecond / aspectRatFirst;
int shapeAnswer;
do {
std::cout << std::endl;
std::cout << "Choose your shape:" << std::endl;
std::cout << " 1. Triangle" << std::endl;
std::cout << " 2. Square" << std::endl;
std::cout << "Answer: "; std::cin >> shapeAnswer;
} while (shapeAnswer != 1 && shapeAnswer != 2);
64 GLfloat preVertices[];
if (shapeAnswer == 1) {
preVertices = {
-0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //B
0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //C
0.0f, 0.5f * float(sqrt(3)) * 2 / 3, 0.0f //A
};
}
else if (shapeAnswer == 2) {
preVertices = {
-0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //B
0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //C
0.0f, 0.5f * float(sqrt(3)) * 2 / 3, 0.0f //A
};
}
81 GLfloat vertices[] = preVertices;
window = glfwCreateWindow(windowWidth, windowHeight, "OpenGLCourse", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
gladLoadGL();
glViewport(0, 0, windowWidth, windowHeight);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
119 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glClearColor(0.07f, 0.13f, 0.17f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
My problem is between lines 64-81 and the line 119.
What I am trying to do is to create an array "vertices" for the specified shape vertices coordinates. The problem is that the triangle shape has 3 vertices and the square has 4 vertices, the array tho can only have one number of elements. I have another array "preVertices" just because I tried a lot of things to fix this problem.
The code wasn't working mainly because at line 119 I have to get the size of vertices, and the vertices seems to be undefined (and i think its because its getting defined inside of an if statement, or it was, at first, as i said, i changed a lot of things trying to resolve the problem), now, I think one solution would be just to make two different arrays with the different arrays and actually use an if statement to determine which i need at line 119, but I was wondering if there exists a solution with only one array, cuz I m thinking if there would be 100 different shapes it would be more time consuming to make 100 different arrays and it will also occupy more ram than needed, am I right?
This is a question following OpenGL and loading/reading data in AoSoA (hybrid SoA) format.
I am trying to use a shader storage buffer object (SSBO) to store vertex data which is represented in AoSoA format. I am having trouble drawing the vertices, which obviously means that I am doing something wrong somewhere. The problem is that I can't seem to figure out what or where. The answer to the initial question above seems to indicate that I should not be using vertex attribute arrays, so the question then becomes, how do I render this SSBO, given the code I am about to present?
VertexData structure
constexpr auto VECTOR_WIDTH = 4;
constexpr auto VERTEX_COUNT = 16;
struct VertexData
{
std::array<float, VECTOR_WIDTH> px;
std::array<float, VECTOR_WIDTH> py;
};
// Later stored in a std::vector
std::vector<VertexData> vertices(VERTEX_COUNT / VECTOR_WIDTH);
Vertex shader (should this really be a compute shader?)
struct Vertex4
{
float px[4]; // position x
float py[4]; // position y
};
layout(std430, binding=0) buffer VertexData
{
Vertex4 vertices[];
};
void main()
{
int dataIx = gl_VertexID / 4;
int vertexIx = gl_VertexID % 4;
vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);
}
Assign vertexPosition index
// Do I need this? Where do I use it? glEnableVertexAttribArray(position_attrib_index)?
const GLuint position_attrib_index = 0;
glBindAttribLocation(program, position_attrib_index, "vertexPosition");
SSBO setup
const GLuint ssbo_binding_point = 0;
GLuint ssbo{};
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
//glBufferStorage(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_MAP_WRITE_BIT);
glBufferData(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_STATIC_DRAW);
const auto block_index = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "VertexData");
glShaderStorageBlockBinding(program, block_index, ssbo_binding_point);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, ssbo_binding_point, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
Render loop
while (!glfwWindowShouldClose(window)) {
process_input(window);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
// ???
glfwSwapBuffers(window);
glfwPollEvents();
}
I just can't seem to figure out how this is supposed to work. Grabbing at straws, I also tried creating a VAO with a later call to glDrawArrays(GL_POINTS, 0, VERTEX_COUNT), but it didn't work either:
GLuint vao{};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(position_attrib_index);
glVertexAttribPointer(position_attrib_index, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
It seems to me that I should be using position_attrib_index (which should point to vertexPosition) for something, the question is for what?
Complete example code
requires OpenGL 4.3, GLEW and GLFW
build command example: g++ -std=c++17 main.cpp -lGLEW -lglfw -lGL -o ssbo
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <array>
#include <iostream>
#include <vector>
void process_input(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
void glfw_error_callback(int error_code, const char *description)
{
std::cerr << "GLFW Error: [" << error_code << "] " << description << '\n';
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
auto create_glfw_window()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
return glfwCreateWindow(800, 600, "OpenGL and AoSoA layout", nullptr, nullptr);
}
void set_callbacks(GLFWwindow *window)
{
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetErrorCallback(glfw_error_callback);
}
void print_versions()
{
std::cout << "Using GLFW " << glfwGetVersionString() << '\n';
std::cout << "Using GLEW " << glewGetString(GLEW_VERSION) << '\n';
}
bool init_loader()
{
GLenum err = glewInit();
if (GLEW_OK != err) {
std::cerr << "GLEW error: " << glewGetErrorString(err);
}
return err == GLEW_OK;
}
void GLAPIENTRY MessageCallback(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam = nullptr)
{
std::cerr << "[GL DEBUG] " << (type == GL_DEBUG_TYPE_ERROR ? "Error: " : "") << message << '\n';
}
constexpr auto VECTOR_WIDTH = 4;
constexpr auto VERTEX_COUNT = 16;
struct VertexData
{
std::array<float, VECTOR_WIDTH> px;
std::array<float, VECTOR_WIDTH> py;
};
static const char* vertex_shader_source =
"#version 430\n"
"struct Vertex4\n"
"{\n"
" float px[4]; // position x\n"
" float py[4]; // position y\n"
"};\n"
"layout(std430, binding=0) buffer VertexData\n"
"{\n"
" Vertex4 vertices[];\n"
"};\n"
"void main()\n"
"{\n"
" int dataIx = gl_VertexID / 4;\n"
" int vertexIx = gl_VertexID % 4;\n"
" vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);\n"
"}\n";
static const char* fragment_shader_source =
"#version 430\n"
"out vec4 out_color;\n"
"void main()\n"
"{\n"
" out_color = vec4(1.0, 0.5, 0.5, 0.25);\n"
"}\n";
int main(int argc, char *argv[])
{
glewExperimental = GL_TRUE;
auto window = create_glfw_window();
if (window == nullptr) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
set_callbacks(window);
init_loader();
print_versions();
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(MessageCallback, nullptr);
std::vector<VertexData> vertices(VERTEX_COUNT / VECTOR_WIDTH);
vertices[0] = {
{-0.75f, 0.75f, 0.75f, -0.75f},
{-0.75f, -0.75f, 0.75f, 0.75f}
};
vertices[1] = {
{-0.50f, 0.50f, 0.50f, -0.50f},
{-0.50f, -0.50f, 0.50f, 0.50f},
};
vertices[2] = {
{-0.25f, 0.25f, 0.25f, -0.25f},
{-0.25f, -0.25f, 0.25f, 0.25f},
};
vertices[3] = {
{-0.05f, 0.05f, 0.05f, -0.05f},
{-0.05f, -0.05f, 0.05f, 0.05f},
};
auto vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, nullptr);
glCompileShader(vertex_shader);
auto fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr);
glCompileShader(fragment_shader);
auto program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
const GLuint position_attrib_index = 0;
glBindAttribLocation(program, position_attrib_index, "vertexPosition");
glLinkProgram(program);
//glUseProgram(program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
//
// SSBO
//
const GLuint ssbo_binding_point = 0;
GLuint ssbo{};
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
//glBufferStorage(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_MAP_WRITE_BIT);
glBufferData(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_STATIC_DRAW);
const auto block_index = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "VertexData");
glShaderStorageBlockBinding(program, block_index, ssbo_binding_point);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, ssbo_binding_point, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
//
// VAO
//
//GLuint vao{};
//glGenVertexArrays(1, &vao);
//glBindVertexArray(vao);
//glEnableVertexAttribArray(position_attrib_index);
//glVertexAttribPointer(position_attrib_index, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glClearColor(0.15f, 0.15f, 0.2f, 1.0f);
glPointSize(10.0f);
while (!glfwWindowShouldClose(window)) {
process_input(window);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
//glDrawArrays(GL_POINTS, 0, VERTEX_COUNT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
This is the correct way to issue a draw with the data you have:
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, VERTEX_COUNT);
However, your issue is that your vertex shader does not write to gl_Position, therefore nothing gets rasterized (whatever undefined behavior happens). You should set the position of the vertices in the shader as follows:
//...
out gl_PerVertex {
vec4 gl_Position;
};
void main()
{
int dataIx = gl_VertexID / 4;
int vertexIx = gl_VertexID % 4;
vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);
gl_Position = vec4(vertexPosition, 0, 1);
}
You can get rid of "Assign vertexPosition index", and your VAO doesn't need to have any attributes.
I'm trying to learn OpenGL with this tutorial I tried to do the coding in OS X Mavericks but the result is just a black window. I believe there should be a white triangle but don't know what I'm missing.
Here's the code
glut_utils.h
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
void init();
void display();
void reshape (int w, int h);
void keyboard(uchar key, int x, int y);
glut_utils.cpp
#include <string>
#include <vector>
#include "glut_utils.h"
GLuint CreateShader(GLenum eShaderType, const std::string &strShaderFile)
{
GLuint shader = glCreateShader(eShaderType);
const char *strFileData = strShaderFile.c_str();
glShaderSource(shader, 1, &strFileData, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);
const char *strShaderType = NULL;
switch(eShaderType)
{
case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
case GL_GEOMETRY_SHADER_EXT: strShaderType = "geometry"; break;
case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
}
fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
delete[] strInfoLog;
}
return shader;
}
GLuint CreateProgram(const std::vector<GLuint> &shaderList)
{
GLuint program = glCreateProgram();
for(size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
glAttachShader(program, shaderList[iLoop]);
glLinkProgram(program);
GLint status;
glGetProgramiv (program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
fprintf(stderr, "Linker failure: %s\n", strInfoLog);
delete[] strInfoLog;
}
for(size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
glDetachShader(program, shaderList[iLoop]);
return program;
}
GLuint theProgram;
const std::string strVertexShader(
"#version 330\n"
"layout(location = 0) in vec4 position;\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
"}\n"
);
const std::string strFragmentShader(
"#version 330\n"
"out vec4 outputColor;\n"
"void main()\n"
"{\n"
" outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n"
"}\n"
);
void InitializeProgram()
{
std::vector<GLuint> shaderList;
shaderList.push_back(CreateShader(GL_VERTEX_SHADER, strVertexShader));
shaderList.push_back(CreateShader(GL_FRAGMENT_SHADER, strFragmentShader));
theProgram = CreateProgram(shaderList);
std::for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
}
const float vertexPositions[] = {
0.75f, 0.75f, 0.0f, 1.0f,
0.75f, -0.75f, 0.0f, 1.0f,
-0.75f, -0.75f, 0.0f, 1.0f,
};
GLuint positionBufferObject;
GLuint vao;
void InitializeVertexBuffer()
{
glGenBuffers(1, &positionBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
void init()
{
InitializeProgram();
InitializeVertexBuffer();
glGenVertexArraysAPPLE(1, &vao);
glBindVertexArrayAPPLE(vao);
}
void display()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(theProgram);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glUseProgram(0);
glutSwapBuffers();
}
void reshape (int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
exit(EXIT_SUCCESS);
return;
}
}
Tut01.cpp
#include "common.h"
#include "glut_utils.h"
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_3_2_CORE_PROFILE | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Hello Triangle");
init();
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
Try including the core profile header first:
#include <OpenGL/gl3.h>
#include <GLUT/glut.h>
Remove the APPLE suffix from glGenVertexArraysAPPLE and glBindVertexArrayAPPLE - they shouldn't be defined with the gl3.h header anyway.
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.