I am using C++, OpenGL and glut. I am trying to make 5 houses that are rotated properly like this:
However, whenever I try to implement the glRotatef function, I seem to not be able to either get the proper coordinates or something is off somewhere in my code. Furthermore, I set the background color to white but it's still all black, how come? For now I have the houses set to white to counter this for now. Here is my code:
#include <GL/glut.h>
typedef int vert2D[2];
void initialize()
{
glClearColor(1.0, 1.0, 1.0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(10.0, 215.0, 0.0, 250.0);
glMatrixMode(GL_MODELVIEW);
}
void drawHouse(vert2D* sq, vert2D* tri)
{
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_LOOP);
glVertex2iv(sq[0]);
glVertex2iv(sq[1]);
glVertex2iv(sq[2]);
glVertex2iv(sq[3]);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2iv(tri[0]);
glVertex2iv(tri[1]);
glVertex2iv(tri[2]);
glEnd();
}
void render()
{
vert2D sqPts[4] = { {115, 150}, {115, 125}, {100,125}, {100,150} };
vert2D triPts[3] = { {120, 150}, {95,150}, {108,160} };
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glMatrixMode(GL_MODELVIEW);
drawHouse(sqPts, triPts);
glPushMatrix();
glTranslatef(1.0, 0.0, 0.0);
glRotatef(-10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glTranslatef(1.0, 0.0, 0.0);
glRotatef(-10.0, 0.0, 0.0, -1.0);
drawHouse(sqPts, triPts);
glPopMatrix();
glPushMatrix();
glTranslatef(-1.0, 0.0, 0.0);
glRotatef(10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glTranslatef(-1.0, 0.0, 0.0);
glRotatef(10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glPopMatrix();
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(640, 480);
glutCreateWindow("TestMeOut");
initialize();
glutDisplayFunc(render);
glutMainLoop();
}
Let's answer the simpler question of why your background is still black, first:
You simply never glClear(GL_COLOR_BUFFER_BIT) the color buffer. You tell OpenGL "hey, the next time I call glClear with (at least) the GL_COLOR_BUFFER_BIT, I want the color buffer to be cleared to white." but you never actually clear the buffer.
Now, onto how we can draw the houses with their correct locations and orientations:
You should first start by defining your house's vertices in a sensible local coordinate system/frame that is suitable for transforming them in further steps. Currently, with how you define your house's vertices, it is hard to do any transformations on those (mainly because linear transformations like rotation are always relative to the coordinate system's origin).
So, let's change that. Let's define the origin (0, 0) for your house to be the center of the bottom/base line of the house. And let's also define that your house's quad has a side length of 10 "units":
vert2D sqPts[4] = {
{-5, 0}, // <- bottom left
{ 5, 0}, // <- bottom right
{ 5,10}, // <- top right
{-5,10} // <- top left
};
Now, for the roof of the house, we assume the same coordinate system (with (0, 0) being the center of the house's base/bottom line), so we start at Y=10:
vert2D triPts[3] = {
{-6, 10}, // <- left
{ 6, 10}, // <- right
{ 0, 12} // <- top
};
Next, we need to define where (0, 0) should be in our "world", so to speak. One definition could be: (0, 0) should be the center of the bottom of the viewport/screen and the viewport should have a length of 100 "units". Right now, we don't care about a correct aspect ratio when the viewport's width does not equal the viewport's height. This can be added later.
Starting from the clip space coordinate system, we can transform this clip space into our own "world space" by using these transformations:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(0.0, -1.0, 0.0); // <- move the origin down to the bottom of the viewport
glScalef(1.0 / 50.0, 1.0 / 50.0, 1.0); // <- "scale down" the clip space to cover more space in the viewport
Now, the above part is essentially what gluOrtho2D() does as well, but highlighting the actual coordinate system transformation steps is useful here.
Now that we defined our house's local coordinate system and our "world" coordinate system, we can rotate and translate the world coordinate system such that the houses appear at their correct locations and orientations in our world.
In order to draw 5 houses, we just use a for-loop:
glMatrixMode(GL_MODELVIEW);
for (int i = -2; i <= 2; i++) { // <- 5 steps
glPushMatrix();
glRotatef(i * 20.0, 0.0, 0.0, 1.0);
glTranslatef(0.0, 50.0, 0.0);
drawHouse(sqPts, triPts);
glPopMatrix();
}
So, starting from our world coordinate system, we transform it by rotating the appropriate amount around its origin (0, 0) for the house with index i to have the correct rotation, and then translate the coordinate system by 50 units along its (now rotated) Y axis.
These two transformations will now result in a house to be drawn at the desired location. So, repeat that 5 times in total with differing rotation angles, and you're done.
Related
I draw many lines to form a grid. I want to see the grid rotated on its X-axis, but I never get the intended result. I tried glRotatef and gluLookAt which does not work the way I want. Please see the pictures below.
this is the grid
this is how I want to see it
Edit: geez, posting the code here is also hard, lol, anyway here it is.
Edit2: removed, only leave the code that has issues.
Please find the code below, no matter how I set the gluLookAt, the grid result won't be in the perspective I want.
#include <GL/glut.h>
void display() {
...
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
for (int i = 0; i < 720; i += 3)
{
glColor3f(0, 1, 1);
glVertex3f(linePoints[i], linePoints[i + 1], linePoints[i + 2]);
}
glEnd();
glFlush();
}
void init() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -2, 1.25, 0, 0, 0, 0, 1, 0);
}
Lets assume, that you have a grid in the xy plane of the world:
glColor3f(0, 1, 1);
glBegin(GL_LINES);
for (int i = 0; i <= 10; i ++)
{
// horizontal
glVertex3f(-50.0f + i*10.0f, -50.0f, 0.0f);
glVertex3f(-50.0f + i*10.0f, 50.0f, 0.0f);
// vertical
glVertex3f(-50.0f, -50.0f + i*10.0f, 0.0f);
glVertex3f( 50.0f, -50.0f + i*10.0f, 0.0f);
}
glEnd();
Ensure that the distance of to the far plane of the projection is large enough (see gluPerspective). All the geometry which is not in between the near an far plane of the Viewing frustum is clipped.
Further more ensure that the aspect ratio (4.0 / 3.0) match the ratio of the viewport rectangle (window).
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 200);
For the use of gluLookAt, the up vector of the view has to be perpendicular to the grid. If the grid is arranged parallel to the xy plane, then the up vector is z axis (0, 0, 1).
The target (center) is the center of the grid (0, 0, 0).
The point of view (eye position) is ought to be above and in front of the grid, for instance (0, -55, 50). Note the point of view is used for a grid with the bottom left of (-50, -50, 0) and a top right of (50, 50, 0).
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -55.0, 50.0, 0, 0, 0, 0, 0, 1);
I need to make this wheel to make a rotation animation around its center in openGL continuously without clicking the mouse,because the wheel makes its rotation if the left button of the mouse is clicked!!, this is the wheel:
This is the code I used to draw the wheel and to make the rotation:
#include <freeglut.h>
#include <glaux.h>
void whiteStud()
{
glColor3f(1.0, 1.0, 1.0);
glutSolidSphere(0.01, 16, 16);
}
void blackWheel()
{
glColor3f(0.129412, 0.129412, 0.129412);
glutSolidSphere(0.1, 16, 16);
}
void wheelWithStuds()
{
/**********************************/
int iTimeElapsed = glutGet(GLUT_ELAPSED_TIME);
float fScale= 0.5f;
long i;
/**********************************/
/* clear all pixels */
glClear(GL_COLOR_BUFFER_BIT);
/**********************************/
glPushMatrix();
glTranslatef(0.25, 0.25, 0.0);
glRotatef(iTimeElapsed * fScale,0.0,0.0,1.0);
blackWheel(); // draw the wheel without studs.
/**********************************/
// five studs, step 72 degree (72*5=360 degree).
for (i=0; i<5; i++) {
glPushMatrix();
glRotatef(72*i,0.0,0.0,1.0); // rotate coordinate 72 degree.
glTranslatef(0.04, 0.0, 0.0);// translate on the rotated coordinate.
whiteStud(); // draw the stud.
glPopMatrix();
}
glTranslatef(0.0, 0.0, 0.0);// translate in order to draw a stud at the center of the wheel.
whiteStud();// draw the stud at the center of the wheel.
/**********************************/
/* don't wait! start processing buffered OpenGL routines */
glFlush();
glPopMatrix();
/**********************************/
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(400, 400);
glutInitWindowPosition(10, 10);
glutCreateWindow("(-Rotating Car Wheel-)");
/* select clearing (background) color */
glClearColor(1.0, 1.0,1.0, 1.0);
/* initialize viewing values */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glutDisplayFunc(wheelWithStuds);
glutMainLoop();
return 0;
}
I want this wheel to rotate by itself without clicking the left button of the mouse, how can I perform this?
Here is a new draw_wheel() with the desired motion. Notably, you forgot glutPostRedisplay() at the end of the draw method; this function tells glut to redraw the window. Also you were not resetting your first call to glTranslatef(), so every time you clicked the window the object got further away from its original position.
void draw_wheel()
{
int iTimeElapsed = glutGet(GLUT_ELAPSED_TIME);
float fRevolveScale1 = 0.2f;
float fRevolveScale2 = 0.4f;
long i;
// clear all pixels
glClear(GL_COLOR_BUFFER_BIT);
// push temp state
glPushMatrix();
// translate to center
glTranslatef(0.5f, 0.5f, 0.0);
// rotate around pivot
glRotatef(iTimeElapsed * fRevolveScale1,0.0,0.0,1.0);
// translate to planet location
glTranslatef(0.25f, 0.25f, 0.0);
glRotatef(iTimeElapsed * fRevolveScale2,0.0,0.0,1.0);
glColor3f(0.129412f, 0.129412f, 0.129412f);
glutSolidSphere(0.1f, 16, 16);
// five bolts, step 72 degree (72*5=360 degree)
glColor3f(1.0, 1.0, 1.0);
for(i=0; i<5; ++i)
{
glPushMatrix();
glRotatef(72.0f*i,0.0,0.0,1.0); // rotate coordinate 72 degree
glTranslatef(0.04f, 0.0, 0.0);// translate on the rotated coordinate
glutSolidSphere(0.01f, 16, 16);
glPopMatrix();
}
glTranslatef(0.0f, 0.0f, 0.0f);// translate on the rotated coordinate
glutSolidSphere(0.01, 16, 16);
// pop temp state
glPopMatrix();
glFlush();
glutPostRedisplay();
}
I am attempting to make a simple drawing using openGL. However, the depth buffer doesn't appear to be working.
Other people with a similar problem are typically doing one of two things wrong:
Not including glEnable(GL_DEPTH_TEST)
Bad clipping values
However, my code does not have either of these problems.
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluPerspective(25.0,1.0,10.0,200.0);
// Set the camera location
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(20.0, 10.0, 50.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Cull backfacing polygons
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE)
drawCoordinateAxis();
drawBox(5.0,2.0,5.0,0.8,0.0,0.0);
glTranslated(1.0,-1.0,1.0); //The box is 5x2x5, it is shifted 1 unit down and 1 in the x and z directions
drawBox(5.0,2.0,5.0,0.0,1.0,1.0);
...
When I execute my code, this is drawn. http://imgur.com/G9y41O1
Note that the blue box and the red box collide, so the red box should be covering part of the blue box.
The functions drawCoordinateAxis() and drawBox() just draw a few primitives, nothing fancy inside.
I am running this on Debian squeeze.
void reshape(GLint width, GLint height)
{
g_Width = width;
g_Height = height;
glViewport(0, 0, g_Width, g_Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65.0, (float)g_Width / g_Height, g_nearPlane, g_farPlane);
glMatrixMode(GL_MODELVIEW);
}
So set Matrix Mode to GL_PROJECTION first, then gluPerspective.... and then back to MODELVIEW mode.
I have a code with which I generate a pawn in OpenGL. However, I want to make its parts draggable. My question is more of a general one, but here's the code for my pawn so that you get an idea of what I'm doing:
int main()
{
/* open gl initialization */
while(running())
{
glClear(GL_COLOR_BUFFER_BIT + GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glColor3ub(0, 0, 0);
/* the basis of the pawn */
glPushMatrix();
glScalef(1.6, 1.6, 0.8);
glTranslatef(0.0, 0.0, -2.7 - offset);
drawSmoothUnityEllipsoidPatch(0, 2*M_PI, 0, M_PI /2 );
glPopMatrix();
/* upped ellipsoid */
glPushMatrix();
glScalef(0.8, 0.8, 0.15);
glTranslatef(0.0 - offset, 0.0, 6.0);
drawSmoothUnitySphere();
glPopMatrix();
/* lower ellipsoid */
glPushMatrix();
glScalef(1.2, 1.2, 0.15);
glTranslatef(0.0 - offset, 0.0, -10.0);
drawSmoothUnitySphere();
glPopMatrix();
/* the cone */
glPushMatrix();
glScalef(1.0, 1.0, 3.5);
glTranslatef(0.0 + offset, 0.0, -0.5);
drawSmoothUnityCone();
glPopMatrix();
/* the sphere on top of the pawn */
glPushMatrix();
glScalef(0.7, 0.7, 0.7);
glTranslatef(0.0, 0.0, 2.3 + offset);
drawSmoothUnitySphere();
glPopMatrix();
glfwTerminate();
return 0;
}
where offset is irrelevant. The functions drawSmoothUnity(shape) just draw a unity shape in the centre of the coordinate system. I want to te able to drag and drop any of these shapes in the visible area (800x600, my window-size).
You can use gluUnproject to map your cursor position from screen space into world space. By tracking the delta of the 3D world coordinates when the mouse button was first clicked to the current position (after dragging) this gives you the x,y&z values you should use to translate your object.
Also, it should be 'glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);'
This is kind of off the top of my head and is psuedocodish. This doesn't take into account any selection or any of that. So, clicking down and moving the mouse would move the object even if the object wasn't under the mouse cursor when you clicked. You'll obviously need to add mouse handlers.
glm::dvec3 original_position;//position of object when we start moving
glm::dvec3 world_anchor;//world space coordinates of where we left clicked
glm::ivec2 screen_anchor;//screen space coordinates of where we left clicked
Object object;
OnLButtonDown(int x, int y)//x,y = where we clicked
{
original_position = object.GetPosition();
screen_anchor = ivec2(x,y);//screen coords where we clicked
gluUnproject(x,y,0,modelview_matrix,projection_matrix,viewport,&world_anchor.x,
&world_anchor.y,&world_anchor.z);
}
OnMouseMove(int x, int y) //x,y = current mouse cursor position
{
if(left_button_down)
MoveObject(screen_anchor.x-x,screen_anchor.y-y);
}
}
MoveObject(int dx, int dy)//dx,dy = distance from current mouse position to screen_anchor
{
glm::dvec3 world_position;//current mouse position in world coordinates
gluUnProject(dx,dy,0,modelview_matrix,projection_matrix,viewport,&world_position.x,
&world_position.y,&world_position.z);
glm::dev3 world_delta = world_anchor-world_position;
object.SetPosition(original_position+world_delta);
}
I've been experimenting with programs from my text book that involved clipping 2-D polygons using glOrtho and then creating glutWireSpheres in gluPerspective. My goal is to clip half the sphere with a plane, however, I am having trouble clipping 3-D objects. I created a toggle button to show the sphere clipped and unclipped, however, the button instead shows the sphere moving in a ellipse motion I believe.
Here is my drawscene for creating the sphere
double eqn0[4] = {1, 0, 0.0, -60}; // Data for clipping plane 0.
// Choose window.
glutSetWindow(id2);
gluLookAt(0.0, 3.0, 12.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glClipPlane(GL_CLIP_PLANE0, eqn0); // Specify clipping plane 0.
if (isClip0) glEnable(GL_CLIP_PLANE0); // Clip points s.t. z > 0.25.
else glDisable(GL_CLIP_PLANE0);
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
glutWireSphere(1.0, 10, 10);
glPopMatrix();
glFlush();
And here is my toggle
case '0':
if (isClip0 == 0) isClip0 = 1;
else isClip0 = 0;
glutPostRedisplay();
break;
Can someone help me get in the right direction for clipping 3-D objects? Because this will work on 2-D polygons, yet when I try to apply it to spheres, the toggle button doesn't even act like a toggle.
EDIT: Full code:
#include <cmath>
#include <iostream>
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# include <GL/glut.h>
#endif
#define PI 3.14159265
using namespace std;
// Globals.
static int id1, id2; // Window identifiers.
static int isClip0 = 0; // Is clipping plane 0 enabled?
static int isClip1 = 0; // Is clipping plane 1 enabled?
static int isClip3 = 0; // Is clipping plane 0 enabled?
static int isClip4 = 0; // Is clipping plane 1 enabled?
// Drawing routine for first window.
void drawScene1(void)
{
// Choose window.
glutSetWindow(id1);
glClear(GL_COLOR_BUFFER_BIT);
// A red square.
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex3f(10.0, 10.0, 0.0);
glVertex3f(40.0, 10.0, 0.0);
glVertex3f(40.0, 40.0, 0.0);
glVertex3f(10.0, 40.0, 0.0);
glEnd();
glFlush();
}
// Drawing routine for second window.
void drawScene2(void)
{
double eqn0[4] = {1, 0, 0.0, -1000}; // Data for clipping plane 0.
// Choose window.
glutSetWindow(id2);
gluLookAt(0.0, 3.0, 12.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glClipPlane(GL_CLIP_PLANE0, eqn0); // Specify clipping plane 0.
if (isClip0) glEnable(GL_CLIP_PLANE0); // Clip points s.t. z > 0.25.
else glDisable(GL_CLIP_PLANE0);
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
glutWireSphere(1.0, 10, 10);
glPopMatrix();
glFlush();
}
// Initialization routine for first window.
void setup1(void)
{
// Black background.
glClearColor(0.0, 0.0, 0.0, 0.0);
}
// Initialization routine for second window.
void setup2(void)
{
// Green background.
glClearColor(1.0, 1.0, 1.0, 0.0);
}
// Reshape routine for first window.
void resize1(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Non-square aspect ratio squashes the square.
glOrtho(0.0, 50.0, 0.0, 100.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Reshape routine for second window.
void resize2(int w, int h)
{
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)w/(float)h, 1.0, 50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Keyboard input processing routine shared by both windows.
void keyInput(unsigned char key, int x, int y)
{
switch(key)
{
case 27:
exit(0);
break;
case '0':
if (isClip0 == 0) isClip0 = 1;
else isClip0 = 0;
glutPostRedisplay();
break;
default:
break;
}
}
// Main routine.
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
// First top-level window definition.
glutInitWindowSize(250, 500);
glutInitWindowPosition(100, 100);
// Create the first window and return id.
id1 = glutCreateWindow("windows.cpp - window 1");
// Initialization, display, and other routines of the first window.
setup1();
glutDisplayFunc(drawScene1);
glutReshapeFunc(resize1);
glutKeyboardFunc(keyInput); // Routine is shared by both windows.
// Second top-level window definition.
glutInitWindowSize(250, 500);
glutInitWindowPosition(400, 100);
// Create the second window and return id.
id2 = glutCreateWindow("windows.cpp - window 2");
// Initialization, display, and other routines of the second window.
setup2();
glutDisplayFunc(drawScene2);
glutReshapeFunc(resize2);
glutKeyboardFunc(keyInput); // Routine is shared by both windows.
glutMainLoop();
return 0;
}
Sphere is dealt with in drawScene2
So, after adding a glLoadIdentity() right before the gluLookAt(), the movements will go away (as I already had suggested...). And when one sets a useful clip plane equation, the clipping works as expected, too. As you define a sphere with radius 1 around the object space center, setting
GLdouble eqn0[4] = {1, 0, 0.0, 0.5};
will result in the sphere being clipped at x=-0.5, so 3/4 of it is still visible, as one would expect.