PDA

View Full Version : Very basic drawing problem



Debbie
11-05-2011, 03:00 PM
My problem is I have a shape that rotates using two keyboard keys and now i need to draw another shape that doesn't, i have tried doing this in the same display function but no other shape is showing. Basically i'm very new to opengl and have no idea whether i'm supposed to create a new function or use display lists and i've tried a few things to no avail.

Here's my code for the display.

void display(void)
{
glClear (GL_COLOR_BUFFER_BIT); /* clear window */
glColor3f(1.0, 1.0, 1.0); /* white drawing objects */
glLoadIdentity();
glRotatef(yRotationAngle, 0.0, 0.0, 1.0);

glBegin(GL_LINE_LOOP);
glVertex3f(0.0,0.2,0.0); //top of spaceship
glVertex3f(-0.2,-0.2,0.0); //left point of spaceship
glVertex3f(0.0,0.0,0.0); //centre of spaceship
glVertex3f(0.2,-0.2,0.0); //right point of spaceship
glEnd();
}

BionicBytes
11-05-2011, 03:03 PM
Use glPushMatrix to save the contents of the ModelView matrix between draw calls. Use glPopMatrix to restore the matrix after those draw calls.

Debbie
11-05-2011, 03:12 PM
Thanks:)

Debbie
11-05-2011, 04:20 PM
Now i have another problem. I want to draw a shape with 6 vertices but i need the vertices to be random, also i need them to be within a decimal range of -1.0 to 1.0. Here's the code i've been trying out so far.

#include "shared/gltools.h" // OpenGL toolkit - in the local shared folder
#include <stdlib.h>
#include <math.h>

//set up some constants
#define X_CENTRE 0.0 /* centre point of square */
#define Y_CENTRE 0.0
#define LENGTH 1.0 /* lengths of sides of square */

float yRotationAngle = 0;



/* reshape callback function
executed when window is moved or resized */
void reshape(int width, int height)
{
glViewport(0, 0, width, height);
/* uses orthographic (parallel) projection
use xmin = -1, xmax = 1
ymin = -1, ymax = 1
znear = -1, zfar = 1 - not relevant here (2D) */
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glMatrixMode( GL_MODELVIEW );
}



//* display callback function
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT); /* clear window */
glColor3f(1.0, 1.0, 1.0); /* white drawing objects */
glPushMatrix();
glLoadIdentity();
glRotatef(yRotationAngle, 0.0, 0.0, 1.0);


glBegin(GL_LINE_LOOP);

//specify the vertices of the spaceship
glVertex3f(0.0,0.2,0.0); //top of spaceship
glVertex3f(-0.2,-0.2,0.0); //left point of spaceship
glVertex3f(0.0,0.0,0.0); //centre of spaceship
glVertex3f(0.2,-0.2,0.0); //right point of spaceship
glEnd();
glPopMatrix();

for(int i = 0; i < 60; i++); {
GLfloat vertices[i] =(rand() % 1.0) + 0.2;
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_POLYGON, 0, 6);
glDisableClientState(GL_VERTEX_ARRAY);



glutSwapBuffers();

}





void keyboard(unsigned char key, int x, int y)
{
switch ( key )
{
case 'r': yRotationAngle = yRotationAngle + 10.0;
glutPostRedisplay();
break;
case 'e': yRotationAngle = yRotationAngle - 10.0;
glutPostRedisplay();
default: break;
}
}


/* graphics initialisation */
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0); /* window will be cleared to black */
}

int main(int argc, char** argv)
{
/* window management code ... */
/* initialises GLUT and processes any command line arguments */
glutInit(&amp;argc, argv);
/* use single-buffered window and RGBA colour model */
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
/* window width = 400 pixels, height = 400 pixels */
glutInitWindowSize (400, 400);
/* window upper left corner at (100, 100) */
glutInitWindowPosition (100, 100);
/* creates an OpenGL window with command argument in its title bar */
glutCreateWindow ("Example 1");

init();

for(int i = 0; i < 60; i++); {
GLfloat vertices[i] = (rand() % 1) + -1;
}

glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}


If you could tell me why this doesn't work and guide me to fixing it or a better way of going about it that would be amazing, thanks.

