Related
This simple program was designed to draw 13 even, red and white stripes placed alternately, as in the US flag.
// A Simple OpenGL Project
// Author: Michael Hall
//
// This C++ code and project are provided "as is" without warranty of any kind.
//
// Copyright 2010 XoaX - For personal use only, not for distribution
//
// Elaborated by me :)
#include <glut.h>
void DrawStripes(const int quantity)
{
glBegin(GL_QUADS);
for(int i=1; i <= quantity ; i++)
{
if(i%2)
glColor3f(1.0,0.0,0.0);
else
glColor3f(1.0,1.0,1.0);
glVertex2f(0,static_cast<float>(i-1)/static_cast<float>(quantity));
glVertex2f(1.0,static_cast<float>(i-1)/static_cast<float>(quantity));
glVertex2f(0,static_cast<float>(i)/static_cast<float>(quantity));
glVertex2f(1.0,2*static_cast<float>(i)/static_cast<float>(quantity));
}
}
void Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 1.0);
DrawStripes(13);
glEnd();
glFlush();
}
void Initialize()
{
glClearColor(0.0, 0.0, 102.0/255.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
int main(int iArgc, char** cppArgv)
{
glutInit(&iArgc, cppArgv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(950,500);
glutInitWindowPosition(200, 200);
glutCreateWindow("Rough draft");
Initialize();
glutDisplayFunc(Draw);
glutMainLoop();
return 0;
}
This is how it looks in practice:
Why there are blue triangles on the foreground? I've specified only "QUADS" inside Draw/DrawStripes functions.
The blue comes from your clear color:
glClearColor(0.0, 0.0, 102.0/255.0, 0.0);
That third parameter is the Blue channel of the clear color. When you call glClear(GL_COLOR_BUFFER_BIT); you initialize the render target with the clear color.
Thus the blue you are seeing is from your vertices not covering up the entire render target, and letting the blue clear color through. To see it, enable wireframe (glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);).
Also you really ought to draw in a counter-clock wise fashion: top left, bottom left, bottom right, top right. That will result in your polygons being drawn front-facing (which generally is what you want to avoid back-face culling).
At the moment your are "folding" the polygon, by doing top left, top right, bottom left, then bottom right you essentially twist the quad. Try in clockwise order (invert bottom right and bottom left) and see if you can still see the polygons (you shouldn't if back face culling is on).
Finally you also multiply only the bottom right Y coordinate by 2, why ? That is what is causing your deformation (on top of the twisting). You should have both bottom vertices with the same Y coordinate to make a rectangle (so bottom right and bottom left Y coordinate must match).
I think you're drawing the quad vertices in the wrong order. They should be counterclockwise, but you're drawing a 'twisted' quad.
Try swapping the 3rd and 4th vertex in your for loop.
How do you rotate an object in OpenGL a certain number of degrees? Is there a built-in command or do I have to use a formula? I've been stuck on this issue for days. Its a program that draws a shape under my mouse as it moves.
Say I have a drawing function:
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glColor3f ( 1, 1, 1 );
glBegin (toggle_type );
//Where cur_x and cur_y is the current mouse location that gets auto-updated
//ratiox is 0.7 and ratioy is 0.6
if (toggle_type==GL_QUADS) //rectangle from (-length, -length) to (length,length)
{
glVertex2f ( cur_x- length*ratiox, cur_y + length*ratioy );
glVertex2f ( cur_x+ length*ratiox, cur_y + length*ratioy );
glVertex2f ( cur_x+ length*ratiox, cur_y- length*ratioy );
glVertex2f ( cur_x- length*ratiox, cur_y- length*ratioy );
}
else if (toggle_type==GL_TRIANGLES)//triangle with vertices (-length, -length), (length, -length), (0, length).
{
glVertex2f ( cur_x- length, cur_y - length );
glVertex2f ( cur_x+length, cur_y - length );
glVertex2f ( cur_x, cur_y + length );
}
else if (toggle_type==GL_LINES) //line brush with vertices (0,-length), (0,length)
{
glVertex2f ( cur_x, cur_y - length );
glVertex2f ( cur_x, cur_y + length );
}
I can't just use glRotatef() before I use glBegin can I? I want to rotate the way it's drawn around my mouse a certain number of degrees. Is there not a built in function? What formula should I look into using if not?
You need to learn how to use OpenGL transforms: glTranslate, glRotate, and glScale.
Translate means "move stuff." Scale means "make stuff bigger or smaller." Rotate means what it sounds like it means.
With OpenGL transforms, it helps to think in terms of changing the coordinate system every time you issue a transform.
So to do this, let's saying you're drawing a box around the cursor. First translate to the position of the mouse cursor. That's where you want to do your drawing. Then rotate the coordinate system around the cursor, so you can draw a box easily without having to do funny stuff with sines and cosines and angles. Then, scale the object to whatever size you want it to be -- this shrinks or expands the coordinate system. Finally, just draw a one-unit-across box around the origin (0,0), and it will appear on screen in the location, rotation, and size you want.
If you try to rotate before you translate, you'll get incorrect results. The technical reason for this is that OpenGL post-multiplies transform matrices by vertex vectors.
And, yes, you should do all transforms outside of your begin/end block. Your begin/end block is just for specifying vertices, normals, etc.
I was just playing with freeglut to see if multi windows can work (seem it does!), and i was using rotations to see some change in display:
#include <cstdio>
#include <cassert>
#include <GL/freeglut.h>
#define DEGREES_X_SEC 10.0
int w_dc, w_ds;
float yRotationAngle;
void DrawSphere()
{
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glRotatef(yRotationAngle, .3f, .3f, .3f);
glutWireSphere(.3, 20, 20);
glFlush();
glutSwapBuffers();
}
void DrawCube()
{
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glRotatef(yRotationAngle, .2f, .2f, .2f);
glutWireCube(.5);
glFlush();
glutSwapBuffers();
}
void Idle()
{
static int previousTime = 0;
int currentTime = glutGet(GLUT_ELAPSED_TIME);
if (currentTime - previousTime > 10)
{
float x_frame = (DEGREES_X_SEC / 1000.0) * (currentTime - previousTime);
yRotationAngle += x_frame;
glutPostWindowRedisplay(w_dc);
glutPostWindowRedisplay(w_ds);
previousTime = currentTime;
}
}
// other code here....
int main(int argc, char *argv[])
{
// let glut eat any command line args that it owns
glutInit(&argc, argv);
// full color, double buffered
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(800, 600);
w_dc = make_window("cube", DrawCube);
glutPositionWindow(100, 100);
w_ds = make_window("sphere", DrawSphere);
glutPositionWindow(200, 200);
// not bound to any window
glutIdleFunc(Idle);
glutMainLoop();
return 0;
}
HTH, of course requires freeglut...
you need to focus an allegraic material like c 5 and m2, this is automatic rotation and will be instantly rewarded by the government because it shows abnormal behaviour, let me know if this helps.
Rog.
I hope you can help me with a little problem...
I know how to draw a circle, that's not a problem - here is the code in c#
void DrawEllipse()
{
GL.Color3(0.5, 0.6, 0.2);
float x, y, z;
double t;
GL.Begin(BeginMode.Points);
for (t = 0; t <= 360; t += 0.25)
{
x = (float)(3*Math.Sin(t));
y = (float)(3*Math.Cos(t));
z = (float)0;
GL.Vertex3(x, y, z);
}
GL.End();
}
But there is a problem - when I Rotate 'Gl.Rotate(angle, axis)' and then redraw a circle - yeah, it's still circle in the 3D, but I want a circle in the screen - I mean static circle which is not rotating with 3D object in it... Is that possible? How to repair the code?
Are you trying to draw a 2D circle on top of a 3D scene to create a HUD or similar? If you are then you should research 2D OpenGL, glOrtho and using multiple viewports in a scene. There is a discussion around this here:
http://www.gamedev.net/topic/388298-opengl-hud/
Just draw it at a position before the camera!
Use pushMatrix() and popMatrix().
Or you can draw the other things between pushMatrix() and popMatrix(). Then draw the circle.
HUD (heads-up display): http://en.wikipedia.org/wiki/HUD_(video_gaming)
void setupScene ()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// set the perspective
glFrustum(...) // or glu's perspective
}
void loop ()
{
// main scene
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport (...)
// push the camera position into GL_MODELVIEW
// (i.e. the inverse matrix of its object position)
// draw your normal 3D objects
// switch to 2D projection (for the HUD)
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(....)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw the objects onto the HUD
// switch back to 3d projection (i.e. restore GL_PROJECTION)
// glEnable (GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
// glMatrixMode(GL_MODELVIEW);
// swap buffers
}
The commented code is optional, depending on what you're gonna do in the end. Take it as hints.
I am making a rollercoaster inside of a skybox in OpenGL, and without much background on it's functions or computer graphics it is proving to be very difficult. I drew a rollercoaster using Catmull-Rom spline interpolation, and drew each point with glVertex3f. Now I want to call an update() function every 50ms to move the camera around the track. gluLookAt() is producing weird results, either removing the track from the screen, producing a black screen, etc. I think I need to move some of the matrix functions around but I am not sure where to put each one. Here is my code so far:
int main(int argc, char** argc)
{
// ... load track, etc ...
// Init currpos, nextpos, iter, up
currpos = Vec3f(0, 0, 0);
nextpos = currpos;
iter = 0;
up = Vec3f(0, 1, 0);
deque<Vec3f> points;
Vec3f newpt;
// Loop through the points and interpolate
for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++)
{
Vec3f curr(*pv); // Initialize the current point and a new point (to be drawn)
points.push_back(curr); // Push the current point onto the stack
allpoints.push_back(curr); // Add current point to the total stack
if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate
{
for (float u = 0.0f; u < 1.0f; u += 0.01f)
{
newpt = interpolate(points[0], points[1], points[2], points[3], u);
glColor3f(1, 1, 1);
glVertex3f(newpt.x(), newpt.y(), newpt.z());
allpoints.push_back(newpt);
}
points.pop_front();
}
}
// glutInit, InitGL(), etc...
}
void InitGL(GLvoid)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(100.0, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, .0001, 999999);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
}
void display (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z());
glPushMatrix();
glEnable(GL_TEXTURE_2D); // Enable texturing from now on
/* draw skybox, this was from previous assignment and renders correctly */
glPopMatrix();
// now draw rollercoaster ...
glPushMatrix();
glBegin(GL_LINE_STRIP);
deque<Vec3f> points;
Vec3f newpt;
for each (Vec3f pt in allpoints)
{
glColor3f(1, 1, 1);
glVertex3f(pt.x(), pt.y(), pt.z());
}
glutTimerFunc(50, update, 1);
glEnd();
glPopMatrix();
// Swap buffers, so one we just drew is displayed
glutSwapBuffers();
}
void update(int a)
{
if (iter < allpoints.size())
{
currpos = allpoints[iter];
nextpos = allpoints[iter + 1];
gaze = nextpos - currpos;
gaze.Normalize();
Vec3f::Cross3(binorm, gaze, up);
binorm.Normalize();
Vec3f::Cross3(up, binorm, gaze);
up.Normalize();
glutPostRedisplay();
}
iter++;
}
The idea is that I am keeping a global deque allpoints that includes the control points of the spline and the interpolated points. Once that is complete, I call update() every 50ms, and move the camera along each point in allpoints. In a previous version of the project, I could see that the rollercoaster was being drawn correctly. It is gluLookAt() that doesn't seem to work how I want it to. With the code above, the program starts with the camera looking at one side of the skybox with a part of the rollercoaster, and then when update() is called, the rollercoaster disappears but the camera does not move. I have been messing around with where I am putting the OpenGL matrix functions, and depending on where they are sometimes update() will cause a blank screen as well.
Besides the absence of glPopMatrix (which user971377 already spotted), you call glLoadIdentity in your drawing routine, which of course overwrites any changes you did on the modelview matrix in the update method (using gluLookAt).
Always keep in mind: gluLookAt, glOrtho, gluPerspective, glTranslate, glRotate, and all other matrix and transformation functions always work on the top element (changed by glPush/PopMatrix) of the currently selected matrix stack (changed by glMatrixMode). And they always multiply the current matrix, istead of replacing it. So like for gluPerspective, you should call glLoadIdentity before calling gluLookAt. And the whole camera change should be done in the rendering routine, istead of the update routine.
Instead of doing any GL transformations in update you should rather change the variables on which the camera depends and set the camera (gluLookAt on the modelview matrix) in the display method. To demonstrate the standard use of these functions, your code should be something like:
void display()
{
<general state setup (glClear, ...)>
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLookAt(camera); //view transformation (camera)
//object 1
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object 1>
glPopMatrix();
...
//object n
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object n>
glPopMatrix();
gluSwapBuffers();
}
void update()
{
camera = ...;
}
}
Noticed in your code glPushMatrix(); is called with no glPopMatrix();
Just a thought, this might have something to do with you issue.
gluLookAt always applies its result to current matrix, which in your case is GL_MODEL_VIEW. But when you render your roller coaster, you load identity in that matrix, which erase the value you put using gluLookAt.
In this case, you don't need to touch the model view. In fact, GL_MODEL_VIEW stands for model matrix multiply by view matrix. In this case, you can glPushMatrix() followed by glMulMatrix( myModelMatrix ) and after rendering glPopMatrix(). With this, you can keep your view matrix inside the GL_MODEL_VIEW and still use a different model matrix for each object
I also suggest you only change projection matrix once a frame, and not each frame.
It's been a long time since I touched OpenGL, but here are a few things to consider:
With each call to display(), you are drawing the skybox with the current matrix then loading the identity matrix to draw the roller coaster. Perhaps load the identity within the push/pop so that the skybox is constant, but your prevailing tranformations on the roller coaster are applied.
Do you need to call gluPerspective and glMatrixMode with every call to display()?
Repeatedly calculating binorm from up and then up from binorm will probably give you unexpected results in terms of rotation of the camera around the screen's z axis.
The call to gluLookAt appears to have nextpos and currpos reversed, pointing the camera in the opposite direction.
(Opinion only) It may still look wierd with a completely stationary skybox. Matching camera rotation (but not translation) when drawing the skybox and roller coaster may look better.
Alright, I'm trying to recreate the old classic, Missile Command, using OpenGL in C++. This is my first foray into OpenGL, although I feel fairly comfortable with C++ at this point.
I figured my first task was to figure out how to move 2d objects around the screen, seemed like it would be fairly simple. I created two quick method calls to make either triangles or quads:
void makeTriangle(color3f theColor, vertex2f &p1, vertex2f &p2, vertex2f &p3,
int &xOffset, int &yOffset)
{
//a triangle
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glEnd();
}
void makeQuad(color3f theColor, vertex2f &p1, vertex2f &p2, vertex2f &p3,
vertex2f &p4, int &xOffset, int &yOffset)
{
//a rectangle
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glVertex2f(p4.x, p4.y);
glEnd();
}
color3f and vertex2f are simple classes:
class vertex2f
{
public:
float x, y;
vertex2f(float a, float b){x=a; y=b;}
};
class color3f
{
public:
float red, green, blue;
color3f(float a, float b, float c){red=a; green=b; blue=c;}
};
And here is my main file:
#include <iostream>
#include "Shapes.hpp"
using namespace std;
int xOffset = 0, yOffset = 0;
bool done = false;
void keyboard(unsigned char key, int x, int y)
{
if( key == 'q' || key == 'Q')
{
exit(0);
done = true;
}
if( key == 'a' )
xOffset = -10;
if( key == 'd' )
xOffset = 10;
if( key == 's' )
yOffset = -10;
if( key == 'w' )
yOffset = 10;
}
void init(void)
{
//Set color of display window to white
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//Set parameters for world-coordiante clipping window
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-400.0,400.0,-300.0,300.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
color3f aGreen(0.0, 1.0, 0.0);
vertex2f pa(-400,-200);
vertex2f pb(-400,-300);
vertex2f pc(400,-300);
vertex2f pd(400,-200);
makeQuad(aGreen,pa,pb,pc,pd,xOffset,yOffset);
color3f aRed(1.0, 0.0, 0.0);
vertex2f p1(-50.0,-25.0);
vertex2f p2(50.0,-25.0);
vertex2f p3(0.0,50.0);
makeTriangle(aRed,p1,p2,p3,xOffset,yOffset);
glFlush();
}
int main(int argc, char** argv)
{
// Create Window.
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutCreateWindow("test");
// Some initialization.
init();
while(!done)
{
//display functions
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
// Start event loop.
glutMainLoop();
}
return 0;
}
A quad is defined as the "background" for the time being and consists of just a green rectangle along the bottom of the screen. The red triangle is the "object" that I wish to move. On a keypress, an offset is saved in the direction indicated.
I've tried using glTranslatef(xOffset,yOffset,0); but the problem with that is that it moves both elements on the screen and not just the red triangle. I attempted to put the whole call to draw the triangle between a push and pop matrix operation:
PushMatrix();
glTranslatef(xOffset,yOffset,0);
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glEnd();
PopMatrix();
As far as I can tell, that destroys any changes that the translation was doing beforehand.
I've also tried just changing the values of the x and y coordinates before calling the draw, but that just causes a brief flicker before leaving the triangle in its original position:
p1.x += xOffset;
p2.x += xOffset;
p3.x += xOffset;
p1.y += yOffset;
p2.y += yOffset;
p3.y += yOffset;
There has to be a nice simple way of doing this, and I'm just overlooking it. Could someone offer a suggestion please?
EDIT:
My actual problem was that I was never refreshing the screen after an initial draw. What I needed was to specify an idle function inside my main loop:
glutIdleFunc(IdleFunc);
Where the actual IdleFunc looks like:
GLvoid IdleFunc(GLvoid)
{
glutPostRedisplay();
}
Instead of using glFlush() inside my draw function, I should have been using glutSwapBuffers(). By doing that, the code I had first come up with:
p1.x += xOffset;
p2.x += xOffset;
p3.x += xOffset;
p1.y += yOffset;
p2.y += yOffset;
p3.y += yOffset;
Works fine for my purposes. I didn't have a need to translate the matrix, I just needed to draw the element in a different position from one scene to the next.
GL_MODELVIEW is what you need.
From the OpenGL FAQ, 2.1: http://www.opengl.org/resources/faq/technical/gettingstarted.htm
program_entrypoint
{
// Determine which depth or pixel format should be used.
// Create a window with the desired format.
// Create a rendering context and make it current with the window.
// Set up initial OpenGL state.
// Set up callback routines for window resize and window refresh.
}
handle_resize
{
glViewport(...);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set projection transform with glOrtho, glFrustum, gluOrtho2D, gluPerspective, etc.
}
handle_refresh
{
glClear(...);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set view transform with gluLookAt or equivalent
// For each object (i) in the scene that needs to be rendered:
// Push relevant stacks, e.g., glPushMatrix, glPushAttrib.
// Set OpenGL state specific to object (i).
// Set model transform for object (i) using glTranslatef, glScalef, glRotatef, and/or equivalent.
// Issue rendering commands for object (i).
// Pop relevant stacks, (e.g., glPopMatrix, glPopAttrib.)
// End for loop.
// Swap buffers.
}
You answer your own question, that is the solution:
glPushMatrix();
glTranslatef(xOffset,yOffset,0);
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glEnd();
glPopMatrix();
That will change the modelview matrix while the rectangle is drawn, then it will revert the modelview matrix back to what it were before. Did you actualy tried that? What whent wrong?
If I'm reading your code right, you want to only rotate one element right? If so, do this:
Call glPushMatrix();
then do your rotation
Store how much you've rotated
then draw your rotated item
then call glPopMatrix();
That will only rotate the one object.
EDIT:
I see that doing that "destroys" the previous rotation. Could you elaborate? That is the correct way to translate/rotate one object.
I also notice that you aren't initializing the Modelview Matrix. You should initialize the Modelview Matrix after you setup your PROJECTION matrix. You also need to make sure that you are initializing both matrices to the identity. And finally, make sure that you are initializing both matrices EVERY time the screen refreshes. To test this, set a breakpoint on your matrix initialization and see if it gets hit only once or every frame.