Undesirable serration in surface drawing in OpenGL using Vertex Buffer Objects - c++

First off, I am giving a screenshot of the problematically rendered images in opengl. The fourth surface image is drawn by Matlab and it is what the image supposed to look like in Opengl.
.
.
.
Matlab rendering of the dataset:
(First 3 images are the problematic serrated drawing from OpenGL in different angles, and the 4th one is the MATLAB drawn image which is correct)
The image is a 1024 x 1024 complex matrix. Each element's imaginal part is the height of the point (in a 1024x1024 heightmap), and the real part is the colour of the point.
In matlab we have created a small gaussian shaped mountain. In OpenGL it is rendered with rags and serration. The "raggedness" is spread through the entire image.
Moreover, according to the viewing angle of the object, there appears to be region beyond a line where not only a more weird version of serration happens and also the rendered graphics make a height jump/change.
What can cause this? why is this "raggedness" happenning and what is that line? we have run out of all ideas now and will appreaciate any help. Related parts of the VBO code is given below. We basically create a float4 object for a vertex. first, second and third float numbers in the structure correspond the the coordinations of the point. 4th float (treated as 4 one-byte numbers) is the RGBA color.
also note that the complex matrix which contains the heightmap and the color information is stored in the GPU, so there are calls to CUDA in the code. when all the data is dumped into a file, matlab successfully draws the map, so the data is definitely correct.
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
void initGL()
{
...
glViewport(0, 0, window_width, window_height);
glEnable(GL_BLEND);
glEnable(GL_COLOR_MATERIAL);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)window_width / (GLfloat) window_height, 0.1, 15.0);
...
}
void display()
{
camx += camx_v;
camy += camy_v;
camx_v=0;
camy_v=0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// set view matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 1, /* look from camera XYZ */
0, 0, 0, /* look at the origin */
0, 1, 0); /* positive Y up vector */
drawGround();
glTranslatef(camx, camy, translate_z);
glRotatef(rotate_x, 1.0, 0.0, 0.0);
glRotatef(rotate_y, 0.0, 1.0, 0.0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 16, BUFFER_OFFSET(0));
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 16, BUFFER_OFFSET(12));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_i);
glDrawElements(GL_TRIANGLES, (mesh_width-1) * (mesh_height-1) * 6, GL_UNSIGNED_INT, (GLvoid*)0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glutSwapBuffers();
}
void createVBO(GLuint* vbo, struct cudaGraphicsResource **vbo_res,
unsigned int vbo_res_flags)
{
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
unsigned int size = mesh_width * mesh_height * 4 * sizeof(float);
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
cutilSafeCall(cudaGraphicsGLRegisterBuffer(vbo_res, *vbo, vbo_res_flags));
}
void createIBO(GLuint* vbo, struct cudaGraphicsResource **vbo_res,
unsigned int vbo_res_flags, unsigned int numofindice)
{
glGenBuffers(1, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *vbo);
unsigned int size = (mesh_width-1) * (mesh_height-1) * numofindice * sizeof(GLuint);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, 0, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
cutilSafeCall(cudaGraphicsGLRegisterBuffer(vbo_res, *vbo, vbo_res_flags));
}
void main()
{
initGL();
createVBO(&vbo, &cuda_vbo_resource, cudaGraphicsMapFlagsWriteDiscard);
createIBO(&vbo_i, &cuda_vbo_resource_i, cudaGraphicsMapFlagsWriteDiscard, 6);
glutMainLoop();
}
//KERNEL TO FILL the INDEX BUFFER in GPU, called once at the initialization of the program.
__global__ void fillIBO(unsigned int* pos_i, unsigned int M)
{
unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;
unsigned int bi;
if(y<M-1 && x<M-1)
{
bi = ((M-1)*y +x)*6;
//TRI
pos_i[bi++] = x + y*M + 1;
pos_i[bi++] = x + y*M + M + 1;
pos_i[bi++] = x + y*M;
pos_i[bi++] = x + y*M;
pos_i[bi++] = x + y*M + M + 1;
pos_i[bi++] = x + y*M + M;
}
}

replace second triangle by :
pos_i[bi++] = x + y*M + 1;
pos_i[bi++] = x + y*M + M + 1;
pos_i[bi++] = x + y*M + M;
also, I'm pretty sure it should be
bi = (M*y +x)*6;