thokra
11-05-2011, 04:50 PM
for(int i = 0; i < 60; i++); {
GLfloat vertices[i] =(rand() % 1.0) + 0.2;
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_POLYGON, 0, 6);
glDisableClientState(GL_VERTEX_ARRAY);


Oh boy. :)

First of all, you for-loop does absolutely nothing than incrementing its counter since you put the semicolon before the actual instruction block.

Second, inside the block you're locally defining an array and attempt to initialize it illegally. I presume you're compiler threatens to let your computer explode for that, the undefined symbol i and the fact that you're trying to compute the integer modulus with a double constant.

Third, generating a random number in the real interval [-1,1] is NOT what you're doing with



(rand() % 1.0) + 0.2;


rand() puts out INTEGER values in the range 0..RAND_MAX. Then, the modulo operator does not accept double constants. Even if it did you'd get either 0 or 1. Adding 0.2 would even bring you out of your targeted range. One way to generate values in the range you're looking for would be for example:



float value = static_cast<float>(rand()) / static_cast<float>(RAND_MAX) * 2.f - 1.f;


Still, this wouldn't do you any good, since you're obviously trying to generate 60 random numbers. For polygon consisting of 6 vertices, and a vertex pointer defining a size 2, the maximum amount of values would be 12 - not 60.

What you probably want is:



GLfloat vertices[12];

for(int i = 0; i < 12; i++)
vertices[i] = static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
* 2.f - 1.f;

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_POLYGON, 0, 6);
glDisableClientState(GL_VERTEX_ARRAY);


HTH.

Debbie
11-06-2011, 06:29 AM
Thanks for that, it really helped me understand it better. Now i've realized that was never really going to work for my problem.
So i've gone about it a different way, I have a shape and need multiple of the same shape displayed in random positions.

I'm trying out some code to create random x and y positions which will translate my shape. But I can't get it working.


for(int i = 0; i < 2; i++)
vertices[i] = (rand());

glLoadIdentity();
glTranslatef(vertices[1],vertices[2],0.0);
glBegin(GL_POLYGON);
glVertex2f(3.0,6.0);
glVertex2f(5.0,6.0);
glVertex2f(4.0,8.0);
glVertex2f(6.0,8.0);
glVertex2f(7.0,7.0);
glVertex2f(6.0,5.0);
glVertex2f(4.0,4.0);
glEnd();

Also i need the random numbers to be between a range so will

static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
* 2.f - 1.f;

that still work for this? And after that's working will putting it all in a loop so that it displays 10 of these randomly situated shapes work? If anyone could recommend good opengl guides or tutorials as well that would be really helpful, thanks.

thokra
11-06-2011, 07:15 AM
Have you read my reply carefully?



for(int i = 0; i < 2; i++)
vertices[i] = (rand());


You need to think about what this will give you. Then, if you have n polygons and need 2 offsets per polygon, how big does you offset array need to be?

If you got that, you need to think about your projection. First I noticed the following:



/* uses orthographic (parallel) projection
use xmin = -1, xmax = 1
ymin = -1, ymax = 1
znear = -1, zfar = 1 - not relevant here (2D) */


How are the near and far clipping planes not relevant when using a parallel projection? There not called clipping planes for nothing.

Second, if you have the top, left, bottom and right set to -1/1, how do you expect to see a polygon that's been translated out of the view frustum? Add to that, your vertices are all outside the view frustum to begin with.

Third, please, please use the '['code']' tags to have the board format your code snippets!

Fourth, as for your question for good OpenGL material, Google is your friend and so is the majority of online book stores. Also, board member Alfonse has very extensive tutorial at http://www.arcsynthesis.org/gltut/. (http://www.arcsynthesis.org/gltut/) I urge you to read through from the beginning and focus especially on the projection parts (or the math in general).

Debbie
11-06-2011, 07:35 AM
Well they're not relevant to drawing my shapes because i'm not doing anything 3d. Also i have since then changed the x, y and z values of the view frustum to -10,10.

I know that if the polygon is translated out of the view frustum it won't be visible, but i have no idea how to make sure the random numbers for the translation stay within a certain range.

Thanks for the link, i'll definitely have a read through.

thokra
11-06-2011, 07:45 AM
Well, this gives you range [-1,1]:



float normalizedRandomNumber()
{
return static_cast<float>(rand()) / static_cast<float>(RAND_MAX) * 2.f - 1.f;
}


