Drawing a Circle with OpenGL - c++

I'm trying to manipulate some code to draw a circle instead of the triangle that is already being printed by the tutorial. I'm not super familiar with C++ or OpenGL, which is why I'm just trying it out.
Any suggestions or corrections to my code would be greatly appreciated.
I keep getting a breakpoint error in XCODE on this line:
glDrawArrays(GL_TRIANGLE_FAN, 0, numPoints); // draw the points and fill it in
and it says:
Thread 1: EXC_BAD_ACCESS(code=1, address=0x0)
Here is the original vector buffer for the triangle in the tutorial I'm following:
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
I'm pretty sure that my calculations are correct, but I don't know why it' not drawing a circle. Here is my manipulation:
// Make a circle
GLfloat x;
GLfloat y;
GLfloat z = 0.0f;
int theta = 0;
float radius = 50.0f;
int currentSize = 0;
int numPoints = 30;
GLfloat g_vertex_buffer_data[numPoints*3];
while (theta <= 360) {
x = (GLfloat) radius * cosf(theta);
y = (GLfloat) radius * sinf(theta);
g_vertex_buffer_data[currentSize++] = x;
g_vertex_buffer_data[currentSize++] = y;
g_vertex_buffer_data[currentSize++] = z;
/*
cout << "Theta: " << theta << endl;
for (int i = 0; i < currentSize; i++) {
cout << "g_vertex_buffer_data[" << g_vertex_buffer_data[i] << "]" << endl;
}
*/
theta = theta + (360/numPoints);
}
Here is the rest of the code in the .cpp file:
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data),g_vertex_buffer_data, GL_STATIC_DRAW);
do{
// Clear the screen
glClear( GL_COLOR_BUFFER_BIT );
// Use our shader
glUseProgram(programID);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(vertexPosition_modelspaceID);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
vertexPosition_modelspaceID, // The attribute we want to configure
numPoints, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the circle!
glDrawArrays(GL_TRIANGLE_FAN, 0, numPoints); // draw the points and fill it in
glDisableVertexAttribArray(vertexPosition_modelspaceID);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
// Cleanup VBO
glDeleteBuffers(1, &vertexbuffer);
glDeleteProgram(programID);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;

There are a few problems in this code. The most severe one that probably causes the crash is here:
glVertexAttribPointer(
vertexPosition_modelspaceID, // The attribute we want to configure
numPoints, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
The second argument to glVertexAttribPointer() is the number of components per vertex. Since you have 3 floats (x, y and z) per vertex, the correct value is 3. So the call should be:
glVertexAttribPointer(
vertexPosition_modelspaceID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
There is also a 1-off error where the points are created:
while (theta <= 360) {
If you include 360 in the range, you will effectively repeat the first vertex, and write one more vertex than the allocated space. This should be:
while (theta < 360) {
Also, the arguments to cosf() and sinf() are in radians. So you will have to convert the angles from degrees to radians for these functions:
x = (GLfloat) radius * cosf(theta * M_PI / 180.0f);
y = (GLfloat) radius * sinf(theta * M_PI / 180.0f);

Related

How to build data for a tessellated rectangle

I am not able to figure out the function that would be required to build data for a tessellated rectangle.
Currently this is what i do for a non tessellated rectangle;
GLuint Waveindices[] = {
0, 1, 3,
1, 2, 3
};
std::vector<GLfloat> verticesRect;
verticesRect = {
// Positions // Normal Coords // Texture Coords
width, height, 0.0f, 0.0 , 0.0, 1.0 , 1.0f, 0.0f, // Top Right
width, -height, 0.0f, 0.0 , 0.0, 1.0 , 1.0f, 1.0f, // Bottom Right
-width, -height, 0.0f, 0.0 , 0.0, 1.0 , 0.0f, 1.0f, // Bottom Left
-width, height, 0.0f, 0.0 , 0.0, 1.0 , 0.0f, 0.0f // Top Left
glGenVertexArrays(1, &m_VAO);
glGenBuffers(1, &m_VBO);
glGenBuffers(1, &m_EBO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, verticesRect.size() * sizeof(GLfloat), &verticesRect[0],
GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Waveindices), Waveindices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
};
Apologies i don't have any code for the options which i tried as i just could not get any meaning full output from the code which i wrote.
This is how the rectangle should look like when Tessellation value is 2.
What you need is to linearly interpolate between the edge points ... compute x,y,z, set texture coordinate and once finished recompute normals using cross product. Then just create triangulation and render ...
Here simple C++ (old api) example:
GLfloat divide(GLfloat a,GLfloat b){ if (fabs(b)<1e-10) return 0.0; else return a/b; }
void normalize(GLfloat *c,GLfloat *a) // c = a/|a|
{
GLfloat l=divide(1.0,sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2])));
c[0]=a[0]*l;
c[1]=a[1]*l;
c[2]=a[2]*l;
}
void cross(GLfloat *c,GLfloat *a,GLfloat *b) // c = cross(a,b)
{
GLfloat q[3];
q[0]=(a[1]*b[2])-(a[2]*b[1]);
q[1]=(a[2]*b[0])-(a[0]*b[2]);
q[2]=(a[0]*b[1])-(a[1]*b[0]);
for(int i=0;i<3;i++) c[i]=q[i];
}
void genere(GLfloat w,GLfloat h)
{
const int m=16,n=16; // points per grid axis
const int n8=n*8; // size of VBO gfx data
const int sz0=m*n8; // size of VBO gfx data
const int sz1=(m-1)*(n-1)*6;// size of indices
GLfloat dat[sz0];
GLuint idx[sz1];
int i,j,k,a,b;
GLfloat x,y,z,dx,dy,l;
GLfloat u[3],v[3],nor[3];
// gfx data
dx=2.0*w/GLfloat(n-1);
dy=2.0*h/GLfloat(m-1);
for (a=0,y=-h,j=0;j<m;j++,y+=dy)
for ( x=-w,i=0;i<n;i++,x+=dx)
{
// Vertex
z=0.3*sin((x*x)+(y*y));
dat[a]=x; a++;
dat[a]=y; a++;
dat[a]=z; a++;
// Normal (will be recomputed latter)
dat[a]=0.0; a++;
dat[a]=0.0; a++;
dat[a]=1.0; a++;
// TexCoord
dat[a]=(x+w)/(w+w); a++;
dat[a]=(y+h)/(h+h); a++;
}
// triangulation indices
for (a=0,j=1;j<m;j++)
for ( i=1;i<n;i++)
{
// b = location of point[i,j] in dat[]
b=((n*j)+i)*8;
// first triangle per quad
idx[a]=b-8; a++;
idx[a]=b-8-n8; a++;
idx[a]=b; a++;
// second triangle per quad
idx[a]=b-8-n8; a++;
idx[a]=b-n8; a++;
idx[a]=b; a++;
// recompute inner normals
for (k=0;k<3;k++)
{
u[k]=dat[idx[a-6]+k]-dat[idx[a-4]+k];
v[k]=dat[idx[a-5]+k]-dat[idx[a-4]+k];
}
cross(nor,u,v); normalize(nor,nor);
for (k=0;k<3;k++)
{
u[k]=dat[idx[a-3]+k]-dat[idx[a-1]+k];
v[k]=dat[idx[a-2]+k]-dat[idx[a-1]+k];
}
cross(u,u,v); normalize(u,u);
for (k=0;k<3;k++) dat[idx[a-1]+3+k]=0.5*(nor[k]+u[k]);
}
// copy edge normals
for (j=0,i=1;i<n;i++)
{
// b = location of point[i,j] in dat[]
b=((n*j)+i)*8;
// copy
for (k=0;k<3;k++) dat[b+3+k]=dat[b+3+k+n8];
}
for (i=0,j=1;j<m;j++)
{
// b = location of point[i,j] in dat[]
b=((n*j)+i)*8;
// copy
for (k=0;k<3;k++) dat[b+3+k]=dat[b+3+k+8];
}
// old api render (just for debug ignore this)
glBegin(GL_TRIANGLES);
for (i=0;i<sz1;i++)
{
j=idx[i];
glNormal3fv(dat+j+3);
glTexCoord3fv(dat+j+6);
glVertex3fv(dat+j);
}
glEnd();
}
Just beware that the normals are single sided so your lighting equation shoul dhandle that otherwise one side would be dark with lighting.
The normals are averaged between 2 triangles in each grid cell (if you want more smooth surface average 4 triangles).
Here preview:
If I did not make any silly mistake somewhere the data format should match yours ... So just remove the old api rendering and add the VBO stuff instead of it

OpenGL Problems with Rendering Multiple Objects

I'm brand new to OpenGL and am having some difficulty rendering multiple objects.
I have a vector each of which has its own VertexBuffer. Then, in the while loop I draw each shape on its own.
It's all well and good when I have many of the same objects (multiple cubes etc.) however, when I add a triangle mesh everything gets all out of whack.
I can have many cubes
I can have a single triangle mesh:
But, when I try to have a cube and then a triangle mesh I get:
I'm totally at a loss for what's going on. The code for my loop is provided below.
while (!glfwWindowShouldClose(window))
{
// Get the size of the window
int width, height;
glfwGetWindowSize(window, &width, &height);
float aspect_ratio = 1 * float(height)/float(width); // corresponds to the necessary width scaling
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
// Clear the framebuffer
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Enable depth test
glEnable(GL_DEPTH_TEST);
glUniform3f(program.uniform("triangleColor"), 1.0f, 1.0f, 1.0f);
glUniformMatrix4fv(program.uniform("proj"), 1, GL_FALSE, projection.data());
glUniformMatrix4fv(program.uniform("view"), 1, GL_FALSE, view.data());
int tally = 0;
for (int i = 0; i < surfaces.size(); i++) {
Surface *s = surfaces[i];
Vector3f color = s->getColor();
int tempIndex = triangleIndex;
Matrix4f model = s->getModel();
// Convert screen position to world coordinates
double xworld = ((xpos/double(width))*2)-1;
double yworld = (((height-1-ypos)/double(height))*2)-1; // NOTE: y axis is flipped in glfw
if (isPressed && mode == "translate") {
if(tempIndex == i) {
Vector4f center = s->getCenter() + model.col(3);
Vector4f displacement = Vector4f(xworld, yworld, 0, 1) - center;
Matrix4f translation = translateMatrix(displacement(0), displacement(1), displacement(2));
model = translation * s->getModel();
s->setModel(model);
}
}
glUniform3f(program.uniform("triangleColor"), color(0), color(1), color(2));
glUniformMatrix4fv(program.uniform("model"), 1, GL_FALSE, model.data());
glDrawArrays(GL_TRIANGLES, 0, s->getVertices().size());
}
And I initialize each VBO when making the object as
VertexBufferObject VBO;
VBO.init();
VBO.update(Vertices);
program.bindVertexAttribArray("position", VBO);
Surface* s = new Surface(VBO, Vertices, percentScale, 0, transformedCenter, SmoothNormals, FlatNormals, color);
s->setModel(model);
surfaces.push_back(s);
And where Program::bindVertexAttribArray is defined as
GLint Program::bindVertexAttribArray(
const std::string &name, VertexBufferObject& VBO) const
{
GLint id = attrib(name);
if (id < 0)
return id;
if (VBO.id == 0)
{
glDisableVertexAttribArray(id);
return id;
}
VBO.bind();
glEnableVertexAttribArray(id);
glVertexAttribPointer(id, VBO.rows, GL_FLOAT, GL_FALSE, 0, 0);
check_gl_error();
return id;
}
You're not binding any buffers before the draw call. You're probably simply drawing whatever buffer you last bound when you initialised them. You'll need something like this at the end of your loop before glDrawArrays:
...
program.bindVertexAttribArray("position", VBO); // where VBO is the buffer of surface s
glUniform3f(program.uniform("triangleColor"), color(0), color(1), color(2));
glUniformMatrix4fv(program.uniform("model"), 1, GL_FALSE, model.data());
glDrawArrays(GL_TRIANGLES, 0, s->getVertices().size());

How do I get rid of the red line in my OpenGL circle

Here is the output of my program.
Here is my code
#include <cstdio> // for C++ i/o
#include <iostream>
using namespace std; // to avoid having to use std::
#define GLEW_STATIC // include GLEW as a static library
#include <GLEW/glew.h> // include GLEW
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp> // include GLM (ideally should only use the GLM headers that are actually used)
using namespace glm; // to avoid having to use glm::
#include "shader.h"
#define PI 3.14159265
#define MAX_SLICES 32
#define MIN_SLICES 8
#define MAX_VERTICES (MAX_SLICES+2)*3 // a triangle fan should have a minimum of 3 vertices
#define CIRCLE_RADIUS 0.5
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
// global variables
GLfloat g_vertices[MAX_VERTICES] = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f
};
GLuint g_slices = MAX_SLICES; // number of circle slices
GLuint g_VBO = 0; // identifiers
GLuint g_VAO = 0;
GLuint g_shaderProgramID = 0;
void generate_circle()
{
float angle = PI*2 / static_cast<float>(g_slices); // used to generate x and y coordinates
float scale_factor = static_cast<float>(WINDOW_HEIGHT) / WINDOW_WIDTH; // scale to make it a circle instead of an elipse
int index = 0; // vertex index
g_vertices[3] = CIRCLE_RADIUS * scale_factor; // set x coordinate of vertex 1
// generate vertex coordinates for triangle fan
for (int i = 2; i < g_slices+2; i++)
{
// multiply by 3 because a vertex has x, y, z coordinates
index = i * 3;
g_vertices[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices[index + 2] = 0.0f;
// update to next angle
angle += PI*2 / static_cast<float>(g_slices);
}
}
static void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0); // set clear background colour
// create and compile our GLSL program from the shader files
g_shaderProgramID = loadShaders("SimpleVS.vert", "SimpleFS.frag");
// generate vertices of triangle fan
generate_circle();
// create VBO and buffer the data
glGenBuffers(1, &g_VBO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*(g_slices + 2), g_vertices, GL_STATIC_DRAW);
// create VAO and specify VBO data
glGenVertexArrays(1, &g_VAO);
glBindVertexArray(g_VAO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glEnableVertexAttribArray(0); // enable vertex attributes
}
// function used to render the scene
static void render_scene()
{
glClear(GL_COLOR_BUFFER_BIT); // clear colour buffer
glUseProgram(g_shaderProgramID); // use the shaders associated with the shader program
glBindVertexArray(g_VAO); // make VAO active
glDrawArrays(GL_LINE_LOOP, 0, g_slices+2); // display the vertices based on the primitive type
glFlush(); // flush the pipeline
}
int main(void)
{
GLFWwindow* window = NULL; // pointer to a GLFW window handle
glfwSetErrorCallback(error_callback); // set error callback function
// initialise GLFW
if(!glfwInit())
{
// if failed to initialise GLFW
exit(EXIT_FAILURE);
}
// minimum OpenGL version 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// create a window and its OpenGL context
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "DemoCode", NULL, NULL);
// if failed to create window
if(window == NULL)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window); // set window context as the current context
glfwSwapInterval(1); // swap buffer interval
// initialise GLEW
if(glewInit() != GLEW_OK)
{
// if failed to initialise GLEW
cerr << "GLEW initialisation failed" << endl;
exit(EXIT_FAILURE);
}
// set key callback function
glfwSetKeyCallback(window, key_callback);
// initialise rendering states
init();
// the rendering loop
while(!glfwWindowShouldClose(window))
{
render_scene(); // render the scene
glfwSwapBuffers(window); // swap buffers
glfwPollEvents(); // poll for events
}
// clean up
glDeleteProgram(g_shaderProgramID);
glDeleteBuffers(1, &g_VBO);
glDeleteVertexArrays(1, &g_VAO);
// close the window and terminate GLFW
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
I want to get rid of the red line coming out from the axis. I just want a hollow circle.
I'm using GL_LINE_LOOP to draw my arrays. Am I using the wrong primitive?
I have tried adjusting the coordinates in g_vertices and it does make the line smaller, but when I increase the radius of the circle, the line appears again.
You are drawing a GL_LINE_LOOP:
see Khronos group OGL Primitive documentation:
GL_LINE_LOOP: As line strips, except that the first and last vertices are also used as a line.
Thus, you get n lines for n input vertices. If the user only specifies 1 vertex, the drawing command is ignored.
The line between the first and last vertices happens after all of the previous lines in the sequence.
You initilize the first and the second vertex position with (0, 0, 0):
GLfloat g_vertices[MAX_VERTICES] = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f
};
And then you add the vertices for the circle, because your loop starts as the index starts at index 2:
for (int i = 2; i < g_slices+2; i++)
{
......
}
What you are drawing is a line from the center to the first point on the circle.
Then you draw the circle. Finally the last vertex position (on the circle) is connected to the first, which is the center point of the circle.
You have to skip the 2 vertices at the begin of the list. You do not have to initialize the first two vertices and you can start the loop at 0.
See the code above:
Definitions and global variables:
#define MAX_SLICES 32
#define MAX_VERTICES MAX_SLICES*3
GLfloat g_vertices_circle[MAX_VERTICES];
GLuint g_slices = MAX_SLICES;
Create the vertex position and color attribute array
for (int i = 0; i < g_slices; i++)
{
float angle = (float)PI * 2.0f * (float)i / float(g_slices);
int index = i * 3;
g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices_circle[index + 2] = 0.0f;
}
Set up vertex buffer object:
glGenBuffers(1, &g_VBO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * g_slices, g_vertices, GL_STATIC_DRAW);
And finally the drawing:
glDrawArrays( GL_LINE_LOOP, 0, g_slices );
Here
GLfloat g_vertices[MAX_VERTICES] = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f
};
And here:
g_vertices[3] = CIRCLE_RADIUS * scale_factor; // set x coordinate of vertex 1
// generate vertex coordinates for triangle fan
for (int i = 2; i < g_slices+2; i++)
Vertex 0 is always (0, 0, 0).

