Related
I want to generate VBO and EBO for subdivided plane, I draw with GL_TRIANGLES, I want to know effective way to do this.
Eventually it will be a huge cube consists from 6 subdivided plane, so, i can't imagine alghorithm to generate VBO and EBO for subdivide.
What i have as input data:
cube
std::vector<float> vertices =
{
// +Y SIDE //Colors
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
// -Y SIDE
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
// +X SIDE
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
// -X SIDE
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
// +Z SIDE
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
// -Z SIDE
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f
};
std::vector<unsigned int> indices =
{
// +Y
1, 2, 0, 3, 2, 1,
// -Y
4, 6, 5, 5, 6, 7,
// +X
8, 9, 10, 9, 11, 10,
// -X
14, 13, 12, 14, 15, 13,
// +Z
17, 18, 16, 19, 18, 17,
// -Z
20, 22, 21, 21, 22, 23
};
So, i want to write a function witch accept subdivision and change my indeces and vertices vectors, just loop over existed planes in cube and subdivide it
I'm trying to render a cube and rotate it along it's Y axis using OpenGL ES 2.0, however the cube does not render as a cube but rather as some sort of very flat trapezium. A few images showing the odd behaviour:
Very flat:
beginning to rotate:
mid-rotation:
and after rotation:
I'm not exactly sure what is causing the strange behaviour. I am utilising the Pigs in a Blanket library for rendering on PS Vita.
These are my cube vertices. The first 3 values in each row are the vertex data, the last 2 values are for texture mapping
GLfloat vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
This is my initialization function. surface_width = 960, surface_height = 544 and aspect = 1.764706
void TestScene::init(EGLint s_width, EGLint s_height)
{
surface_height = s_height;
surface_width = s_width;
model = glm::mat4(1.0f);
projection = glm::mat4(1.0f);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
texture.load_texture("app0:assets/wall.jpg");
if (!shader.load_shaders("app0:shaders/vert.cg", "app0:shaders/frag.cg"))
sceKernelExitProcess(0);
}
This is my rendering function
void TestScene::render(EGLDisplay display, EGLSurface surface, double deltaTime)
{
glViewport(0, 0, surface_width, surface_height);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.ID);
glUseProgram(shader.ID);
GLint mvpLoc = glGetUniformLocation(shader.ID, "mvp");
GLint position = glGetAttribLocation(shader.ID, "vPosition");
GLint texLoc = glGetAttribLocation(shader.ID, "vTexCoord");
GLfloat aspect = (GLfloat)surface_width/(GLfloat)surface_height;
projection = glm::perspective(glm::radians(camera.Zoom), aspect, 0.1f, 100.0f);
view = camera.GetViewMatrix();
model = glm::rotate(model, glm::radians(1.0f), glm::vec3(0.0f, -1.0f, 0.0f));
glm::mat4 mvp = projection * view * model;
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvp));
// Bind vertex positions
glEnableVertexAttribArray(position);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
// Bind texture positions
glEnableVertexAttribArray(texLoc);
glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableVertexAttribArray(position);
glDisableVertexAttribArray(texLoc);
eglSwapBuffers(display, surface);
}
My cameras zoom value is 45.0f and this is the GetViewMatrix method:
glm::mat4 Camera::GetViewMatrix()
{
return glm::lookAt(Position, Position + Front, Up);
}
and finally the shaders:
vert.cg
void main
(
uniform float4x4 mvp,
float4 vPosition,
float2 vTexCoord: TEXCOORD0,
out float4 oPosition: POSITION,
out float2 fTexCoord: TEXCOORD
)
{
oPosition = mul(mvp, vPosition);
fTexCoord = vTexCoord;
};
frag.cg
float4 main
(
in float2 fTexCoord: TEXCOORD0,
uniform sampler2D texture1: TEXUNIT0
)
{
float4 col;
col = tex2D(texture1, fTexCoord);
return col;
}
I have a feeling it has something to do with my projection matrix but I'm not entirely sure. Any help is greatly appreciated, thank you
UPDATE:
If I update the near value in glm::perspective from 0.1f to 1.0f it produces a better looking but still false result, so I'm pretty sure the issue is in my projection matrix. What am I doing wrong here?
projection = glm::perspective(glm::radians(camera.Zoom), aspect, 0.1f, 100.0f);
becomes
projection = glm::perspective(glm::radians(camera.Zoom), aspect, 1.0f, 100.0f);
for the following results:
Wider but still incorrect
Another angle
Again
I've found the issue. I was multiplying the model view projection matrix incorrectly in the vert shader.
oPosition = mul(mvp, vPosition);
should be
oPosition = mul(vPosition, mvp);
this works with a near value of 0.1f
EDIT
Also the missing faces were due to incorrect winding order with my vertices. Here is a corrected set of vertices, they are in clockwise order glFrontFace(GL_CW);
GLfloat vertices[] = {
// Back face
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // Bottom-left
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // bottom-left
// Front face
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // top-right
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // top-left
// Left face
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-right
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-left
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-left
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-left
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-right
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-right
// Right face
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-left
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-right
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-right
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-left
// Bottom face
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // top-right
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-left
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, // top-left
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-left
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // top-right
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-right
// Top face
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // bottom-right
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, // bottom-left
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f // top-left
};
So I am having this assignment which requires to create a skybox; the texture is provided as a single file. Bear in mind, I am very slow when it comes to understanding OpenGL, and this particular SkyBox has been driving me insane. I read up on every little thing on the internet that I thought could relate to my issue, but I either can't comprehend what is going on, which is not what I am after since I want to know what I am doing and not copy/paste some code, or the result ends up being something different.
The code relating to the skybox so far:
GLfloat cubeVertexData[108] =
{
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
//4
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
//5
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
//6
0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f
};
GLfloat textureCoordsSkyBox[72] = {
//face 1
0.75,0.33, // 0,1,
0.75,0.67, // 1,1,
0.5,0.33, // 0,0,
0.5,0.33, // 0,0,
0.75,0.67, // 1,0,
0.5,0.67, // 1,1,
//face 2
0.5,1.0, // 1,1,
0.25,1, // 0,1,
0.5,0.67, // 1,0,
0.5,0.67, // 1,0,
0.25,1.0, // 0,1,
0.25,0.67, // 1,1,
//face 3
0,0.67,// 1,1,
0,0.33,// 0,1,
0.25,0.67,// 1,0,
0.25,0.67,// 1,0,
0,0.33,// 0,1,
0.25,0.33,// 0,0,
//face 4
0.25,0.0,// 0,1,
0.5,0.0,// 1,1,
0.25,0.33,// 0,0,
0.25,0.33,// 0,0,
0.5,0.0,// 1,1,
0.5,0.33,// 0,0,
//face 5
0.5,0.67,// 1,0,
0.25,0.67,// 0,0,
0.5,0.33,// 1,1,
0.5,0.33,// 1,1,
0.25,0.67,// 0,0,
0.25,0.33,// 0,1,
//face 6
0.75,0.33,// 1,1,
1.0,0.33,// 0,1,
0.75,0.67,// 1,0,
0.75,0.67,// 1,0,
1.0,0.33,// 0,1,
1.0,0.67// 0,0
};
GLfloat gCubeVertexdataNormals[108] =
{
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f
};
void DrawSkyBox() {
glFrontFace(GL_CW);
glBindTexture(GL_TEXTURE_2D, textures[SKYIMAGE]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, gCubeVertexdataNormals);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, cubeVertexData);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordsSkyBox);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
Loading texture [part of code missing as I have different textures for other elements loaded here]:
.....
#define SKYIMAGE 5 //sky image
const char *textureFiles[TEXTURE_COUNT] = { "stormydays.tga".... };
I am not sure if it is of importance, but I will also mention that the other textured elements of the scene do not have coordinates from 0-1, but from 100 to 1000. I tried previously to set up the textureCoordsSkyBox to 1000 in terms of coordinates, but still no result.
I imagine I do something completely wrong when it comes to the binding of the texture, but I am having a hard time comprehending how I can improve that part. Any advice would be deeply appreciated. Thank you in advance.
-Edit-
So this is the texture I am using:
What I am seeing is just black, besides the other elements of the scene like the back wall, some grass and some flowers [this is what I was referring to when I said textured elements of the scene]. I am attaching the code here of what part of my drawing the scene function looks like:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
gluLookAt(cameraX, cameraY, cameraZ,//eye
50.00, 90.00, 50.00,//centre
0.00, 1000.00, 0.00);//up
glPushMatrix();
DrawSkyBox();
glPopMatrix();
glPushMatrix();
glTranslatef(0.0, 0.0, -100.0);
glRotatef(-90.0, 1.0, 0.0, 0.0);
drawTexturedSurface(IMAGE1); //grass
glPopMatrix();
glPushMatrix();
glTranslatef(0.0, 0.0, -350.0);
drawTexturedSurface(IMAGE4); //front stone wall
glPopMatrix();
glPushMatrix();
.......
glPopMatrix();
drawGUI();
glPushMatrix();
glutSwapBuffers();
}
Also, it is the fixed version of OpenGL. I tried messing about with GL_LIGHTING, GL_CULL_FACE, GL_DEPTH_TEST and glDisableClientState but it is the same result. Also, I don't get any errors.
In your case the skybox is a very tiny object in the center of the world.
You have to draw the skybox in at the position of the camera. When you darw the sykbox, then you have to disable the depth test, this cause that the depth buffer is not written and all other parts of the scene cover the skybox.
Further two-dimensional texturing has to be enabled by glEnable(GL_TEXTURE_2D), before the skybox geometry is drawn:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
gluLookAt(
cameraX, cameraY, cameraZ,//eye
50.00, 90.00, 50.00,//centre
0.00, 1000.00, 0.00);//up
glDisable(GL_DEPTH_TEST);
glPushMatrix();
glTranslatef(cameraX, cameraY, cameraZ); // model transformation to the camera position
glEnable(GL_TEXTURE_2D);
DrawSkyBox();
glPopMatrix();
glEnable(GL_DEPTH_TEST);
I have a base class that contains an unassigned pointer _vertices, and I want to populate it from the derived class constructor:
class GameRenderable {
bool _indexed;
int _vertSize;
int _idxSize;
unsigned int VAO, VBO, EBO;
unsigned int _texture0;
protected:
float *_vertices;
unsigned int *_indices;
public:
GameRenderable(GameRenderableMode grm);
~GameRenderable();
void Render();
protected:
void SetupBuffer(int, int);
};
void GameRenderable::SetupBuffer(int vs, int is) {
_indexed = false;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vs, _vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
_idxSize = is;
_vertSize = vs;
}
void GameRenderable::Render() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _texture0);
glBindVertexArray(VAO);
glm::mat4 model = glm::mat4(1.0f);
GetShader()->setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, _vertSize);
}
The derived classes:
class Cube : public GameRenderable {
public:
Cube();
~Cube();
};
Cube::Cube():GameRenderable(GameRenderableMode::_3D) {
/* Cube ASCII
E--------F A -0.5f, 0.5f, -0.5f
/| /| B 0.5f, 0.5f, -0.5f
A--------B | C -0.5f, -0.5f, -0.5f
| | | | D 0.5f, -0.5f, -0.5f
| G------|-H E -0.5f, 0.5f, 0.5f
|/ |/ F 0.5f, 0.5f, 0.5f
C--------D G -0.5f, -0.5f, 0.5f
H 0.5f, -0.5f, 0.5f
*/
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
_vertices = new float[sizeof(vertices)];
memcpy_s(_vertices, sizeof(vertices), vertices, sizeof(float));
SetupBuffer(36, 0);
SetupTexture("container.jpg");
}
Cube::~Cube() {
}
When I call SetupBuffer() the array passed to openGL is always only 1 element, and nothing is drawn. If I put the code of SetupBuffer() directly inside the constructor, it works.
GL Buffer Issues
The sizeof( type ) operator returns the size in bytes, so for example the code:
std::cout << sizeof(float) << std::endl;
will print the output: 4
so on the following line:
_vertices = new float[sizeof(vertices)];
you are allocating 4 times the amount of data that you need to store the array vertices. It should be something like:
_vertices = new float[sizeof(vertices) / sizeof(float)];
//this is more ugly but could also be:
_vertices = (float*)(new char[sizeof(vertices)]);
//that works since an ascii 'char' is 1 byte
the function memcpy_s from MSDN:
Parameters
dest
New buffer.
destSize
Size of the destination buffer, in bytes for memcpy_s and wide characters (wchar_t) for wmemcpy_s.
src
Buffer to copy from.
count
Number of characters to copy.
so the call should be something like:
memcpy_s(_vertices, sizeof(vertices), vertices, sizeof(vertices));
//although, I would just use the regular 'memcpy':
memcpy(_vertices, vertices, sizeof(vertices));
Your SetupBuffer function takes the parameter vs which is input directly into glBufferData, however glBufferData also takes the size in bytes:
size
Specifies the size in bytes of the buffer object's new data store.
so entering the value 36 will not suffice. You want to find a way to pass the value of sizeof(vertices), although since you know the stride of each vertex (5 floats), you could change the call to:
glBufferData(GL_ARRAY_BUFFER, vs * 5 * sizeof(float), _vertices, GL_STATIC_DRAW);
As many of the comments mentioned, you could also use the std::vector class to simplify some of the code, however I think it is much more important to address the misunderstandings in the code you have already written.
OOP Issues
I am fairly sure the above will fix your problem. However, just to make sure the constructor:
Cube::Cube() : GameRenderable(GameRenderableMode::_3D) {
doesn't overwrite the GameRenderable constructor, the GameRenderable constructor will be called first (with the parameter _3D) so ensure that the code within the GameRenderable constructor doesn't break anything (as I can't see it).
I have just started to learn OpenGL and I am currently trying to apply the OpenGL knowledge I have acquired in a small game architecture, but I am having a hard time making this work with Classes. I am trying to display a triangle on the screen using a separate class like this:
CubeModel.h
#pragma once
#include <vector>
#include <glad\glad.h>
class CubeModel
{
public:
//x y and z are dimensions of the cube
CubeModel();
CubeModel( float x, float y, float z);
~CubeModel();
void Bind();
void Unbind();
private:
unsigned int m_VAO, m_VBO;
std::vector<float> m_vertices = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
std::vector<float> m_vertices2 = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
};
CubeModel.cpp
#include "CubeModel.h"
CubeModel::CubeModel()
{
CubeModel(1.0f, 1.0f, 1.0f);
}
CubeModel::CubeModel(float x, float y, float z)
{
unsigned int VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(m_vertices[0]) * m_vertices.size(),
m_vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
m_VAO = VAO;
m_VBO = VBO;
}
CubeModel::~CubeModel()
{
glDeleteVertexArrays(1, &m_VAO);
glDeleteBuffers(1, &m_VBO);
}
void CubeModel::Bind()
{
glBindVertexArray(m_VAO);
}
void CubeModel::Unbind()
{
glBindVertexArray(0);
}
Game_State.h (where CubeModel is used):
#pragma once
#include "Window.h"
#include "Shader.h"
#include "CubeModel.h"
#define TIMESTEP 1.0f/100.0f
class Game_State
{
public:
Game_State();
~Game_State();
int Run();
bool IsDone();
private:
void HandleInput();
void Update(double deltatime);
void Render();
Window m_window;
double m_elapsedTime = 0;
Shader m_cubeShader;
CubeModel m_testCube;
};
Game_State.cpp:
#include "Game_State.h"
Game_State::Game_State()
: m_window("Title to be determined...", glm::vec2(1920, 1080))
, m_cubeShader("cubeshader.vs","cubeshader.fs")
{
}
Game_State::~Game_State()
{
}
int Game_State::Run()
{
while (m_elapsedTime > TIMESTEP)
{
m_elapsedTime -= TIMESTEP;
HandleInput();
Update(m_elapsedTime);
}
Render();
m_elapsedTime += glfwGetTime();
glfwSetTime(0.0f);
return 0;
}
void Game_State::Update(double deltatime)
{
m_window.Update();
}
void Game_State::Render()
{
m_window.BeginDraw(0.7f, 0.5f, 0.3f, 1.0f);
m_cubeShader.use();
m_testCube.Bind();
glDrawArrays(GL_TRIANGLES, 0, 6);
m_testCube.Unbind();
m_window.EndDraw();
}
void Game_State::HandleInput()
{
if (glfwGetKey(m_window.GetWindow(), GLFW_KEY_F11) == GLFW_PRESS)
{
m_window.ToggleFullscreen();
}
if (glfwGetKey(m_window.GetWindow(), GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
m_window.CloseWindow();
}
}
bool Game_State::IsDone() { return m_window.IsDone(); }
When i tried to debug the code, everything was working and the VAO and VBO both got an ID but by the time i call the bind function before drawing it to the screen in a separate render function it binds the array with ID 0. Both the m_VAO and m_VBO gets reset to 0 by the time bind() is called, what is the reason for this?!?! I've tried using this exact code directly in the render function and it works so the render is fine it seems. (I'm using GLFW and GLAD)
Thanks in advance! :)
This:
CubeModel::CubeModel()
{
CubeModel(1.0f, 1.0f, 1.0f);
}
is wrong. That creates a CubeModel temporary within the constructor. That's not the same thing as delegating the constructor. If that's what you wanted, you have to use the proper C++11 syntax:
CubeModel::CubeModel() : CubeModel(1.0f, 1.0f, 1.0f)
{}
Note that this may not be your only problem, since you neglected to post all of your code.
For example, CubeModel is technically copyable, but it shouldn't be. You make no special allowances for copying (which by its nature, would have to create a new VAO and buffer, and copy the data from the other VAO/buffer). So you need to delete the copy operations, and write appropriate move operations:
CubeModel(const CubeModel &) = delete;
CubeModel(CubeModel &&other) : m_VAO(other.m_VAO), m_VBO(other.m_VBO)
{
other.m_VAO = 0;
other.m_VBO = 0;
}
And do something similar for the move assignment operation. Or just leave it as being unassignable.
In C++, you can't call a constructor from inside another constructor as you do here:
CubeModel::CubeModel()
{
CubeModel(1.0f, 1.0f, 1.0f);
}
What is actually happening here is that you create a temporary, unnamed CubeModel which get's deleted when the default constructor is left. That's when your VAO gets deleted.
If you don't want to duplicate the code in both function, you need to write a new method and call that one from both constructors.