The only thing you need to know to keep the shapes visible at all times are the extents in x and y direction.

As a simple example think of a square with lenght/width = 2, centered around the origin in object space (i.e. min = (-1, -1) max = (1, 1)). Your frustum planes are symmetrically set to -10/10. the maximum offset are then equal to (abs(9), abs(9)).

With the value from the function return a value in the above range, you can simply use



x = 9.f * normalizedRandomNumber();
y = 9.f * normalizedRandomNumber();


as your offsets.

Debbie
11-06-2011, 09:26 AM
Thanks! So i now have two out of my 10 shapes in random positions. But the code is very long, i'm guessing there's a more efficient way than what i've done.


for(int i = 0; i < 20; i++)
RandomNumber[i] = static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
* 2.f - 1.f;

float x1= 9.f * RandomNumber[1];
float y1= 9.f * RandomNumber[2];
float x2= 9.f * RandomNumber[3];
float y2= 9.f * RandomNumber[4];

glLoadIdentity();
glTranslatef(x1, y1, 0.0);
glBegin(GL_POLYGON);
glVertex2f(-1.0,1.0);
glVertex2f(1.0,1.0);
glVertex2f(0.0,3.0);
glVertex2f(2.0,3.0);
glVertex2f(3.0,2.0);
glVertex2f(2.0,0.0);
glVertex2f(0.0,-1.0);
glEnd();

glLoadIdentity();
glTranslatef(x2, y2, 0.0);
glBegin(GL_POLYGON);
glVertex2f(-1.0,1.0);
glVertex2f(1.0,1.0);
glVertex2f(0.0,3.0);
glVertex2f(2.0,3.0);
glVertex2f(3.0,2.0);
glVertex2f(2.0,0.0);
glVertex2f(0.0,-1.0);
glEnd();


glutSwapBuffers();

}


Also i have two keys that rotate a different shape and every time i press them the polygons move around. How do i get them to only draw once?

thokra
11-06-2011, 10:08 AM
There're a few.

First, since the code for rendering the shape doesn't change, you can put it a separate function. Then youc call the function for every shape and only alter the translation.

Second, you can shorten the random number generation, put it in a separate function and loop trough the array of positions which further shortens the draw() function.

Then the resulting code would merely be:



void generateRandomNumbers(int count, float* numbers)
{
for(int i = 0; i < count; i++)
numbers[i] = static_cast<float>(rand()) / static_cast<float>(RAND_MAX) * 2.f - 1.f;
}

void drawShape()
{
glBegin(GL_POLYGON);
glVertex2f(-1.0,1.0);
glVertex2f(1.0,1.0);
glVertex2f(0.0,3.0);
glVertex2f(2.0,3.0);
glVertex2f(3.0,2.0);
glVertex2f(2.0,0.0);
glVertex2f(0.0,-1.0);
glEnd();
}

void draw()
{
int num_shapes = 10;

// we need an array of num_shapes * 2 offsets
float offsets[num_shapes * 2];
generateRandomNumbers(num_shapes * 2, numbers);

for(int i = 0; i < num_shapes)
{
glPushMatrix();
// i * 2 is always the first of the two offsets for shape i
glTranslatef(offsets[i * 2], offsets[i * 2 + 1], 0.f);
drawShape();
glPopMatrix();
}
}


All in all, this is simply an application of the divide-and-conquer principle. The code doesn't look shorter, but when you think about it, this thing draws 0 to n shapes without any code duplication.

Concerning the rotation I'm unsure what you want to achieve. Do you want each shape to rotate individually?

Debbie
11-06-2011, 11:09 AM
error C2057: expected constant expression
error C2466: cannot allocate an array of constant size 0
error C2133: 'offsets' : unknown size

it came back with these errors also it says a ; is missing after num_shapes in the line for(int i = 0; i < num_shapes). Not exactly sure what i've done wrong there.

I have these two pieces of code to make a shape rotate


glPushMatrix();
glLoadIdentity();
glRotatef(yRotationAngle, 0.0, 0.0, 1.0);


glBegin(GL_LINE_LOOP);

