Related
I am attempting to draw an icosahedron following this popular OpenGl tutorial in the redBook.
I am using GLUT to handle windowing.
Here is my complete code. It is mostly the code from the tutorial plus some clerical work using GLUT
#include <stdio.h>
#include <GL/glut.h>
#define X .525731112119133606
#define Z .850650808352039932
void mouseEventHandler(int button, int state, int x, int y){
}
void display() {
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
static GLfloat vdata[12][3] = {
{-X,0.0,Z}, {X,0.0,Z}, {-X,0.0,-Z}, {X,0.0,-Z},
{0.0,Z,X}, {0.0,Z,-X}, {0.0,-Z,X}, {0.0,-Z,-X},
{Z,X,0.0}, {-Z,X,0.0}, {Z,-X,0.0}, {-Z,-X,0.0},
};
static GLuint tindices[20][3] = {
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
int i;
glBegin(GL_TRIANGLES);
for (i = 0; i < 20; i++){
glNormal3fv(&vdata[tindices[i][0]][0]);
glVertex3fv(&vdata[tindices[i][0]][0]);
glNormal3fv(&vdata[tindices[i][1]][0]);
glVertex3fv(&vdata[tindices[i][1]][0]);
glNormal3fv(&vdata[tindices[i][2]][0]);
glVertex3fv(&vdata[tindices[i][2]][0]);
}
glEnd();
glFlush ( );
}
void windowSetup(){
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(80, 80);
glutInitWindowSize(1000,1000);
glutCreateWindow("OpenGL Ico");
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode( GL_MODELVIEW);
glLoadIdentity();
gluOrtho2D( -2.0, 2.0, -2.0, 2.0 );
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
windowSetup();
glutDisplayFunc(display);
glutMouseFunc(&mouseEventHandler);
glutMainLoop();
}
This is my output:
This is very different from the expected output:
Does someone know why these differ so much?
The differences seem to be:
My icosahedron is missing faces
My icosahedron is being viewed from a different angle
My icosahedron is lit differently
The first one is the most pressing. I have noticed when I change glMatrixMode( GL_MODELVIEW); to glMatrixMode( GL_PROJECTION); the faces that aren't showing up appear and those that are currenty appearing disappear. Does anybody know why this could be?
missing faces
most likely you just have wrong order of indices. In such case Reversing them will solve the issue. To check this you can try:
glDisable(GL_CULL_FACE);
if problem disappears I am right. If not it is different thing (like too close to camera cutting by Z_NEAR but that would look a bit different).
To identify the correct face you can use glColor based on i for exaple
if (i==5) glColor3f(1.0,0.0,0.0); else glColor3f(1.0,1.0,1.0);
the red face would be the 6th in this case {8,3,10}
lighting
You are using vertex coordinates as normals so do not expect FLAT shading. Also I do not see you are setting any lights here (but that can be hidden in GLUT somewhere I do not use it). To remedy this use just single normal per triangle. so average the 3 normals you got and make an unit vector from that and use that (before first glVertex call of each triangle).
orientation
just rotate your GL_MODELVIEW to desired orientation. Standard perspective GL_PROJECTION has z axis as viewing direction and x,y axises matches the screen (while GL_MODELVIEW is unit)
[Edit1] I tried your code
So the problem is you got reverse order of indices then default polygon winding in OpenGL (at least in my environment) and wrong normals here fixed code:
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
const GLfloat vdata[12][3] =
{
{-X,0.0,Z}, {X,0.0,Z}, {-X,0.0,-Z}, {X,0.0,-Z},
{0.0,Z,X}, {0.0,Z,-X}, {0.0,-Z,X}, {0.0,-Z,-X},
{Z,X,0.0}, {-Z,X,0.0}, {Z,-X,0.0}, {-Z,-X,0.0},
};
const GLuint tindices[20][3] =
{
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11}
};
int i;
GLfloat nx,ny,nz;
glEnable(GL_CULL_FACE);
glFrontFace(GL_CW);
glBegin(GL_TRIANGLES);
for (i = 0; i < 20; i++)
{
nx =vdata[tindices[i][0]][0];
ny =vdata[tindices[i][0]][1];
nz =vdata[tindices[i][0]][2];
nx+=vdata[tindices[i][1]][0];
ny+=vdata[tindices[i][1]][1];
nz+=vdata[tindices[i][1]][2];
nx+=vdata[tindices[i][2]][0]; nx/=3.0;
ny+=vdata[tindices[i][2]][1]; ny/=3.0;
nz+=vdata[tindices[i][2]][2]; nz/=3.0;
glNormal3f(nx,ny,nz);
glVertex3fv(vdata[tindices[i][0]]);
glVertex3fv(vdata[tindices[i][1]]);
glVertex3fv(vdata[tindices[i][2]]);
}
glEnd();
And preview:
it is a screenshot and my object is rotating so do not expect correct orientation you expect.
For the sake of learning, I'm accessing individual pixel data using GLUT and manually setting pixel color by going through all pixels in the window, like this (some non-related code omitted):
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
glPointSize(1.0f);
glColor3f(255, 0, 0);
glBegin(GL_POINTS);
glVertex2i(i, j);
glEnd();
}
}
glutSwapBuffers();
}
void timer(int obsolete) {
glutPostRedisplay();
glutTimerFunc(16, timer, 0);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("GLUT Test");
init();
glutDisplayFunc(display);
timer(0);
glutMainLoop();
return 0;
}
I'm expecting to get a fully red pixels window, but I'm getting something different - a window with black vertical stripes, as if horizontal for loop suddenly skipped some lines.
Any ideas what am I doing wrong here? I have a suspicion it might be related to float to int conversion somewhere "inside", but I'm not sure what to search for.
Edit: I've found out that if I resize the window in runtime to be one pixel less in width, then these black stripe tears disappear.
You set up the projection such that the left edge is at 0, and the right one at WIDTH. Note that your pixels are small squares with an area, and this means that 0.0 maps to the left edge ot the left-most pixel, and WIDTH maps to the right edge of the right-most pixel. Integer coordinates will lie exactly in the middle between two pixels. And with some numerical precision loss during transformation, you might end up with two neighboring points beeing rounded to the same pixel.
You can either add 0.5 to x and y when drawing your points, or just shift your orth projection by half a pixel so that integers are mapped to pixel centers:
Ortho(-0.5f, WIDTH-0.5f, -0.5f, HEIGHT-0.5f, ...);
I want to make a space invader game in opengl. So I thought of creating the enemies using triangles. Before making the game, I want to try out my hand in animation. I have triangle. i want to translate it left upto some point with animation(i.e, triangle is translated after some interval of time. It should look as if it is moving).After reaching some point in the left, I want to translate it back to the same position or some distances right. The process should go on till the screen is open. I used sleep function. But it is not working. No animation is shown. Only the translated triangle is drawn at different translated position. Help me.
Here is my code-
#include "windows.h"
#include <gl/glut.h>
#include<stdio.h>
void init( void )
{
printf( "OpenGL version: %s\n", (char*)glGetString(GL_VERSION));
printf( "OpenGL renderer: %s\n", (char*)glGetString(GL_RENDERER));
//Configure basic OpenGL settings
glClearColor(1.0, 1.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,640.0,0.0,480.0);
glColor3f(1.0,0.0,0.0);
glPointSize(3);
}
void house(int x, int y,int z)
{
glPushMatrix();
glTranslatef(x, y,z);
glBegin (GL_LINES);
glVertex2i (0,30);
glVertex2i (15,60);
glVertex2i (15,60);
glVertex2i (30,30);
glVertex2i (30,30);
glVertex2i (0,30);
glEnd();
//Sleep(200);
glPopMatrix();
//glutSwapBuffers();
}
// Main drawing routine. Called repeatedly by GLUT's main loop
void display( void )
{
//Clear the screen and set our initial view matrix
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
int i;
for(i = 10; i < 350; i = i + 50)
{
house(i,20,0);
Sleep(200);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFlush();
}
// Entry point - GLUT setup and initialization
int main( int argc, char** argv )
{
glutInit( &argc, argv );
glutInitDisplayMode (GLUT_DEPTH | GLUT_SINGLE| GLUT_RGB);
glutInitWindowSize (800, 600);
glutInitWindowPosition (100, 100);
glutCreateWindow( "OpenGL Test" );
glutDisplayFunc( display );
init();
glutMainLoop();
return 0;
}
In main() you have declared your display() as display callback function. GLUT will call this function either when it determines that the window need to be redrawn or when it is told to redraw it for example by the function glutPostRedisplay().
The display function is expected to call redraw the windows at a specific point in time. The glFlush() will force the execution of the GL commands.
The problem is that your animation loop is inside the redraw function and glFlush() is called at the end, showing the result at once. And you don't tell GLUT to redraw the windows. This is why you don't seee the animation.
For the purpose of the tutorial, I propose you to define a global variable for the initial position of the house drawing. Of course, you'll have to improve this as soon as you understood how all this works.
static int pos = 10; // temporary work around, just for the demo
Then define a timer function, that gets called after a time interval. This will be the core of your animation, organizing the moving, and the redrawing of the window by calling glutPostRedisplay() :
void timerfunc(int value) // handle animation
{
pos += 50; // update the postion
if (pos<350) // as in your originial loop
glutTimerFunc(200, timerfunc, 0); // plan next occurence
glutPostRedisplay(); // redraw the window
}
Activate your timer function, in main() just before launching glutMainLoop():
glutTimerFunc(200, timerfunc, 0); // call a timer function
glutMainLoop(); // this call is already in your code
Your display function can then be changed into:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
house(pos, 20, 0); // draw the house at its last calculated position
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFlush();
}
Then it works in animated modus !
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'm trying to display a text-overlay (basically a help screen which shows my keyboard shortcuts) on top of a 3D Texture I'm rendering. The texture works great and I've got some east-to-use rotations and translations for the user.
My thought was to use
const unsigned char tmp[100] = "text to render";
glRasterPos2i(x, y);
glColor4b(255, 255, 255, 255);
glutBitmapString(GLUT_BITMAP_HELVETICA_18, tmp);
As recommended in How do I use glutBitmapString() in C++ to draw text to the screen? .
This works great except that the text now rotates with the object instead of remaining in a static location on the screen. I read some documentation and found that the glRasterPos functions are manipulated when you manipulate the model view matrix:
The object coordinates presented by glRasterPos are treated just like those of a glVertex command: They are transformed by the current modelview and projection matrices and passed to the clipping stage.
-Source
I then found via another post that you could push and pop the current matrix with glPushMatrix and glPopMatrix.
-Source
When I do this, the text disappears all together. At first I thought I might have had the coordinates wrong for the text, but I tried x=y=0 through x=y=25 in intervals of .01 and never saw the text. It's still possible I'm misunderstanding where this should be drawn, but I'm not sure what to try next.
My drawing function is calling something akin to:
glLoadIdentity();
glPushMatrix();
glTranslatef(0,0,-sdepth);
glRotatef(-stheta, 1.0, 0.0, 0.0);
glRotatef(sphi, 0.0, 0.0, 1.0);
glRotatef(rotateX,0,1,1);
glRotatef(rotateY,1,0,0);
glTranslatef(-0.5,-0.5,-0.5);
glPopMatrix();
glRasterPos2i(2, 2);
glColor4b(255, 255, 255, 255);
glutBitmapString(GLUT_BITMAP_HELVETICA_18, tmp);
Anyone have any recommendations for debug/troubleshooting steps to try to get this text to display in a single, static location on the screen?
Well, if glRasterPos is treated the same way as glVertex, then you need to set up proper projection (GL_PROJECTION) matrix (using gluOrtho2D) before calling glRasterPos.
Give this a shot:
#include <GL/glut.h>
#include <string>
using namespace std;
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3ub(255,0,0);
glPushMatrix();
glScalef(5,5,5);
glBegin(GL_QUADS);
glVertex2f(-1,-1);
glVertex2f(1,-1);
glVertex2f(1,1);
glVertex2f(-1,1);
glEnd();
glPopMatrix();
glColor3ub(0,255,0); // A
glRasterPos2i(0,0); // B
string tmp( "wha-hey!" );
for( size_t i = 0; i < tmp.size(); ++i )
{
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, tmp[i]);
}
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double aspect_ratio = (double)w / (double)h;
glOrtho(-10*aspect_ratio, 10*aspect_ratio, -10, 10, -1, 1);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(800,600);
glutCreateWindow("Text");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return EXIT_SUCCESS;
}
Oddly enough swapping lines A and B causes the glColor3ub() call to not take effect. I think that's what you were running into with the code sequence you posted.
As an aside glColor4b() takes chars which max out at 127. You should switch to glColor4ub() if you want to persist in passing in 255.
Documented here ("The sequence of glRasterPos(), glColor(), glBitmap() doesn't result in the desired bitmap color"), but no explanation given :(
EDIT: Ah ha! The current raster position contains its own color state, which is only updated during a glRasterPos() call.