Related
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
};
I recently needed to implement a function in the QT+OPENGL environment, that is, I drew a cube (presumably in the center of the view) in my own defined framebuffer (I defined it as fbo) and colored it in red. And nothing is drawn in the default buffer, so I can't see my cube in the view (but it is drawn in the framebuffer fbo)
I hope that when I click in the middle of the view (the position of the cube), I can display the color of the cube----red instead of the color of the background of the view.
Here are the problems I have encountered:
I can only get the color of the background of the view with the mouse, and the cube drawn in the frame buffer is not picked up (the cube is red).
In the initializeGL() function, I initialized and configured the framebuffer fbo and some of the configuration required to draw the cube.
In the paintGL() function, I bind my defined framebuffer to GL_FRAMEBUFFER and then do the drawing.
In the mousePressEvent(QMouseEvent *e) function, I did the picking work. This is the response function of the QT mouse click. I put the information read by glReadPixels into the array pix and print it out.
void OpenglWidget::initializeGL()
{
core1 = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_0_Core>();
core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
core->glGenFramebuffers(1, &fbo);
core->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create the texture object for the primitive information buffer
core->glGenTextures(1, &m_pickingTexture);
glBindTexture(GL_TEXTURE_2D, m_pickingTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32UI, SCR_WIDTH, SCR_HEIGHT,
0, GL_RGB_INTEGER, GL_UNSIGNED_INT, NULL);
core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
m_pickingTexture, 0);
// Create the texture object for the depth buffer
core->glGenTextures(1, &m_depthTexture);
core->glBindTexture(GL_TEXTURE_2D, m_depthTexture);
core->glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT,
0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
m_depthTexture, 0);
// Disable reading to avoid problems with older GPUs
core->glReadBuffer(GL_NONE);
// Verify that the FBO is correct
GLenum Status = core->glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status == GL_FRAMEBUFFER_COMPLETE) {
qDebug() << "ok";
}
// Restore the default framebuffer
core->glBindTexture(GL_TEXTURE_2D, 0);
core->glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLfloat verticPosition[] = {
-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,
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,
};
GLint beamIndices[] = {
0,1,2,3,4,5,6,7
};
core->glGenVertexArrays(1, &VAOBeam);
core->glGenBuffers(1, &VBOBeam);
core->glGenBuffers(1, &EBOBeam);
core->glBindVertexArray(VAOBeam);
core->glBindBuffer(GL_ARRAY_BUFFER, VBOBeam);
core->glBufferData(GL_ARRAY_BUFFER,sizeof(float) * 3 * 36, verticPosition, GL_STATIC_DRAW);
core->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOBeam);
core->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 8, beamIndices, GL_STATIC_DRAW);
core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
core->glEnableVertexAttribArray(0);
core->glBindBuffer(GL_ARRAY_BUFFER, 0);
core->glBindVertexArray(0);
}
void OpenglWidget::paintGL()
{
core->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0,0,1,1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
float frametime =GetFrameTime();
mCamera.Update(frametime);
Shader GLprogram = Shader("E:\\QT\\OpenglTest\\vs.vert","E:\\QT\\OpenglTest\\fs.frag");
GLprogram.use();
core->glBindVertexArray(VAOBeam);
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, mCamera.TempTranslateVrc);
glm::mat4 view = glm::mat4(1.0f);
//view = glm::lookAt(glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.5f,0.5f,0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
view = glm::lookAt(mCamera.mPos,mCamera.mViewCenter,mCamera.mUp);
glm::mat4 projection = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(45.0f), (float)1.0, 0.1f, 100.0f);
GLprogram.setMatrix4f("model",model);
GLprogram.setMatrix4f("view",view);
GLprogram.setMatrix4f("projection",projection);
core->glDrawArrays(GL_TRIANGLES,0,36);
core->glUseProgram(0);
update();
}
void OpenglWidget::mousePressEvent(QMouseEvent *e)
{
core1 = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_0_Core>();
float pix[4] = {0.0};
mCamera.getInitPos(e->x(),e->y());//This is the camera's setup function, no need to worry about it.
core1->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
core1->glReadBuffer(GL_COLOR_ATTACHMENT1);
core1->glReadPixels(e->x() , 500 - e->y() + 65, 1, 1, GL_RGBA, GL_FLOAT, pix);
qDebug() << e->x()<< 500 - e->y() <<pix[0] << pix[1] << pix[2] << pix[3];
}
I can only get the color of the background of the view with the mouse, and the cube drawn in the frame buffer is not picked up (the cube is red).
The issue is caused, because in the color buffer attached to GLCOLOR ATTACHMENT1, never is rendered to.
The name of the enumerator constant for the 1st color buffer, which can be attached by glFramebufferTexture2D to a framebuffer is GL_COLOR_ATTACHMENT0, rather than not GL_COLOR_ATTACHMENT1:
void OpenglWidget::initializeGL()
{
// [...]
core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0, // <---- GL_COLOR_ATTACHMENT0 instead of GL_COLOR_ATTACHMENT1
GL_TEXTURE_2D,
m_pickingTexture, 0);
// [...]
}
void OpenglWidget::mousePressEvent(QMouseEvent *e)
{
// [...]
core1->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
core1->glReadBuffer(GL_COLOR_ATTACHMENT0); // <---- GL_COLOR_ATTACHMENT0
// [ ...]
}
Note, by default it is rendered to the first color buffer (GL_COLOR_ATTACHMENT0) of a framebuffer. If you want to render to an other color buffer, than the 1st one, then you would have to specify a color buffer (list) explicitly by glDrawBuffers.
See OpenGL 4.6 API Core Profile Specification; 17.4.1 Selecting Buffers for Writing; page 513:
17.4.1 Selecting Buffers for Writing
[...] The set of buffers of a framebuffer object to which all fragment colors are written is controlled with the commands
void DrawBuffers( sizei n, const enum *bufs );
void NamedFramebufferDrawBuffers( uint framebuffer, sizei n, const enum *bufs );
[...] For framebuffer objects, in the initial state the draw buffer for
fragment color zero is COLOR_ATTACHMENT0. For both the default framebuffer
and framebuffer objects, the initial state of draw buffers for fragment colors other then zero is NONE.
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 am trying to reduce the number of faces that are rendered in my voxel engine by implementing a greedy meshing algorithm similar to Mikola's (http://0fps.net/2012/06/30/meshing-in-a-minecraft-game/)
Since I am using a VBO to draw each triangle for every cube I am wondering how I will be able to merge the triangles of adjacent cubes?
For reference here is what my cube vertex array looks like (note that it is interleaved to allow for texture coordinates to be included):
GLfloat cubeInterleaved[] =
{
// Front face u v
-0.5f, -0.5f, 0.5f, 0, 0,
0.5f, -0.5f, 0.5f, 1, 0,
0.5f, 0.5f, 0.5f, 1, 1,
-0.5f, 0.5f, 0.5f, 0, 1,
// Right face
0.5f, -0.5f, 0.5f, 0, 0,
0.5f, -0.5f, -0.5f, 1, 0,
0.5f, 0.5f, -0.5f, 1, 1,
0.5f, 0.5f, 0.5f, 0, 1,
// Back face
0.5f, -0.5f, -0.5f, 0, 0,
-0.5f, -0.5f, -0.5f, 1, 0,
-0.5f, 0.5f, -0.5f, 1, 1,
0.5f, 0.5f, -0.5f, 0, 1,
// Left face
-0.5f, -0.5f, -0.5f, 0, 0,
-0.5f, -0.5f, 0.5f, 1, 0,
-0.5f, 0.5f, 0.5f, 1, 1,
-0.5f, 0.5f, -0.5f, 0, 1,
// Top Face
-0.5f, 0.5f, 0.5f, 0, 0,
0.5f, 0.5f, 0.5f, 1, 0,
0.5f, 0.5f, -0.5f, 1, 1,
-0.5f, 0.5f, -0.5f, 0, 1,
// Bottom Face
0.5f, -0.5f, 0.5f, 0, 0,
-0.5f, -0.5f, 0.5f, 1, 0,
-0.5f, -0.5f, -0.5f, 1, 1,
0.5f, -0.5f, -0.5f, 0, 1
};
Since I am using a VBO to draw each triangle for every cube I am confused as to how I will be able to merge the triangles of adjacent cubes.
By using only a subset of the vertices, which is done by properly populating the index buffer for drawing.
Take this set of 4 triangles for example
5
/ \
3 --- 4
/ \ / \
0 --- 1 --- 2
You can either draw
GL_TRIANGLES: 0 1 3 1 2 4 1 4 3 3 4 5
or if all the vertices are coplanar you can just use the outer edges
GL_TRIANGLES: 0 2 5
And you can do the same with the vertices of blocks forming your world by appropriately populating the index buffer passed to glDrawElements
I'm trying out raw OpenGL, so I decided to code very, very simple game based on 3d blocks, something a'la retarded Minecraft game, just to improve my skills.
Last problems I've met with were cullings. I've finally figured out how to make Frustum Culling and Backface Culling, and they both work well, but unfortunatelly I have no idea how to code Occlusion Culling to not display boxes that are covered by other boxes that are closer to player.
Just for test in main draw loop I'm looping through all boxes, later I'll change it to a more efficient way, now this is how the code looks like:
for( std::map< std::string, Cube* >::iterator it = Cube::cubesMap.begin( ); it != Cube::cubesMap.end( ); it++ )
{
cube = ( *it ).second;
if( !cube )
continue;
(...)
if( Camera::cubeInFrustum( cube->position.x, cube->position.y, cube->position.z, 0.5f ) && cube->isInRoundDistance( 80 ) )
cube->draw( );
}
And Cube::Draw:
void Cube::draw( )
{
glPushMatrix( );
glTranslatef( position.x, position.y, position.z );
if( showSide1 == false && showSide2 == false && showSide3 == false && showSide4 == false && showSide5 == false && showSide6 == false )
{
glPopMatrix( );
return;
}
GLfloat cube[] =
{
-0.5f, -0.5f, 0.5f,// Front face
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,// Back face
-0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,// Left face
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,// Right face
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,// Top face
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,// Bottom face
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f
};
float textures[] =
{
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f
};
//ss << position.x + 2 << ", " << position.y << ", " << position.z << std::endl;
glVertexPointer(3, GL_FLOAT, 0, cube);
glTexCoordPointer(2, GL_FLOAT, 0, textures);
if( showSide1 || showSide2 || showSide3 || showSide4 )
glBindTexture(GL_TEXTURE_2D, imageSides->texture);
if( showSide1 )
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if( showSide2 )
glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
if( showSide3 )
glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
if( showSide4 )
glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
if( showSide5 )
{
glBindTexture(GL_TEXTURE_2D, imageUp->texture);
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
}
if( showSide6 )
{
glBindTexture(GL_TEXTURE_2D, imageDown->texture);
glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
}
glPopMatrix( );
}
I'm pretty sure it's inefficient, as I said earlier, this code will be optimized soon. Now I'm trying to make it working. The bool variables showSide are made for detection, if there is box with other box next to it, the sides between them won't be drawn.
I've been looking and googling how to make the occlusion culling, but I failed, there are only laconic informations or theory.
My question is, could anyone help me how to not draw covered blocks? I heard there is GLEW which I've compiled and injected, it has two following lines:
glBeginQuery(GL_SAMPLES_PASSED_ARB, query);
glEndQuery(GL_SAMPLES_PASSED);
Apparently Query is helpful to solve my problem, but I unsuccessfully tried to use it with Google on many ways, firstly no cubes were drawn, secondly game was drawn as earlier, covered cubes also.
Generally, you shouldn't expect a graphical API to do the work for you - its job is rendering, and your job is making sure it has as little to render as possible.
I recommend reading this blog: http://www.sea-of-memes.com/summary/blog_parts.html
It is about someone developing a minecraft-ish engine from scratch, and goes over everything from occlusion to lighting to transparency. In fact, the very first part should answer your question pretty well.