//specify the vertices of the spaceship
glVertex3f(0.0,1.0,0.0); //top of spaceship
glVertex3f(-1.0,-1.0,0.0); //left point of spaceship
glVertex3f(0.0,0.0,0.0); //centre of spaceship
glVertex3f(1.0,-1.0,0.0); //right point of spaceship
glEnd();
glPopMatrix();


void keyboard(unsigned char key, int x, int y)
{
switch ( key )
{
case 'r': yRotationAngle = yRotationAngle + 10.0;
glutPostRedisplay();
break;
case 'e': yRotationAngle = yRotationAngle - 10.0;
glutPostRedisplay();
default: break;
}
}

I want the shapes that i'm currently trying to get to randomly generate to stay still, but when i used the keys to rotate the line loop they rotated as well.

thokra
11-06-2011, 11:25 AM
Oops, screwed up the for loop and i didn't realize you were using Visual C++.



void draw()
{
int num_shapes = 10;

// we need an array of num_shapes * 2 offsets
float* offsets = new float[num_shapes * 2];
generateRandomNumbers(num_shapes * 2, offsets);

for(int i = 0; i < num_shapes; ++i)
{
glPushMatrix();
// i * 2 is always the first of the two offsets for shape i
glTranslatef(offsets[i * 2], offsets[i * 2 + 1], 0.f);
drawShape();
glPopMatrix();
}

delete [] offsets;
}


This should do it. Just draw you line loop after all shapes - that should fix the rotation problem. You have to make sure you push the identity to the stack wenn drawing the shapes!

Debbie
11-06-2011, 11:55 AM
This generated what i'm guessing is 10 shapes but they only appear in the middle very close together. I've tried changing some stuff but nothing worked. I understand all of the code apart from the numbers array, i'm not entirely sure where/how this comes into play.

thokra
11-06-2011, 12:06 PM
Dang it, screwe up again. I really should rest. :)

Change the random number generator:



void generateRandomNumbers(int count, float max_offset, float* numbers)
{
for(int i = 0; i < count; i++)
numbers[i] = (static_cast<float>(rand()) /
static_cast<float>(RAND_MAX) *
2.f - 1.f) *
max_offset;
}


and the draw function as follows:



void draw()
{
int num_shapes = 10;

// this needs to reflect the extents of your shape - play around a bit
float max_offset = 5.f;

// we need an array of num_shapes * 2 offsets
float* offsets = new float[num_shapes * 2];
generateRandomNumbers(num_shapes * 2, offsets, max_offset);

....
}


In the previous form the offset was alsways in the range [-1,1]. Now it is scaled with the maximum offset to distribute the shape more loosely.

The array stores num_shapes * 2 offsets. The loop iterates over the array and translates shape i with the offsets offsets[i * 2] and offsets[i * 2 + 1].

Why i * 2? Because your array stores n * 2 offsets where n is the number of shapes. For each shape you need 2 offsets. The first pair starts at offsets[0], the second at offsets[2] and so on. Since i takes values {0, 1, 2, ... , n - 1}, you select the first index of a pair with i * 2. The second is alway i * 2 + 1.

Debbie
11-06-2011, 12:37 PM
It says it cannot covert parameter 2 from 'float*' to 'float'

Also the code


void generateRandomNumbers(int count, float max_offset, float* numbers)
{
for(int i = 0; i < count; i++)
numbers[i] = (static_cast<float>(rand()) /
static_cast<float>(RAND_MAX) *
2.f - 1.f) *
max_offset;
}

I'm not entirely sure how number[i] gets used because it's never used again in the code. Thanks for your help, i really would have been stuck for days if i had to find out how to do this through google searches.

thokra
11-06-2011, 12:53 PM
Obviously I'm going completely insane.

Correct the draw method as follows:


// in the draw function
generateRandomNumbers(num_shapes * 2, max_offset, offsets);




I'm not entirely sure how number[i] gets used because it's never used again in the code.


Of course it is. The address of the first element of the array 'offsets' in the draw() function is passed to the random number generator function as a pointer. Therefore the function alters the contents off the array 'offsets'.

Since passing arguments "by reference" (or pointer) is something every C/C++ programmer should understand, I urge you to carefully work through a comprehensive tutorial like this one: http://www.cplusplus.com/doc/tutorial/

BTW, if it doesn't work now I'm throwing my computer out the window. :)

Debbie
11-06-2011, 01:20 PM
Yeah it works now :) Thank you so much for all your help!