Problem: Opengl is converting the integer array, I passed into a vertex array object, into a float array for some reason.
When I try to use the vertices as an ivec2 in my vertex shader I get some weird numbers as outputs, however if I use vec2 instead I get the expected output.
Code:
VertexShader:
#version 430 core
// \/ This is what I'm reffering to when talking about ivec2 and vec2
layout (location = 0) in ivec2 aPos;
uniform uvec2 window;
void main()
{
float xPos = float(aPos.x)/float(window.x);
float yPos = float(aPos.y)/float(window.y);
gl_Position = vec4(xPos, yPos, 1.0f, 1.0f);
}
Passing the Vertex Array:
GLint vertices[] =
{
-50, 50,
50, 50,
50, -50,
-50, -50
};
GLuint VBO, VAO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO); // \/ I'm passing it as an int
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 2 * sizeof(GLint), (void*)0);
glEnableVertexAttribArray(0);
glUseProgram(sprite2DProgram);
glUniform2ui(glGetUniformLocation(sprite2DProgram, "window"), 640, 480);
Output:
The first picture is what happens when I use ivec2 (the bad output).
The second picture is what happes when I use vec2 (the expected output).
If you need to know anything else please ask it in the comments.
For vertex attributes with an integral data it has to be used glVertexAttribIPointer (focus on the I), to define an array of generic vertex attribute data.
This means, that if you use the ivec2 data type for the attribute in the vertex shader:
in ivec2 aPos;
then you have to use glVertexAttribIPointer wehan you define the array of generic vertex attribute data.
Change your code like this, to solve the issue:
// glVertexAttribIPointer instead of glVertexAttribPointer
glVertexAttribIPointer(0, 2, GL_INT, GL_FALSE, 2 * sizeof(GLint), (void*)0);
See OpenGL 4.6 API Compatibility Profile Specification; 10.2. CURRENT VERTEX ATTRIBUTE VALUES; page m389:
When values for a vertex shader attribute variable are sourced from an enabled generic vertex attribute array,
the array must be specified by a command compatible with the data type of the variable.
The values loaded into a shader attribute variable bound to generic attribute index are undefined if the array for index was not specified by:
VertexAttribFormat, for floating-point base type attributes;
VertexAttribIFormat with type BYTE, SHORT, or INT for signed integer base type attributes; or
VertexAttribIFormat with type UNSIGNED_BYTE, UNSIGNED_SHORT, or UNSIGNED_INT for unsigned integer base type attributes.
Related
I know there are uniforms which can solve this problem but I wonder is it possible to add value like int using glVertexAttribPointer()?
Shader:
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aColor;
layout (location = 2) in int aSize;
out vec3 vColor;
void main()
{
gl_Position = vec4(aPosition, 1.0f);
gl_PointSize = aSize;
vColor = aColor;
}
The code:
makeCurrent();
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, points.vbo.size() * sizeof(GLfloat), &points.vbo.front(), GL_STATIC_DRAW); //look below to the struct
glVertexAttribPointer(0, points.vertexAmount, GL_FLOAT, GL_FALSE, points.stride * sizeof(GLfloat), (GLvoid *)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, points.colorAmount, GL_FLOAT, GL_FALSE, points.stride * sizeof(GLfloat), (GLvoid *)(points.vertexAmount * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(/* ??? how to add simple int here ??? */);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
doneCurrent();
points struct:
struct RenderedObjects
{
std::vector<float> vbo;
int vertexAmount = 3;
int colorAmount = 3;
int stride = vertexAmount + colorAmount;
int size = 1;
} points;
glVertexAttribPointer is for arrays of data only. When you issue a dasw call, the GPU will fetch the i-th element of each attribute array which is enabled, and it uses the vertex attrib pointer data to find that element in the VBOs.
For attribute inputs for which no attribute array is enabled, you can set the value as part of the GL state. The function family glVertexAttib...() allows you to set the values for a generic vertex attribute.
OpenGL's naming conventions can get a bit confusing here. By default, vertex attributes are always treated as floating-point, even if you specify the input as integers (same with glVertexAttribPointer()s type parameter). So even if you might think glVertexAttrib1i() might set the value of an scalar integer attribute, it in reality deals with setting a float attribute, just by providing an integer value.
Integer attributes where added later to the GL, and you have to use glVertexAttribI() / glVertexAttribIPointer() (note the capital I letter) for these.
So the correct way to specify a single constant input for layout (location = 2) in int aSize; is:
glVertexAttribI1i(2, yourIntegerValue);
glDisableVertexAttribArray(2); // do NOT use an array for this attribute
(When you create a VAO, all attribute arrays are disabled initially, so you might not need to explicitly call the glDisableVertexAttribArray(2) here.)
So I've been fiddling with an old University project done in OpenGL 3.3 (FreeGLUT + GLEW) and I've run into some problems.
Right at the start, I run the program and I'm getting an error compiling the BumpMap Fragment Shader:
#version 330 core
#define lightCount 10
in vec4 vertPos;
in vec4 eyeModel;
in vec3 normalInterp;
in vec4 ambient;
in vec4 color;
in vec4 spec;
in vec2 texuv;
in vec4 lightPosition[lightCount];
struct LightSource {
vec4 Position;
vec4 Direction;
vec4 Color;
float CutOff;
float AmbientIntensity;
float DiffuseIntensity;
float SpecularIntensity;
float ConstantAttenuation;
float LinearAttenuation;
float ExponentialAttenuation;
int lightType;
};
layout(std140) uniform LightSources {
LightSource lightSource[10];
};
uniform sampler2D diffuse_tex;
uniform sampler2D normal_tex;
out vec4 out_Color;
void main() {
out_Color = vec4(0);
for(int i=0; i<lightCount; i++) {
if(lightSource[i].lightType == 0)
continue;
vec3 NormalMap = texture2D(normal_tex, texuv).rgb;
vec3 normal = normalize(NormalMap * 2.0 - 1.0); //normalize(normalInterp);
vec4 LightDirection = vertPos - lightSource[i].Position;
float Distance = length(LightDirection);
LightDirection = normalize(LightDirection);
vec4 ambientColor = ambient * lightSource[i].Color * lightSource[i].AmbientIntensity;
vec4 diffuseColor = vec4(0, 0, 0, 0);
vec4 dColor = texture2D(diffuse_tex, texuv);
vec4 specularColor = vec4(0, 0, 0, 0);
float DiffuseFactor = dot(normal, vec3(-LightDirection));
if (DiffuseFactor > 0) {
diffuseColor = dColor * lightSource[i].Color * lightSource[i].DiffuseIntensity * DiffuseFactor;
vec3 VertexToEye = normalize(vec3(eyeModel - vertPos));
vec3 LightReflect = normalize(reflect(vec3(LightDirection), normal));
float SpecularFactor = dot(VertexToEye, LightReflect);
SpecularFactor = pow(SpecularFactor, 255);
if(SpecularFactor > 0.0){
//SpecularFactor = pow( max(SpecularFactor,0.0), 255);
specularColor = spec * lightSource[i].Color * lightSource[i].SpecularIntensity * SpecularFactor;
}
}
out_Color += ambientColor + diffuseColor + specularColor;
}
}
ERROR: 0:55: 'function' : is removed in Forward Compatible context texture2D
ERROR: 0:55: 'texture2D' : no matching overloaded function found (using implicit conversion)
So I looked the problem up and even though I thought it was weird I was getting this problem on a project I knew had been in working condition, I switched the texture2D call for a texture call and now the shader compiles, but I get a different error, where creating the buffer object for the first object in the scene:
//Consts defined here for readability
#define VERTICES 0
#define COLORS 1
#define NORMALS 2
#define TEXUVS 3
#define AMBIENTS 4
#define TANGENTS 5
#define SPECULARS 6
#define SPECULARS_CONSTANTS 7
#define NOISE_SCALE 8
void BufferObject::createBufferObject() {
glGenVertexArrays(1, &_vertexArrayObjectID);
glBindVertexArray(_vertexArrayObjectID);
glGenBuffers(1, &_vertexBufferObjectID);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*_vertexCount, _vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(VERTICES);
glVertexAttribPointer(VERTICES, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glEnableVertexAttribArray(COLORS);
glVertexAttribPointer(COLORS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)sizeof(_vertices[0].XYZW));
glEnableVertexAttribArray(NORMALS);
glVertexAttribPointer(NORMALS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)));
glEnableVertexAttribArray(TEXUVS);
glVertexAttribPointer(TEXUVS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)));
glEnableVertexAttribArray(AMBIENTS);
glVertexAttribPointer(AMBIENTS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)));
glEnableVertexAttribArray(TANGENTS);
glVertexAttribPointer(TANGENTS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)+sizeof(_vertices[0].AMBIENT)));
glEnableVertexAttribArray(SPECULARS);
glVertexAttribPointer(SPECULARS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)+sizeof(_vertices[0].AMBIENT)+sizeof(_vertices[0].TANGENT)));
glEnableVertexAttribArray(SPECULARS_CONSTANTS);
glVertexAttribPointer(SPECULARS_CONSTANTS, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)+sizeof(_vertices[0].AMBIENT)+sizeof(_vertices[0].TANGENT)+sizeof(_vertices[0].SPECULAR)));
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glDisableVertexAttribArray(VERTICES);
glDisableVertexAttribArray(COLORS);
glDisableVertexAttribArray(NORMALS);
glDisableVertexAttribArray(TEXUVS);
glDisableVertexAttribArray(AMBIENTS);
glDisableVertexAttribArray(TANGENTS);
glDisableVertexAttribArray(SPECULARS);
glDisableVertexAttribArray(SPECULARS_CONSTANTS);
Utility::checkOpenGLError("ERROR: Buffer Object creation failed.");
}
OpenGL ERROR [Invalid Operation] = 1282
And that's all the info I'm getting. I've moved the checkOpenGLError around and figured out the line glDisableVertexAttribArray(VERTICES) is giving the error.
After a bit more of digging I found out that you're not supposed to set glBindVertexArray(0) (at least before you glDisableVertexAttribArray, from what I remember we set those flags to 0 so we wouldn't accidentally affect anything we didn't want)
At this point the error moves to where we're drawing one of the scene objects. At this point I've hit a bit of a wall and don't where to go to next. I guess my question is whether there is a configuration when running the project that needs to be set, or whether just running this on a more recent graphics card could account for the different behaviour. As a final note, this is running on windows off of Visual Studio 10 (or 15, switched to 10 when reverted all changes and didn't retarget the solution) in widnows, the program configurations are as follows:
//GLUT Init
glutInit(&argc, argv);
glutInitContextVersion(3, 3);
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glutInitWindowSize(windowWidth, windowHeight);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
windowHandle = glutCreateWindow(CAPTION);
//GLEW Init
glewExperimental = GL_TRUE;
GLenum result = glewInit();
//GLUT Init
std::cerr << "CONTEXT: OpenGL v" << glGetString(GL_VERSION) << std::endl;
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glDepthRange(0.0,1.0);
glClearDepth(1.0);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
with the context above being:
CONTEXT: OpenGL v3.3.0 - Build 22.20.16.4749
Let me know if any aditional information is required, I didn't want to add any more unnecessary clutter and the project is too big to just paste it all here...
In your shader you are using glsl version 330 core, which means texture2D() is deprecated and you should use texture() instead.
As for your INVALID OPERATION error, the problem is that you unbound the vao with glBindVertexArray(0); and then called glDisableVertexAttribArray(VERTICES); which operates on the currently bound vao. You should move glBindVertexArray(0); under these calls.
First let me refer to the specification, OpenGL 4.6 API Core Profile Specification; 10.3.1 Vertex Array Objects; page 347 :
The name space for vertex array objects is the unsigned integers, with zero reserved by the GL.
...
A vertex array object is created by binding a name returned by GenVertexArray with the command
void BindVertexArray( uint array );
array is the vertex array object name. The resulting vertex array object is a new state vector, comprising all the state and with the same initial values listed in tables 23.3 and 23.4.
BindVertexArray may also be used to bind an existing vertex array object. If the bind is successful no change is made to the state of the bound vertex array object, and any previous binding is broken.
Tables 23.3, Vertex Array Object State
VERTEX_ATTRIB_ARRAY_ENABLED, VERTEX_ATTRIB_ARRAY_SIZE, VERTEX_ATTRIB_ARRAY_STRIDE, VERTEX_ATTRIB_ARRAY_TYPE, VERTEX_ATTRIB_ARRAY_NORMALIZED, VERTEX_ATTRIB_ARRAY_INTEGER, VERTEX_ATTRIB_ARRAY_LONG, VERTEX_ATTRIB_ARRAY_DIVISOR, VERTEX_ATTRIB_ARRAY_POINTER
Table 23.4, Vertex Array Object State
ELEMENT_ARRAY_BUFFER_BINDING, VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, VERTEX_ATTRIB_BINDING, VERTEX_ATTRIB_RELATIVE_OFFSET, VERTEX_BINDING_OFFSET, VERTEX_BINDING_STRIDE, VERTEX_BINDING_DIVISOR, VERTEX_BINDING_BUFFER.
This means that a Vertex Array Object collects all the information which is necessary to draw an object. In the vertex array object is stored the information about the location of the vertex attributes and the format.
Further the vertex array object "knows" whether an attribute is enabled or disabled.
If you do
glBindVertexArray(0);
glDisableVertexAttribArray( .... );
this causes an INVALID_OPERATION error, when you use a core profile OpenGL context, because then the vertex array object 0 is not a valid vertex array object.
If you would use a compatibility profile context this would not cause an error, because then the vertex array object 0 is the default vertex array object and is valid.
If you do
glBindVertexArray(_vertexArrayObjectID);
glEnableVertexAttribArray( ..... );
glVertexAttribPointer( ..... );
glDisableVertexAttribArray( ..... );
glBindVertexArray(0);
then the draw call will fail. You have made the effort to define all the arrays of generic vertex attributes data and to enable them all correctly, but right after doing that you disable them again. So in the vertex array object is stored the "disabled" state for all the attributes.
The correct procedure to define a vertex array object is:
Generate the vertex buffers, and creates and initializes the buffer object's data store (this step can be done after creating and binding the vertex array object, too):
glGenBuffers(1, &_vertexBufferObjectID);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*_vertexCount, _vertices, GL_STATIC_DRAW);
Generate and bind the vertex array object:
glGenVertexArrays(1, &_vertexArrayObjectID);
glBindVertexArray(_vertexArrayObjectID);
Define and enable the arrays of generic vertex attributes data (this has to be done after binding the vertex array object):
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
glEnableVertexAttribArray(VERTICES);
glVertexAttribPointer(VERTICES, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
....
glBindBuffer(GL_ARRAY_BUFFER, 0);
If you would use an element buffer (GL_ELEMENT_ARRAY_BUFFER), then you would have to specify it now, because the name of (reference to) the element buffer object is stored in the vertex array object, and this has to be currently bound, when the element buffer object gets bound.
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ..... );
Finally you can do glBindVertexArray(0). But there is no reason to do that. It is sufficient to bind a new vertex array object, before you specify a new mesh, or to bind the proper vertex array object before you draw a mesh.
Further there is no need for glDisableVertexAttribArray, as long you don't want to change the vertex array object specification. The state "enabled" is stored in the vertex array object an kept there. If you bind a new vertex array object, the then the object and so all its states become current.
Now drawing is simple:
glBindVertexArray(_vertexArrayObjectID);
glDrawArrays( .... );
Again there is no need of glBindVertexArray(0), after the draw call (especially in core mode).
Currently I have a system that contains 2 buffers, one created CPU side and set to a buffer. and then one from a ssbo and populated from another shader.
Here is the struct for the ssbo data:
struct ssbo_data_t
{
int maxcount = 1024;
float baz[1024];
} ssbo_data;
Then the vao is build like:
//Build buffer
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, arraysize * sizeof(DATATYPE), dataarr, GL_DYNAMIC_DRAW);
//Build vao
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//index,size,type,norm,stride,pointerToFirst
glEnableVertexAttribArray(0); //Position of light
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1); //Color
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(DATATYPE) * 2));
glEnableVertexAttribArray(2); //Intensity
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(DATATYPE) * 5));
glEnableVertexAttribArray(3); //Layer
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(DATATYPE) * 6));
//Try to bind ssbo for lighting data.
glBindBuffer(GL_ARRAY_BUFFER, ssbo);
glEnableVertexAttribArray(4); //MaxSize
glVertexAttribPointer(4, 1, GL_INT, GL_FALSE, 0, (void*)offsetof(ssbo_data_t,maxcount));
glEnableVertexAttribArray(5); //Corner Data
glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*)offsetof(ssbo_data_t, baz));
My question is that if I set no stride for the one buffer, and then a stride for another part of the buffer it should work right? Or is there something i'm missing?
Cause when I actually preform the draw call, the first line is drawn, but all others have a position of -1,-1 Like the first buffer bound to the VAO was reset.
I am however receiving the correct potions from the other buffer, which shows it is working. Its like the first buffer is being unbound on the next draw call.
Due to how large the project is, I cant really post a working example.
As you can see here, I place the primitive to the left and the other object to the right.
The primitive is drawn, and sets its corner positions to the SSBO.
The second object is then drawn and creates 4 line segments from its position.
The first vertex, works as expected, and creates a line segment from its position and terminates on the corner of the box, specified by the VAO.
The next draws don't read the position correctly. But do take the correct information from the ssbo. So... ?
Might be helpful if I posted the vertex shader:
#version 430 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in float intensity;
layout(location = 3) in float layer;
layout(location = 4) in int maxcount;
layout(location = 5) in vec2 loc;
uniform vec2 screensize;
out VS_OUT{
vec3 color;
float intensity;
vec4 targ;
} vs_out;
void main()
{
vec2 npos = ((aPos - (screensize / 2.0)) / screensize) * 2; //Convert mouse chords to screen chords.
gl_Position = vec4(npos, layer, 1.0);
vs_out.targ = vec4(loc, layer, 1.0);
vs_out.color = aColor;
vs_out.intensity = intensity;
}
To answer your question, yes you can mix and match strides and offsets in the same buffer and share vertex attribute data with an SSBO (Shader Storage Buffer Object).
Vertex stride
I'm not sure how you're trying to use the contents of the SSBO there. However, the binding of vertex attributes #4 and #5 looks fishy.
glVertexAttribPointer(4, 1, GL_INT, GL_FALSE, 0, (void*)offsetof(ssbo_data_t,maxcount));
The first vertex will have maxcount as expected in the x component. However, a stride of 0 means that consecutive vertex attributes are packed. The second vertex will therefore read 32 bits from baz[0] and treat that as an integer. The third will read baz[1] and so on. In short, only the first vertex will have the correct maxcount value and the rest will have bogus values.
To fix this, use instanced arrays (also known as vertex divisor). The function to use is glVertexAttribDivisor(). Another option is to bind your SSBO directly and read it as an SSBO (buffer type in GLSL). See the SSBO OpenGL wiki page for an example.
Finally:
glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*)offsetof(ssbo_data_t, baz));
You can use a stride of 0 here because your attribute values are tightly packed. sizeof(float) * 2 gives the same result.
The (wrong) solution
I wrongly stated that BindVertexArray() resets the current GL_ARRAY_BUFFER binding. This is not the case. It does reset the indexed vertex buffer binding though but you already set those.
I'm attempting to render Suzanne (from Blender) in OpenGL 3.3, but the buffer data doesn't seem to be correct. I get this:
https://gyazo.com/ab82f9acb6854a49fccc527ed96cc4e8
I also tried to render a sphere with a simple texture:
https://gyazo.com/85c1e87fcc4eab128ca37b1a0cb1deaa
My importer inserts the vertex data into a std::vector as single floats:
if(line.substr(0,2) == "v ")
{
/** Vertex position */
std::istringstream s(line.substr(2));
float v[3];
s >> v[0]; s >> v[1]; s >> v[2];
this->vertices.push_back(v[0]);
this->vertices.push_back(v[1]);
this->vertices.push_back(v[2]);
}
I setup the array buffer as follows:
glGenBuffers(1, &this->vbo);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glBufferData(GL_ARRAY_BUFFER,
sizeof(float)*(this->vertices.size()+this->textures.size()+this->normals.size()),
NULL,
GL_STATIC_DRAW);
And then I insert the actual data using glBufferSubData
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*this->vertices.size(), this->vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*this->vertices.size(), sizeof(float)*this->textures.size(), this->textures.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*(this->vertices.size()+this->textures.size()), sizeof(float)*this->normals.size(), this->normals.data());
I also insert the indices in the same way (GL_ELEMENT_ARRAY_BUFFER of course).
I then point to the information:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)(sizeof(float)*this->v.size()));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)(sizeof(float)*this->v.size()+this->vt.size()));
My vertex shader takes in the data like this:
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;
layout(location = 2) in vec3 normals;
Am I screwing up the offsets?
EDIT:
I figured out the biggest issue! I wrote an external Lua program to convert the obj files to a format that was easier to import, but it ended up messing with the data and duplicating the indices on the "f #/#/# #/#/# #/#/#" so the file looked like this (x->y->x) instead of (x->y->z)
Also fixed a few other errors thanks to the responses below!
Without seeing your shaders I can't be 100% sure if your calls to glVertexAttribPointer are legit. I also can't tell if you want interleaved vertex data in a single VBO or not. What you currently have packs all of the vertex positions in first, then all of the texture coordinates, and finally all of the normals.
To interleave the data you would first want to put all of it into a single array (or vector) so that each vertex repeats the PPPTTNNN pattern. Where PPP are the three position floats, TT are the two texcoord floats, and NNN are the three normal floats.
It would look something like this (using bogus types, values, and spacing to help illustrate the pattern):
float[] vertices = {
/* pX, pY, pZ, tX, tY, nX, nY, nZ */
1, 1, 1, 0, 0, 1, 1, 1, // vertex 1
0, 0, 0, 1, 1, 0, 0, 0, // vertex 2
1, 1, 1, 0, 0, 1, 1, 1, // vertex 3
...
};
Let's say you put it all into a single vector called vertices, then you can upload it with a single command:
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * this->vertices.size(), this->vertices.data(), GL_STATIC_DRAW);
You could also put each attribute into its own VBO. How you decide to store the data on the GPU is ultimately up to you. If you are purposely storing the data the way you have it, let me know in the comments and I'll update the answer.
Ok, now the shader bits.
Let's say you've got a vertex shader that looks like this:
in vec3 position;
in vec2 texcoord;
in vec3 normal;
out vec2 uv;
void main() {
gl_Position = vec4(position, 1);
uv = texcoord;
}
And a fragment shader that looks like this:
in vec2 uv;
uniform sampler2D image;
out vec4 color;
void main() {
color = texture(image, uv);
}
Then you would want the following glVertexAttribPointer calls:
int stride = (3 + 2 + 3) * sizeof(float);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)3);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)5);
Notice how the first parameter to each call is a different number. This corresponds to position, texcoord, normal respectively in the vertex shader.
Also texture coordinates are typically only a pair of floats (e.g. vec2 texcoord) so I changed the second parameter to 2 for the texcoord call.
Finally the last parameter, when using an interleaved array, only needs to specify the offset per vertex. Thus we get 0, 3, and 5 for position offset, texcoord offset, and normal offset respectively.
Hopefully this gets you where you want to be.
Check out the docs.gl page on glVertexAttribPointer for more info.
I have multiple objects but no idea how to move or rotate them separately. This would be a shorten version of the code I have so far:
const GLchar* vertexSource = "#version 150 core\n"
"in vec3 position;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 proj;"
"void main() {"
" gl_Position = proj * view * model * vec4(position, 1.0);"
"}";
struct Object {
// here are the constructors
vector<Triangle> polys; // Triangle is a struct containing vertex data
GLuint vao, vbo, ebo;
// somne other variables and functions
// ...
};
void ShaderProgram::AddObject(const vector<Triangle>& polys) {
objects.push_back(Object(polys));
Object& obj = objects[objects.size()-1];
glGenVertexArrays(1, &obj.vao);
glBindVertexArray(obj.vao);
// set up vertices and a vertex buffer object for them
// ...
glGenBuffers(1, &obj.vbo);
glBindBuffer(GL_ARRAY_BUFFER, obj.vbo);
glBufferData(GL_ARRAY_BUFFER, obj.polys.size()*polySize*sizeof(float), vertices, GL_STATIC_DRAW);
// 'polySize' is just a constant variable to healp me out and 'vertices' is a float array
// set up element buffer object
// ...
glGenBuffers(1, &obj.ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
// elements is a float array
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, vertSize*sizeof(float), 0);
// 'vertSize' is also a constant variable
}
void ShaderProgram::Draw(float dSec) {
for (Object& it : objects) {
glBindVertexArray(it.vao);
// here's some texturing related stuff
glDrawElements(GL_TRIANGLES, it.vertexCount(), GL_UNSIGNED_INT, 0);
}
}
void ShaderProgram::Move(Object& obj, glm::vec3 vec) {/*move it somehw*/}
void ShaderProgram::Rotate(Object& obj, glm::vec3 rotPoint, glm::vec3 rot) {/*rotate obj around rotPoint*/}
If I run this code everything displays perfectly but I couldn't figure out a clean way to change the positions of the vertices of one specific object during runtime.
Also, this doesn't have anything to do with the initial question but I've noticed that whenever I run the exact same code on my laptop, the program crash when calling glBindFragDataLocation() (it doesn't matter whether I run it on Linux or Windows).
In many rendering applications, several different coordinate systems are used:
Object space: This is the space where vertices are defined. Each model has it's own object coordinates with it's own model origin.
World space: This is the space where all the models in a scene are positioned relative to each other. This is (in general) done by specifying a model-matrix based on the desired location in the scene.
In your case, I would add an additional vec3 member to the Object struct that stores the location.
struct Object {
//Things you already have
glm::vec3 loc;
}
You can then update the model matrix uniform directly before calling glDrawElements. Since the draw call is already issued, changing the model matrix in this place will always influence the correct object:
void ShaderProgram::Draw(float dSec) {
for (Object& it : objects) {
glBindVertexArray(it.vao);
// here's some texturing related stuff
glm::mat4 model_matrix(1.0f);
glm::translate(model_matrix, it.loc);
glUniformMatrix4fv(model_uniform_location, 1, GL_FALSE, model_matrix);
glDrawElements(GL_TRIANGLES, it.vertexCount(), GL_UNSIGNED_INT, 0);
}
}
Another option would be to store a matrix directly in the Object class, which would increase the data size (and might be less intuitive to use), but might reduce runtime costs.
The current state of the Draw function looks like this:
void ShaderProgram::Draw(float dSec) {
objects[0].location.x += dSec;
GLint uniModel = glGetUniformLocation(shaderProgram, "model");
for (Object& it : objects) {
glBindVertexArray(it.vao);
glm::mat4 model;
model = glm::translate(model, it.location);
glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
glDrawElements(GL_TRIANGLES, it.vertexCount(), GL_UNSIGNED_INT, 0);
}
}