I'm trying to learn some basic OpenGL 3D programming. I'm following this guide and some youtube videos. In particular I've reached the chapter which talks about model loading (using Assimp). I've more or less managed to make something work using the guide's code, then I tried to write a more structured program following a series of videos on youtube, in particular this one but when I finished and run the program, it stops, without showing anything if not a black screen. When running the program using the visual studio debugger, I get the following error:
Exception thrown at 0x00007FF9DABA7610 (nvoglv64.dll) in "program name.exe" 0xC0000005: Access violation reading location 0x0000000000000000
The code that generates the exception is
glBindVertexArray(this->VAO);
glDrawElements(GL_TRIANGLES, (this->indices).size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
the first line. I've tried searching for some similar errors on the internet, hoping for answers, and I found that these errors are often caused by a bad configured VAO, in particular this site suggests to carefully check the portion of code where the VAO is configured, which I did, and it seems fine. Moreover, when I try to use the same code to render a model from an array of vertices, it works fine. The method where the VAO is configured is the following one:
void Mesh::setup() {
// create buffers and array objects
glGenVertexArrays(1, &(this->VAO));
glGenBuffers(1, &(this->VBO));
glGenBuffers(1, &(this->EBO));
// configure buffers
glBindVertexArray(this->VAO);
{
// VBO
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, (this->vertices).size() * sizeof(Vertex), &(this->vertices)[0], GL_STATIC_DRAW);
// data configuration
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::textureCoordinates));
// EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (this->indices).size() * sizeof(unsigned int), &(this->indices)[0], GL_STATIC_DRAW);
}
glBindVertexArray(0);
}
where Vertex is a custom structure of the form
typedef struct Vertex {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 textureCoordinates;
// convert an array of vertices into a vector of struct Vertex vertices
static std::vector<struct Vertex> genList(float* vertices, int nrVertices);
} Vertex;
My program is pretty much the same as the one showed on the youtube video (the classes are pretty much identical, the file tree structure might differ a bit).
As I can't write all the program, I will explain its structure:
There is a model class which loads a model from a file or from a class defined in the project:
Model(glm::vec3 position, glm::vec3 size) initializes the class variables
void loadModel(std::string path) loads a model from a file: it uses assimp to convert a model file into a aiScene* object from which the specific data is retrieved via: void processNode(aiNode* node, const aiScene* scene) (a recursive function which iterates through each Assimp's node), Mesh processMesh(aiMesh* mesh, const aiScene* scene) (a function called by processNode which converts the information inside aiMesh into a custom Mesh object that I will describe later), and std::vector<Texture> loadTexture(aiMaterial* material, aiTextureType type) (a function called by processMesh which retrieves all the textures of a material associated to a mesh; it returns a custom Texture object, which I will describe later)
void render(Shader* sahder) (Shader is a custom class that manages shaders) draws the model on the screen. Each mesh of the model is stored in a class variable and has a render method called by Model::render.
void init() it is a method that is meant to be overridden by a child class. In particular, for example, I've defined a class Cube : public Model which has a Cube constructor (that calls the Model super-constructor) and has an init method where the vertex data of the cube -initialized using an array then converted to a Vertex structure -, indices and textures are used to initialize a Mesh object, then stored into a meshes list inside Model class. Using this approach the cube model is perfectly rendered without any exception
There is a Mesh class which converts an Assimp's aiMesh* object into a custom object:
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<Texture> textures = {}) calls the void Mesh::setup() method
void setup() it is the method I've included before: it configures the VAO, EBO and VBO (which, I repeat, work perfectly with the cube class)
void render(Shader* shader) sets the correct value for texture units (distinguishing between diffuse and specular textures) and binds the textures. Then draw each vertex using glDrawElements, these are the lines that generate the exception.
There is a Texture class which loads textures and stores textures' parameters:
Texture(std::string path, std::string directory, aiTextureType type) initializes class variables
void generate() generates an OpenGL texture object
void load(bool flipv) loads the texture from an image (using stb library) and configures texture object parameters (e.g. wrap S or T and so on)
void bind() binds the texture to GL_TEXTURE_2D
In the main function I declared a Model object giving a path (which loaded succcesfully according to the debug std::cout statements I've inserted):
Model model(glm::vec3(0.0f), glm::vec3(1.0f))
model.loadModel("path");
Then in the mainloop, after enabling the shader:
model.render(&objectShader);
As I said before, I've checked my code and it seems to have no errors. I've searched online but couldn't find anything. I can't even think of a way to test the program and see where does this error come from. Have you go any suggestion on how to avoid this issue?
Thanks in advance for your effort and time in answering me! I don't really know if what I've explained about the program and what I've included about the code is enough. If you have any requests on the code or on how the program works that might help you find the issue, please ask me and I will edit this question.
Related
I have a class "Object"
Object::Object(Transform transform, Mesh mesh, Shader shader)
{
this->transform = transform;
this->mesh = mesh;
this->shader = shader;
}
with 3 member variables Transform, Mesh and Shader (in case it's relevant I'm working with OpenGL- GLEW and GLFW)
The above constructor returns a "no default constructor exists for class Mesh" error.
I've defined a constructor for mesh, but my confusion here is that I'm trying to assign a passed variable object Mesh into the constructor when I instantiate an object.
Essentially I want something like
Transform transform() //has a default constructor requiring no parameters
Mesh mesh(parameters)
Shader shader()
Object myObject(transform, mesh, shader);
As a generic example.
In case the Mesh constructor is relevant:
Mesh::Mesh(Vertex* verts, unsigned int numVerts)
{
/*Vertex vertices[] = { Vertex(glm::vec3(-.5,-.5,0)),
Vertex(glm::vec3(0,.5,0)),
Vertex(glm::vec3(.5,-.5,0)) };*/
//vertices = new Vertex[numVerts]{ verts };
m_drawCount = numVerts;
glGenVertexArrays(1, &m_vertexArrayObject);
glBindVertexArray(m_vertexArrayObject);
glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[position_VB]);
glBufferData(GL_ARRAY_BUFFER, numVerts * sizeof(verts[0]), verts, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
tl;dr I'm coming from a C# background, so maybe I've gotten confused but I'm not sure why I would need a default constructor for an object when I'm passing an object in as a parameter when that same object can be instantiated with the constructor I defined elsewhere in my code.
This:
Object::Object(Transform transform, Mesh mesh, Shader shader)
{
this->transform = transform;
this->mesh = mesh;
this->shader = shader;
}
Should be written like this instead:
Object::Object(const Transform& t, const Mesh& m, const Shader& s)
: transform(t), mesh(m), shader(s)
{
}
C++ isn't like C#, and you're going to get very confused if you assume it is.
In C++, all subobjects are constructed before you enter the body of the constructor. So the subobjects of your Object class (transform, mesh, and shader) are constructed using default constructors because you didn't specify anything else. The assignments that you coded in the body of your constructor have no effect on this.
To specify different parameters for the constructors of your subobjects, use a member initializer list, like my code above shows.
I have a code structure that has a Render with the rendering loop, a Shader class and a Model class. I am able to get my shaders to work when I implement them in the renderer, but I'm looking to assign them to a model and call render(), however I'm having an odd issue, that the shader works outside of the model, but not inside.
Shader structure:
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
{
... Generate shaders...
//Assign program ID to the public unsigned int
ID = glCreateProgram();
...attach shaders to program and link...
}
//Install program for use in rendering
void use()
{
glUseProgram(ID);
}
}
Model Structure:
class TextureModel
{
public:
TextureModel(const std::string modelPath, const std::string texturePath)
{
...Initialize model, load in mesh,texture, create a VAO with vertex and
index VBOs, set glAttribArray values...
}
Render(Shader* shader)
{
//glUseProgram(4) <---------- (3)
shader->use(); <---------- (1)
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture);
glDrawElements(GL_TRIANGLES, IBO->GetCount(), GL_UNSIGNED_INT, (void*)0);
glBindVertexArray(0);
}
}
Renderer structure:
Shader* texShader;
TextureModel* Reindeer;
int main()
{
texShader = new Shader("Shaders/camera.vs", "Shaders/textured.fs", "Shaders/passThrough.gs");
Reindeer = new TextureModel("Models/reindeer_v1/reindeer_v1.obj",
"Models/reindeer_v1/reindeer_diffuse.jpg");
while (!glfwWindowShouldClose(window))
{
...Update camera, project and model matrices. Update the shader uniforms...
//texShader->use() <---------- (2)
Reindeer->Render(texShader);
glfwSwapBuffers(window);
}
}
The above code does not render my object.
At point (1) my model calls the texShader->use() passed in by TextureModel::Render(Shader*). For some reason this does not work, however if I call texShader->use() from the rendering loop it works, this is at point (2).
Also in debugging I found that the program ID assigned to texShader on creation is 4. If I put glUseProgram(4) in the model::Render(Shader*) block, this also works. Point (3).
Why does the glUseProgram() function work in all cases except when passed in to my model? I'm really confused at this one.
Looks like I've fixed it.
I've summarized my problem above, but in actual fact I am using two different shaders for different objects.
The both share the same vertex shader (using their own model matrices, with a camera uniform buffer object), use different fragment shaders, and share a geometry shader.
For some reason I am only able to have one instance of the geometry shader working at a time... I need to to further investigation.
Either way I've got the above issue solved.
Thanks
I'm working on creating a cloth simulation in openGL and I've been trying to use a VAO and VBO for rendering rather than the old immediate mode (glBegin, glEnd).
I reckon it's best if I only provide the relevant parts of the code rather than the all of it. So I currently have a class, Cloth, that stores the the mass (nodes) in a vector.
class Cloth {
private:
std::vector<Mass>masses;
public:
std::vector<Mass> getMasses() { return masses; };
// functions below
And a class, Mass.
class Mass {
glm::vec3 currentPos;
glm::vec3 oldPos;
glm::vec3 acceleration;
// functions below
I've createad a VBO like so
glGenBuffers(1, &VBO_ID);
glBindBuffer(GL_ARRAY_BUFFER, VBO_ID);
glBufferData(GL_ARRAY_BUFFER, cloth.getMasses().size() * sizeof(Mass), &cloth.getMasses().front(), GL_DYNAMIC_DRAW);
and a VAO
glGenVertexArrays(1, &VAO_ID);
glBindVertexArray(VAO_ID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GL_FLOAT), 3*sizeof(GL_FLOAT)); // unsure about this part
From what I've gathered, by calling glVertexAttribPointer, you tell the VBO how to handle the data that has been given to it. I gave it a vector of type Mass.
What would be the correct way for me to tell it how to handle the data so that it uses currentPos as vertexes?
and
Is there a better (performance-wise) way of doing this, and if so, how and why?
For example, would it be best to use a struct to hold the currentPos?
I don't see anything wrong with the code. But with vertexBuffer attributes, you don't need to tell the openGL state machine to use currentPos as a vertex, this will be done in the vertex shader.
EDIT I see something wrong with the code. I thought you only sent primitive types. You cannot send your class to your GLSL code and hope that it will work. YOu can send data and the glVertexAttribPointer tells your shader the layout of your data. What you are doing cannot work.
I'd advise you to take a look at https://learnopengl.com/ it helped me a lot and is very complete.
You'll have:
layout (location = 0) in vec3 currentPos;
layout (location = 1) in vec3 oldPos;
layout (location = 2) in vec2 acceleration;
Then you output the position of the vertex with this:
gl_Position = mvp*vec4(currentPos, 1.0);
mvp beeing the Model View Projection matrix that you would probably send as a uniform.
What comes next is a bit out of the scope of your answer but might be interesting:
While I don't know exactly what you're trying to do, you should ne that in the vertex shader you cannot edit the vertex attributes, this means that considering how your code looks right now, you'll have to update your VBO every step of the simulation. you can either update it on you CPU (which might be slow), but it might be significantly faster to do it in a compute shader.
Iam new to OpenGL and also new to C++ .
I created a main.cpp where i do everything .I Create an GLfloat data[] where i store my Cube's Vertices and also one GLfloat color[] for the Color. I create a VAO and a VBO and i have method, where i compile a simple Vertex and Fragment Shader.
The problem is,that my Code is very long,so i thought about creating a Cube Class,Triangle Class and so on.
My Question is now, can i use the same VAO for several Objects or do i use a new VAO for each Object?.
The other thing is, that i dont exactly know how to program this.I'am missing the structure(I used Java before).
My thoughts were :
class Cube {
public:
Cube();
Cube(GLfloat position[],GLfloat color[]);
//But i need the same Shaders for each Object , so do i initialize it here or somewhere else?
compileShader();
drawCube();
}
Note that this are only my thoughts about it..Maybe someone can help me out with this :)
VAO and VBO can be reused but for performance only should be if they aren't changing (for example, if you're keeping a 1x1x1 cube but using transformations to draw additional ones).
For a simple cube in a small application Your ideal structure would be something like
class Cube{
private static int vbo;
private static int vao;
public Cube(){
//If vbo and vao are 0 initialize them here
}
public void render(mat4* transform){
}
}
The shader would be a separate class, which can either be part of the rendering call for this object public void render (mat4* transform, shader* shader) or can be called by the main pipeline.
Now, I would recommend reading about header files in c++. In c++ headers are the right way to develop especially if you are going to be sharing your class around your program. Other classes need to only inherit the header, they don't have to care about the implementation, and that way your code only gets compiled once and you're using the same compiled assembly code throughout your class. (In c++ if you include actual code, it gets compiled, and even though modern linkers are good about merging duplicate code, it's still bad practice)
Cube.h:
class Cube{
static int vbo;
static int vao;
public:
Cube();
void render(mat4* transform);
}
cube.cpp:
Cube::Cube(){
//Initialize Here
}
Cube::render(mat4* transform){
//Render here
}
Then you'd also want a pair for shader
shader.h:
class Shader{
int ProgramID;
public:
Shader();
void activate ();
}
shader.cpp:
Shader::Shader(){
//compile shader here
}
Shader::activate(){
//make this shader program active here
}
The mat4 data for the transform that I mentioned came from http://glm.g-truc.net/0.9.6/index.html which is a great library for handling the math of 3d graphics.
If you want to refactor this further, you can define the render function of cube in an interface that all of your graphic objects will inherit, allowing you to more dynamically instantiate and configure the objects, and not care about what types they are, just that they're of the interface required.
I am trying to draw a square with VBO in my native blackberry 10 application. My implementation is,
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenBuffers(1,&decompressTileImage->VBOId);
glBindBuffer(GL_ARRAY_BUFFER,decompressTileImage->VBOId);
glBufferData(GL_ARRAY_BUFFER,sizeof(tileCoordList)+sizeof(tileTextureCoordList),0,GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(tileCoordList),tileCoordList);
glBufferSubData(GL_ARRAY_BUFFER,sizeof(tileCoordList),sizeof(tileTextureCoordList),tileTextureCoordList);
glTexCoordPointer(3, GL_FLOAT, sizeof(tileTextureCoordList), (void*)sizeof(this->tileCoordList));
glVertexPointer(3, GL_FLOAT, sizeof(tileCoordList), 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_BLEND);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
swapBuffers();
Here tileCoordList contains the co-ordinates for the square and tileTextureCoordList contains the corresponding texture. tileCoordList is a Square3D type structure.
typedef struct
{
Vertex3D lowerLeft;
Vertex3D lowerRight;
Vertex3D upperLeft;
Vertex3D upperRight;
}Square3D;
typedef struct
{
GLfloat x;
GLfloat y;
GLfloat z;
} Vertex3D;
4 Vertex3D represents a square in tileCoordList. Same goes for tileTextureCoordList. I can draw fine without the VBO though. I am using opengl-es 1.1
Another question.
If I create two VBOs. Suppose I bound the first one with its id and copied the data and drew it. And then comes the second one and I also bind it and copy the data and draw it. Now if I want to draw the first one again do I need to bind it again? If I need to bind again do I need to copy the data to buffer for that VBO again also?
It has transpired in the comments that tileCoordList and tileTextureCoordListare pointers to Square3D structures.
This means that the sizeof operator will give you the size of a pointer, not the size of the struct.
You could use e.g.
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(*tileCoordList), tileCoordList);
instead.
You are doing something weird to your buffer. Without knowing what tileCoordList is it's hard to say if you are adding the data correctly.
In general, regarding both of your concerns here: VBOs store the data for you. It is not only possible, but encouraged to do:
vbo_1, vbo_2;
vbo1.LoadData(data_1);
vbo2.LoadData(data_2);
main_loop {
vbo1.Bind();
Draw();
vbo2.Bind();
Draw();
}
I have used pseudocode here, but you should get the idea. I don't understand what the SubData call is supposed to do; in general, one simple glBufferData should be enough. Bind call sets the buffer as an active one.
This line made me cringe - why is VBOId public? Smells like a poorly designed abstraction to me:
glGenBuffers(1,&decompressTileImage->VBOId);
And oh, please don't use this->. The only thing it does here is worsen readability.