Related

Polygon tearing in OpenGL

500x500 grid with 1000 sub Divisions:
Just one question.
Why is this happening ?
#include <iostream>
#include <sstream>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "GameEngine.hpp"
#include "ShaderProgram.h"
#include "Camera.h"
#include "Mesh.h"
const char *title = "Terrain";
GameEngine engine;
OrbitCamera orbitCamera;
float gYaw = 0.0f;
float gPitch = 1.0f;
float gRadius = 200.0f;
const float MOUSE_SENSTIVITY = 0.25f;
bool gWireFrame = false;
void glfw_onKey(GLFWwindow *window, int key, int scancode, int action, int mode);
void glfw_onMouseMove(GLFWwindow *window, double posX, double posY);
void glfw_onMouseScroll(GLFWwindow *window, double deltaX, double deltaY);
int main()
{
if (!engine.init(1024, 768, title))
{
std::cerr << "OpenGL init failed" << std::endl;
std::cin.get();
return -1;
}
//set callbacks
glfwSetKeyCallback(engine.getWindow(), glfw_onKey);
glfwSetCursorPosCallback(engine.getWindow(), glfw_onMouseMove);
std::vector<Vertex> VER;
std::vector<glm::vec3> verts;
std::vector<unsigned int> indices;
std::vector<glm::vec3> norms;
int subDiv = 1000;
int width = 500;
int height = 500;
int size = 0;
for (int row = 0; row < subDiv; row++)
{
for (int col = 0; col < subDiv; col++)
{
float x = (float)((col * width) / subDiv - (width / 2.0));
float z = ((subDiv - row) * height) / subDiv - (height / 2.0);
glm::vec3 pos = glm::vec3(x, 0, z);
verts.push_back(pos);
}
}
size = subDiv * subDiv;
size = verts.size();
for (int row = 0; row < subDiv -1 ; row++)
{
for (int col = 0; col < subDiv -1; col++)
{
int row1 = row * (subDiv);
int row2 = (row+1) * (subDiv);
indices.push_back(row1+col);
indices.push_back(row1+col+1);
indices.push_back( row2+col+1);
indices.push_back(row1+col);
indices.push_back( row2+col+1);
indices.push_back(row2+col);
}
}
for (int i = 0; i < verts.size(); i++)
{
Vertex vertex;
vertex.position = verts[i];
vertex.normal = glm::vec3(0, 0, 0);
vertex.texCoords = glm::vec2(0, 0);
VER.push_back(vertex);
}
VER.begin();
for (int i = 0; i < indices.size(); i += 3)
{
Vertex a = VER[indices[i]];
Vertex b = VER[indices[i + 1]];
Vertex c = VER[indices[i + 2]];
glm::vec3 p = glm::cross(b.position - a.position, c.position - a.position);
VER[indices[i]].normal += p;
VER[indices[i + 1]].normal += p;
VER[indices[i + 2]].normal += p;
}
for (int i = 0; i < VER.size(); i++)
{
VER[i].normal = glm::normalize(VER[i].normal);
}
glm::vec3 cubePos = glm::vec3(0.0f, 0.0f, -5.0f);
GLuint vbo, vao, ibo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, VER.size() * sizeof(Vertex), &VER[0], GL_STATIC_DRAW);
// Vertex Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Normals attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// Vertex Texture Coords
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
int n = indices.size() * sizeof(unsigned int);
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
glBindVertexArray(0);
ShaderProgram shaderProgram;
shaderProgram.loadShaders("shaders/vert.glsl", "shaders/frag.glsl");
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
while (!glfwWindowShouldClose(engine.getWindow()))
{
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 model, view, projection;
model = glm::mat4(1.0f);
orbitCamera.setLookAt(glm::vec3(0, 0, 0));
orbitCamera.rotate(gYaw, gPitch);
orbitCamera.setRadius(gRadius);
model = glm::translate(model, glm::vec3(0, 0, 0));
//model = glm::scale(model, glm::vec3(1, 0, 1));
//model = scaleMat;
projection = glm::perspective(glm::radians(45.0f), (float)engine.getWidth() / (float)engine.getHeight(), 0.00001f, 100.0f);
shaderProgram.use();
glm::vec3 viewPos;
viewPos.x = orbitCamera.getPosition().x;
viewPos.y = orbitCamera.getPosition().y;
viewPos.z = orbitCamera.getPosition().z;
shaderProgram.setUniform("projection", projection);
shaderProgram.setUniform("view", orbitCamera.getViewMatrix());
shaderProgram.setUniform("model", model);
shaderProgram.setUniform("lightPos", glm::vec3(5, 10, 10));
shaderProgram.setUniform("viewPos", viewPos);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES,indices.size(), GL_UNSIGNED_INT, 0);
//glDrawArrays(GL_TRIANGLES, 0, VER.size());
glBindVertexArray(0);
glfwSwapBuffers(engine.getWindow());
}
//cleanup
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glfwTerminate();
return 0;
}
void glfw_onKey(GLFWwindow *window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, GL_TRUE);
}
if (key == GLFW_KEY_E && action == GLFW_PRESS)
{
gWireFrame = !gWireFrame;
if (gWireFrame)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
void glfw_onMouseMove(GLFWwindow *window, double posX, double posY)
{
static glm::vec2 lastMousePos = glm::vec2(0, 0);
if (glfwGetMouseButton(engine.getWindow(), GLFW_MOUSE_BUTTON_LEFT) == 1)
{
gYaw -= ((float)posX - lastMousePos.x) * MOUSE_SENSTIVITY;
gPitch += ((float)posY - lastMousePos.y) * MOUSE_SENSTIVITY;
}
if (glfwGetMouseButton(engine.getWindow(), GLFW_MOUSE_BUTTON_RIGHT) == 1)
{
float dx = 0.01f * ((float)posX - lastMousePos.x);
float dy = 0.01f * ((float)posY - lastMousePos.y);
gRadius += dx - dy;
}
lastMousePos.x = (float)posX;
lastMousePos.y = (float)posY;
}
This is the main code. Rest is just basic initializing code, nothing fancy.
I've tried changing the swapinterval but that doesn't seems to be the problem.
I can share code for the other classes if anyone wants to take a look. And I've also tried lowering the sub divisions.
Edit*
After increasing the value of far plane to 8000:
Still not crisp.
the edit with second image is telling you what is happening ... if tampering with znear/zfar changes output like that it means your depth buffer has low bitwidth to the range you want to use...
However increasing zfar should make things worse (you just for some reason don't see it maybe its cut off or some weird math accuracy singularity).
for me its usual to select the planes so:
zfar/znear < (2^depth_buffer_bitwidth)/2
check you depth_buffer_bitwidth
Try to use 24 bits (you might have 16 bits right now). That should work on all gfx cards these days. You can try 32 bits too but that will work only on newer cards. I am using this code to get the max I can:
What is the proper OpenGL initialisation on Intel HD 3000?
However you are using GLFW so you need to find how to do it in it ... probably there is some hint for this in it ...
increase znear as much as you can
tampering znear has much much more impact than zfar...
Use linear depth buffer
this is the best option for large depth range views like terrains that covers stuf in whole depth view range. See:
How to correctly linearize depth in OpenGL ES in iOS?
however you need shaders and new api for this... I do not think this is doable in old api but luckily you are on new api already ...
if none of above is enough
You can stack up more frustrums together at a cost of multiple rendering of the same geometry. for more info see:
Is it possible to make realistic n-body solar system simulation in matter of size and mass?
How do you initialize OpenGL?
Are you using GL_BLEND?
Using blending is nice to get anti-aliased polygon edges, however it also means your z-buffer gets updated even when a very translucent fragment is drawn. This prevents other opaque fragments with the same z-depth from being drawn, which might be what is causing those holes. You could try disabling GL_BLEND to see if the issue goes away.
What depth function are you using?
By default it is set to GL_LESS. You might want to try glDepthFunc(GL_LEQUAL); So fragments with the same z-depth will be drawn. However, due to rounding errors this might not solve your problem entirely.

OpenGL: texture rendering is stuck

while I am running the drawPlane with:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
everything is fine. The image is rendered and also my triangles.
However, while changing to
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
the texture is not updated anymore only my triangles...
How can I fix it?
void drawCursorHit() {
float cx = (hit_coord.x / (float)wWnd) * 2 - 1;
float cy = ((hit_coord.y / (float)hWnd) * 2 - 1)*-1.f;
float lx = 0.02f;
float ly = lx * 16. / 9.;
glLineWidth(1.5);
glColor3f(0.25f, 0.55f, 0.85f);
glBegin(GL_LINES);
glVertex3f(cx - lx, cy, 0.0);
glVertex3f(cx + lx, cy, 0.0);
glVertex3f(cx, cy - ly, 0.0);
glVertex3f(cx, cy + ly, 0.0);
glEnd();
}
void drawPlane() {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(0.25f, 0.55f, 0.85f);
glBegin(GL_TRIANGLES);
for (int i = 0; i < continuous_plane.triangles.size(); i++)
{
sl::float3 vertices_1 = continuous_plane.vertices.at(continuous_plane.triangles.at(i).x);
sl::float3 vertices_2 = continuous_plane.vertices.at(continuous_plane.triangles.at(i).y);
sl::float3 vertices_3 = continuous_plane.vertices.at(continuous_plane.triangles.at(i).z);
int pixel_x_1 = static_cast<int>(camera_cx + (vertices_1.x * camera_fx) / vertices_1.z);
int pixel_y_1 = static_cast<int>(camera_cy + (vertices_1.y * camera_fy) / vertices_1.z);
int pixel_x_2 = static_cast<int>(camera_cx + (vertices_2.x * camera_fx) / vertices_2.z);
int pixel_y_2 = static_cast<int>(camera_cy + (vertices_2.y * camera_fy) / vertices_2.z);
int pixel_x_3 = static_cast<int>(camera_cx + (vertices_3.x * camera_fx) / vertices_3.z);
int pixel_y_3 = static_cast<int>(camera_cy + (vertices_3.y * camera_fy) / vertices_3.z);
float x_gl_1 = (pixel_x_1 / (float)wWnd) * 2 - 1;
float y_gl_1 = ((pixel_y_1 / (float)hWnd) * 2 - 1)*-1.f;
float x_gl_2 = (pixel_x_2 / (float)wWnd) * 2 - 1;
float y_gl_2 = ((pixel_y_2 / (float)hWnd) * 2 - 1)*-1.f;
float x_gl_3 = (pixel_x_3 / (float)wWnd) * 2 - 1;
float y_gl_3 = ((pixel_y_3 / (float)hWnd) * 2 - 1)*-1.f;
glVertex3f(x_gl_1, y_gl_1, 0.0);
glVertex3f(x_gl_2, y_gl_2, 0.0);
glVertex3f(x_gl_3, y_gl_3, 0.0);
}
glEnd();
}
/**
OpenGL draw function
Render Image and wireframe mesh into a texture using the FrameBuffer
**/
void drawGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glViewport(0, 0, wWnd, hWnd);
// Render image and wireframe mesh into a texture using frame buffer
// Bind the frame buffer and specify the viewport (full screen)
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Render the ZED view (Left) in the framebuffer
glUseProgram(shader_image->getProgramId());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, imageTex);
glUniform1i(texID, 0);
//invert y axis and color for this image (since its reverted from cuda array)
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "revert"), 1);
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "rgbflip"), 1);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_vb);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glUseProgram(0);
// Unbind the framebuffer since the texture is now updated
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Render the texture to the screen
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glUseProgram(shader_image->getProgramId());
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glUniform1i(texID, 0);
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "revert"), 0);
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "rgbflip"), 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_vb);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
if (user_hit_the_screen > 0)
{
drawPlane();
drawCursorHit();
}
// Swap buffers
glutSwapBuffers();
}
You have to set glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); before the 1st glDrawArrays in the function drawGL:
void drawGL() {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
.....
glDrawArrays(GL_TRIANGLES, 0, 6);
....
if (user_hit_the_screen > 0)
{
drawPlane();
drawCursorHit();
}
glutSwapBuffers();
}
To understand the issue, you have to know that OpenGL is a state machine. Every state which is set, is kept, until it is changed again.
Further, the main loop function drawGL is executed continuously.
Note, when glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) is set in drawPlane, then the polygon rasterization mode is changes to GL_LINE.
All the states which are active when the function is left are still active at the begin, when the function is executed the next time. This means that, in the next frame, the rasterization mode is GL_LINE at the beginning.
That is what you didn't expect and is not what you want. You have to ensure that all states are proper set at the begin of the function.

