Faces missing when drawing icosahedron in OpenGL following code in redBook - opengl

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.

Related

Rotate a simple polygon in OpenGL

I follow the code tutorial from the OpenGL programming book, but it doesn't work. It is showing white rectangle at the top left of my window. Could you please tell me what could be wrong with it?
#include<windows.h>
#include <GL/glut.h>
float yRot=0.0;
void Render()
{
//clear color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();//load identity matrix
glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units
//rotate along the y-axis
glRotatef(yRot,0.0f,1.0f,0.0f);
glColor3f(0.0f,0.0f,1.0f); //blue color
glBegin(GL_POLYGON);//begin drawing of polygon
glVertex3f(-0.5f,0.5f,0.0f);//first vertex
glVertex3f(0.5f,0.5f,0.0f);//second vertex
glVertex3f(1.0f,0.0f,0.0f);//third vertex
glVertex3f(0.5f,-0.5f,0.0f);//fourth vertex
glVertex3f(-0.5f,-0.5f,0.0f);//fifth vertex
glVertex3f(-1.0f,0.0f,0.0f);//sixth vertex
glEnd();//end drawing of polygon
yRot+=0.1f;//increment the yRot variable
}
//method the reshape the entire figure.
void reshape(int x, int h){
glViewport(0,0,x,h);
}
void init()
{
glClearColor(0.0,0.0,0.2,0.8);
}
int main(int argc, char** argv)
{
glutCreateWindow("simple triangles");
glutDisplayFunc(Render);
glutReshapeFunc(reshape);
init();
glutMainLoop();
}
First of all, you're not calling glutInit(&argc, argv) in main() before all the other GLUT related calls. Second of all, you're not calling glutSwapBuffers() in Render().
Besides that you aren't changing the projection matrix, and thus don't have the same resize function as the one presented in the beginning of the tutorial.
void Resize(int width, int height)
{
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Changing those things and your code should work.

GLUT mouse Tracking and Drawing

I am making a simple GLUT program which tracks the mouse and put points on the path.
Well This is my code:
void init()
{
glClearColor( 0.0, 0.0, 1.0, 1.0);
glMatrixMode( GL_PROJECTION);
gluOrtho2D( 0.0, 400.0, 0.0, 400.0);
for(int i=0;i<5000;i++)
{
arr[i][0]=0;
arr[i][1]=0;
}
glPointSize(10.0);
}
void drawPoints()
{
glBegin( GL_POINTS );
glColor3f( 0.0,0.0,0.0 );
for ( int i = 0; i < z; i++ )
{
glVertex2f( arr[i][0], arr[i][1]);
}
glEnd();
}
void myDisplay()
{
glClear( GL_COLOR_BUFFER_BIT);
drawPoints();
glutSwapBuffers();
glutPostRedisplay();
}
void myMouseMove( int x, int y)
{
arr[z][0]=x;
arr[z++][1]=y;
}
int main( int argc, char ** argv)
{
glutInit( &argc, argv);
glutInitDisplayMode( GLUT_DOUBLE| GLUT_RGB);
glutInitWindowPosition( 100, 100);
glutInitWindowSize(600,600);
glutCreateWindow( "Testing");
init();
glutDisplayFunc( myDisplay);
glutPassiveMotionFunc( myMouseMove);
glutMainLoop();
return 0;
}
However I am having few problems:
Y coordinate runs in opposite direction.
Draws point ahead of cursor position(while moving in a direction).
Is there any better way to do this?
The Y coordinate being flipped is actually expected behavior. Simply correct for it in your code and you should be fine.
If you want to make sure that your rendered image and mouse cursor are completely synchronized, simply have glut hide the mouse cursor, and then render it yourself using OpenGL.
You should be aware that when using a traditional projection matrix in OpenGL: (0,0) is the lower-left corner. Most window systems will map (0,0) to the top-left corner.
In some circumstances, you can make them match up simply by swapping the bottom/top fields in your call to glOrtho (...) or gluOrtho2D (...) - this has other consequences like reversing polygon winding, so it is not always the best approach.
As for "drawing points ahead of the cursor," I think you may be describing input latency (particularly if you are using VSYNC).
When you use a software cursor vs. hardware cursor the position of the mouse may be off by one or more frames. There is a somewhat technical discussion here (see: Idiosyncrasies) on the effect of buffer swap intervals (OpenGL's mechanism for VSYNC) on input latency.
To fix the inversion do 600 - y for setting arr element. Also your gluOrtho2D is on a scale of 400 by 400 while your windows is 600 by 600 so change your gluOrtho2D scale to the same as the window size and you'll be fine.

Mapping coordinates from 3D perspective projection to 2D orthographic projection in OpenGL in C++

I have written a simple openGL program in C++. This program draws a sphere in 3D perspective projection and tries to draw a line joining the center of the sphere to the current cursor position in 2D orthographic projection. Now for drawing the line I can't figure out the coordinate of center of the sphere.
This is my code :
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
void passive(int,int);
void reshape(int,int);
void init(void);
void display(void);
void camera(void);
int cursorX,cursorY,width,height;
int main (int argc,char **argv) {
glutInit (&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
glutInitWindowSize(1364,689);
glutInitWindowPosition(0,0);
glutCreateWindow("Sample");
init();
glutDisplayFunc(display);
glutIdleFunc(display);
glutPassiveMotionFunc(passive);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display() {
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render 3D content
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60,(GLfloat)width/(GLfloat)height,1.0,100.0); // create 3D perspective projection matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
camera();
glTranslatef(-6,-2,0);
glColor3f(1,0,0);
glutSolidSphere(5,50,50);
glPopMatrix();
// Render 2D content
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width,height, 0); // create 2D orthographic projection matrix
glMatrixMode(GL_MODELVIEW);
glColor3f(1,1,1);
glBegin(GL_LINES);
glVertex2f( centreX,centreY ); // coordinate of center of the sphere in orthographic projection
glVertex2f( cursorX,cursorY );
glEnd();
glutSwapBuffers();
}
void camera(void) {
glRotatef(0.0,1.0,0.0,0.0);
glRotatef(0.0,0.0,1.0,0.0);
glTranslated(0,0,-20);
}
void init(void) {
glEnable (GL_DEPTH_TEST);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_COLOR_MATERIAL);
}
void reshape(int w, int h) {
width=w; height=h;
}
void passive(int x1,int y1) {
cursorX=x1; cursorY=y1;
}
I can,t figure out the values for centreX and centreY. Anyway I can get the correct values to draw the line?
You may be interested in using something like gluProject to go from your object coordinates to the actual (projected) position on screen. Once you have the screen coordinates of the object, it's easy to draw a line from one point to another.
In this case, you'll want to project the centre point of the sphere. For more complex objects I've found that it makes sense to project all of the corners of the object's bounding box and then take the extents of the screenspace position of those corners.
You should get the modelview, viewport and projection matrices before you switch to your orthographic projection (2D mode).
Obviously, in order to go from a screen position (say, where you clicked in the window) to a world position, you'll want to use its companion function, gluUnProject.
Note that the coordinates that come out of gluProject do not necessarily correspond directly to the window position; you might have to flip the "Y" coordinate.
Take a look at this GDSE discussion for some other ideas about how to solve the problem.

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?

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.

Calling glRasterPos2i and glutBitmapString in the presence of ModelView transforms

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.