glUseProgram affecting more than just the VAO

I have successfully created a VAO which produces a triangle which can then be rotated with the mouse (with help from shaders).
My problem comes when I try to draw something else using the standard 'glBegin()' and 'glEnd()' functions. It draws successfully, but now, when I try to rotate the triangle the new drawing also rotates.
I know the problem is somehow fixed using the glUseProgram() function, but I'm not entirely sure why or where it should be added.
Here is my code (I've added it all but the main area of focus should be the display() and init() functions:
#include <GL/glew/glew.h>
#include <GL/freeglut.h>
#include <CoreStructures\CoreStructures.h>
#include <iostream>
#include "texture_loader.h"
#include "shader_setup.h"
using namespace std;
using namespace CoreStructures;
float theta = 0.0f;
bool mDown = false;
int mouse_x, mouse_y;
GLuint myShaderProgram;
GLuint locT; // location of "T" uniform variable in myShaderProgram
GLuint locR; // location of "R" uniform variable in myShaderProgram
GLuint sunPosVBO, sunColourVBO, sunIndicesVBO, sunVAO;
// Packed vertex arrays for the star object
// 1) Position Array - Store vertices as (x,y) pairs
static GLfloat sunVertices [] = {
-0.1f, 0.7f,
0.1f, 0.7f,
0.0f, 0.55f
};
// 2) Colour Array - Store RGB values as unsigned bytes
static GLubyte sunColors [] = {
255, 0, 0, 255,
255, 255, 0, 255,
0, 255, 0, 255
};
// 4) Index Array - Store indices to star vertices - this determines the order the vertices are to be processed
static GLubyte sunVertexIndices [] = {0, 1, 2};
void setupSunVAO(void) {
glGenVertexArrays(1, &sunVAO);
glBindVertexArray(sunVAO);
// copy star vertex position data to VBO
glGenBuffers(1, &sunPosVBO);
glBindBuffer(GL_ARRAY_BUFFER, sunPosVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(sunVertices), sunVertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
// copy star vertex colour data to VBO
glGenBuffers(1, &sunColourVBO);
glBindBuffer(GL_ARRAY_BUFFER, sunColourVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(sunColors), sunColors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const GLvoid*)0);
// enable position, colour buffer inputs
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
// setup star vertex index array
glGenBuffers(1, &sunIndicesVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sunIndicesVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(sunVertexIndices), sunVertexIndices, GL_STATIC_DRAW);
glBindVertexArray(0);
}
void report_version(void) {
int majorVersion, minorVersion;
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
cout << "OpenGL version " << majorVersion << "." << minorVersion << "\n\n";
}
void init(void) {
// initialise glew library
GLenum err = glewInit();
// ensure glew was initialised successfully before proceeding
if (err==GLEW_OK)
cout << "GLEW initialised okay\n";
else
cout << "GLEW could not be initialised\n";
report_version();
glClearColor(0.0, 0.0, 0.0, 0.0);
//
// setup "sun" VBO and VAO object
//
setupSunVAO();
//
// load shader program
//
myShaderProgram = setupShaders(string("Resources\\Shaders\\basic_vertex_shader.txt"), string("Resources\\Shaders\\basic_fragment_shader.txt"));
// get the index / location of the uniform variables "T" and "R" in shader program "myShaderProgram"
locT = glGetUniformLocation(myShaderProgram, "T");
locR = glGetUniformLocation(myShaderProgram, "R");
// "plug-in" shader into GPU pipeline
glUseProgram(myShaderProgram); // we're in the driving seat!!!!! Our shaders now intercept and process our vertices as part of the GPU rendering pipeline (as shown in the lecture notes)
}
// Example rendering functions - draw objects in local, or modelling coordinates
void drawSun(void) {
glBindVertexArray(sunVAO);
glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_BYTE, (GLvoid*)0);
}
void drawShape()
{
glColor3f(0.0f, 0.6f, 0.2f);
glBegin(GL_POLYGON);
glVertex2f(-1.0f, -1.0f); // Left
glVertex2f(-1.0f, -0.1f);
glVertex2f(-0.9f, -0.05f);
glVertex2f(-0.55f, -0.045f);
glVertex2f(-0.49f, -0.06f);
glVertex2f(-0.4f, -0.055f);
glVertex2f(-0.2f, -0.052f);
glVertex2f(0.0f, -0.02f); // Middle
glVertex2f(0.3f, -0.085f);
glVertex2f(0.5f, -0.08f);
glVertex2f(0.8f, -0.088f);
glVertex2f(1.0f, -0.1f);
glVertex2f(1.0f, -1.0f); // Right
glEnd();
}
//
//
void drawScene()
{
drawSun();
drawShape();
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup translation matrix and store in T. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 T = GUMatrix4::translationMatrix(0.01f, 0.01f, 0.0f);
glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);
// Setup rotation matrix and store in R. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, theta);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);
// Draw the scene (the above transformations will be applied to each vertex in the vertex shader)
drawScene();
glutSwapBuffers();
}
void mouseButtonDown(int button_id, int state, int x, int y) {
if (button_id==GLUT_LEFT_BUTTON) {
if (state==GLUT_DOWN) {
mouse_x = x;
mouse_y = y;
mDown = true;
} else if (state == GLUT_UP) {
mDown = false;
}
}
}
void mouseMove(int x, int y) {
if (mDown) {
int dx = x - mouse_x;
int dy = y - mouse_y;
float delta_theta = (float)dy * (3.142f * 0.01f);
theta += delta_theta;
mouse_x = x;
mouse_y = y;
glutPostRedisplay();
}
}
void keyDown(unsigned char key, int x, int y) {
if (key=='r') {
theta = 0.0f;
glutPostRedisplay();
}
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
initCOM();
glutInitContextVersion(3, 3);
glutInitContextProfile (GLUT_COMPATIBILITY_PROFILE);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(800, 800);
glutInitWindowPosition(0, 0);
glutCreateWindow("Combining Transforms");
glutDisplayFunc(display);
glutKeyboardFunc(keyDown);
glutMouseFunc(mouseButtonDown);
glutMotionFunc(mouseMove);
init();
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glutMainLoop();
shutdownCOM();
return 0;
}
EDIT
I have an array of x,y vertices and am trying to draw them alongside the above code. For some reason this seems to take vertex data from the sunVAO.
Is there some kind of cache that needs to be cleared? I've searched google and I can't seem to find anyone else who has conflicting VAO and vertex arrays.
(Also, I have checked my code and the vertex data supplied in the array of vertices is correct, they're just not displayed correctly.)
Code:
static GLfloat bottomMarkerVertices[] = {
-0.045f, -0.75f,
0.045f, -0.75f,
-0.07f, -1.0f,
0.07f, -1.0f
};
glVertexPointer(2, GL_FLOAT, 0, bottomMarkerVertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
note: vertex arrays have been enabled.
Assuming you're defining your coordinates in normalized device space (suggested by the apparent absence of a projection matrix), the rendering loop needs to look a little like this:
void drawScene()
{
//update shader parameters for the sun shader if necessary
drawSun();
glUseProgram(0);
// at this point, the PROJECTION and MODELVIEW matrices are both the identity
// so the shape is expected to be in NDCs and is not to be transformed
// at all
drawShape();
glUseProgram(progForSun);
}
Note that I don't advise to mix legacy and modern OpenGL like that. The results of vertex processing triggered by drawShape() are only defined because you're using a compatibility profile context.
The two elements of your scene move together because they are both using the same transformation matrices, specificed by these lines:
// Setup translation matrix and store in T. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 T = GUMatrix4::translationMatrix(0.01f, 0.01f, 0.0f);
glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);
// Setup rotation matrix and store in R. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, theta);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);
If you want drawShape() not to move with the mouse, you need to reset locR with a fixed theta value before you call it.
drawSun();
GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, 0.0f);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);
drawShape();

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...