Drawing a circle using OpenGL C++

I want to draw a circle in a specific position using the coordinates of the centre of the circle and its radius. All the methods that i found are using glut and none of them position the circle in a specific point.
I wanna mention that I'm new to this things and if I'm doing something wrong, I would be happy to know it.
This is what I did so far:
class Constructor
Mesh::Mesh(Vertex * vertices, unsigned int numVertices) {
m_drawCont = numVertices;
glGenVertexArrays(1, &m_vertexArrayObject);
glBindVertexArray(m_vertexArrayObject);
glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]);
//PUT ALL OF OUR VERTEX DATA IN THE ARRAY
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(vertices[0]), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
Draw Circle Method
void Mesh::DrawCircle() {
glBindVertexArray(m_vertexArrayObject);
glDrawArrays(GL_LINE_LOOP, 0, m_drawCont);
glBindVertexArray(0);
}
Main method
int main(int argc, char **argv) {
Display display(800, 600, "Window1");
Shader shader("./res/basicShader");
Vertex vertices2[3000];
for (int i = 0; i < 3000; i++) {
vertices2[i] = Vertex(glm::vec3(cos(2 * 3.14159*i / 1000.0), sin(2 * 3.14159*i / 1000.0), 0));
}
Mesh mesh3(vertices2, sizeof(vertices2) / sizeof(vertices2[0]));
while (!display.IsClosed()) {
display.Clear(0.0f, 0.15f, 0.3f, 1.0f);
shader.Bind();
mesh3.DrawCircle();
display.Update();
}
}
And this is the
output image
The code which actually creates circle vertices
as cos(x) and sin(x) function returns values is [0..1] than multiplication to some value will give us circle with radios of that value. Adding or subtracting x and y values will move the center of the circle to a specific position. fragments value specifies detalization of circle greater-better.
std::vector<Vertex> CreateCircleArray(float radius, float x, float y, int fragments)
{
const float PI = 3.1415926f;
std::vector<Vertex> result;
float increment = 2.0f * PI / fragments;
for (float currAngle = 0.0f; currAngle <= 2.0f * PI; currAngle += increment)
{
result.push_back(glm::vec3(radius * cos(currAngle) + x, radius * sin(currAngle) + y, 0));
}
return result;
}

opengl with vbo gives error 0x501

I'm trying to display a texture with height-field (think kinect here). What I got gives an 0x501 error, no idea why.
So the questions are: why am I getting this 0x501 error? And the rest of the code: should this work?
// void EC(void) is an inline function that checks for OpenGL errors and shows them
// url_width / url_height: dimensions of the frame and by that the dimensions of the texture/height field
// texture_id: id for the coordinates of each point in the texture
// vector_id: id for the vectors which set the x/y and height
// texture_color_id: id for the frame bitmap which is used for colors
// malloc
vertex_coords = new GLfloat[url_width * url_height * 6 * 3];
texture_coords = new GLfloat[url_width * url_height * 6 * 2];
// calculate x/y offsets in texture for each point
int index = 0;
for (int hMapX = 0; hMapX < url_width; hMapX++)
{
for (int hMapY = 0; hMapY < url_height; hMapY++)
{
for (int nTri = 0; nTri < 6; nTri++)
{
int x = (float)hMapX + ((nTri == 1 || nTri == 2 || nTri == 5) ? 1 : 0);
int y = (float)hMapY + ((nTri == 2 || nTri == 4 || nTri == 5) ? 1 : 0);
texture_coords[index++] = (double)x / (double)url_width;
texture_coords[index++] = (double)y / (double)url_height;
}
}
}
// copy texture pointers into videocard
glBindBuffer(GL_ARRAY_BUFFER, texture_id); EC();
int texture_bytes = url_width * url_height * 6 * 2 * sizeof(GLfloat);
glBufferData(GL_ARRAY_BUFFER, texture_bytes, NULL, GL_STATIC_DRAW); EC();
glBufferSubData(GL_ARRAY_BUFFER, 0, texture_bytes, texture_coords); EC();
// pre-initialize vertex structures
glBindBuffer(GL_ARRAY_BUFFER, vertex_id); EC();
int vertex_bytes = url_width * url_height * 6 * 3 * sizeof(GLfloat);
glBufferData(GL_ARRAY_BUFFER, vertex_bytes, NULL, GL_STATIC_DRAW); EC();
// draw function()
/////... fill vertex array with x,y and height in z
//
// copy vertexes to card
int vertex_bytes = url_width * url_height * 6 * 3 * sizeof(GLfloat);
glBindBuffer(GL_ARRAY_BUFFER, vertex_id); EC();
//
// ======> THIS OPENGL CALL FAILS WITH THE 0x501 ERROR <======
//
glBufferSubData(GL_ARRAY_BUFFER, 0, vertex_bytes, vertex_coords); EC();
// copy texture picture into card
glEnable(GL_TEXTURE_2D); EC();
glBindTexture(GL_TEXTURE_2D, texture_colors_id); EC();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bg -> w, bg -> h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bg -> pixels); EC();
glDisable(GL_TEXTURE_2D); EC();
glEnable(GL_TEXTURE_2D); EC();
glBindTexture(GL_TEXTURE_2D, texture); EC();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Verts
glBindBuffer(GL_ARRAY_BUFFER, vertex_id);
glVertexPointer(3, GL_FLOAT, 0, 0);
// Tex coords
glBindBuffer(GL_ARRAY_BUFFER, texture_id);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertex_id);
// not sure if i should use quads for this
glDrawElements(GL_QUADS, 6, GL_FLOAT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D); EC();

Hard time understanding indices with glDrawElements

I'm trying to draw a terrain with GL_TRIANGLE_STRIP and glDrawElements but I'm having a really hard time understanding the indices thing behind glDrawElements...
Here's what I have so far:
void Terrain::GenerateVertexBufferObjects(float ox, float oy, float oz) {
float startWidth, startLength, *vArray;
int vCount, vIndex = -1;
// width = length = 256
startWidth = (width / 2.0f) - width;
startLength = (length / 2.0f) - length;
vCount = 3 * width * length;
vArray = new float[vCount];
for(int z = 0; z < length; z++) {
// vIndex == vIndex + width * 3 || width * 3 = 256 * 3 = 768
for(int x = 0; x < width; x++) {
vArray[++vIndex] = ox + startWidth + (x * stepWidth);
vArray[++vIndex] = oy + heights[z][x];
vArray[++vIndex] = oz + startLength + (z * stepLength);
}
}
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vCount, vArray, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Terrain::DrawVBO(unsigned int texID, float ox, float oy, float oz) {
float terrainLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
if(!generatedVBOs) {
GenerateVertexBufferObjects(ox, oy, oz);
generatedVBOs = true;
}
unsigned int indices[] = { 0, 768, 3, 771 };
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 4, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexPointer(3, GL_FLOAT, 0, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, terrainLight);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
I believe my vArray is correct, I use the same values when drawing with glBegin(GL_TRIANGLE_STRIP)/glEnd which works just fine.
My guess was to use just the index of the x coordinate for each vertex. But I have no idea if that's the right way to use indices with glDrawElements.
0: Index of the x coordinate from the first vertex of the triangle. Location: (-128, -128).
768: Index of the x coordinate from the second vertex of the triangle. Location: (-128, -127)
3: Index of the x coordinate from the third vertex of the triangle. Location: (-127, -128)
771: Index of the x coordinate from the fourth vertex, which will draw a second triangle. Location: (-127, -127).
I think everything is making sense so far?
What's not working is that the location values above (which I doubled checked on vArray and they are correct) are not the same which glDrawElements is using. Two triangles are drawn but they are a lot bigger than what they should be. It starts correctly at (-128, -128) but it goes to something like (-125, -125) instead of (-127, -127).
I can't understand what I'm doing wrong here...
Using something like the following solves my problem:
unsigned int indices[] = { 0, 256, 1, 257 };
I think it's safe to assume that the index is the x coordinate and that OpenGL is expecting that to be followed by y and z but we shouldn't increase by 3 ourselves, the server does it for us.
And now that I think about it, glDrawElements has the word element on it, which in this case is a vertex with 3 coordinates as specified in glVertexPointer and we need to pass the indices to the element, not the vertex.
I feel so dumb now...