I was trying to make a small wave generator in OpenGL with C++, using an evaluator.
However, I haven't had much luck since my evaluator only gets partially lit.
Why does this happen?
Below I include full source code for completeness' sake, you'll probably only have to look at init(), display() and the constants at the top of the file.
#include <gl/glui.h>
#include <math.h>
const int DIMX = 500;
const int DIMY = 500;
const int INITIALPOS_X = 200;
const int INITIALPOS_Y = 200;
// Aspect ratio (calculated on the fly)
float xy_aspect;
// UI aux. matrices
float view_rotate[16] = { 1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1 };
float obj_pos[] = { 0.0, 0.0, 0.0 };
float obj_pan[] = { 0.0, 0.0, 0.0 };
// Referential axis
double axis_radius_begin = 0.2;
double axis_radius_end = 0.0;
double axis_lenght = 16.0;
int axis_nslices = 8;
int axis_nstacks = 1;
// Light 0 properties
float light0_position[] = {5.0, 5.0, 5.0, 0.0};
float light0_ambient[] = {0.0, 0.0, 0.0, 1.0};
float light0_diffuse[] = {0.6, 0.6, 0.6, 1.0};
float light0_specular[] = {1.0, 1.0, 1.0, 1.0};
float light0_kc = 0.0;
float light0_kl = 1.0;
float light0_kq = 0.0;
double light0x = 5.0;
double light0y = 5.0;
double light0z = 5.0;
double symb_light0_radius = 0.2;
int symb_light0_slices = 8;
int symb_light0_stacks =8;
// Ambient light source properties
float light_ambient[] = {0.5, 0.5, 0.5, 1.0}; /* Set the background ambient lighting. */
// Windowing related variables
int main_window;
GLUquadric* glQ;
GLUI *glui;
const unsigned int gridSize = 40;
float grid[gridSize][gridSize][3];
const int uSize = gridSize;
const int vSize = gridSize;
GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat position[] = {0.0, 0.0, 2.0, 1.0};
GLfloat mat_diffuse[] = {0.6, 0.6, 0.6, 1.0};
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
float mat_shininess[] = {50.0};
void display(void) {
static float value = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -xy_aspect*.04, xy_aspect*.04, -.04, .04, .1, 50.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( obj_pos[0], obj_pos[1], -obj_pos[2]-25 );
glTranslatef( obj_pan[0], obj_pan[1], obj_pan[2] );
glRotated( 20.0, 1.0,0.0,0.0 );
glRotated(-45.0, 0.0,1.0,0.0 );
glMultMatrixf( view_rotate );
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glColor3f(1.0,0.0,0.0);
glPushMatrix();
glRotated(90.0, 0.0,1.0,0.0 );
gluCylinder(glQ, axis_radius_begin, axis_radius_end,
axis_lenght, axis_nslices, axis_nstacks);
glPopMatrix();
glColor3f(0.0,1.0,0.0);
glPushMatrix();
glRotated(-90.0, 1.0,0.0,0.0 );
gluCylinder(glQ, axis_radius_begin, axis_radius_end,
axis_lenght, axis_nslices, axis_nstacks);
glPopMatrix();
glColor3f(0.0,0.0,1.0);
glPushMatrix();
gluCylinder(glQ, axis_radius_begin, axis_radius_end,
axis_lenght, axis_nslices, axis_nstacks);
glPopMatrix();
light0_position[0] = light0x;
light0_position[1] = light0y;
light0_position[2] = light0z;
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glColor3f(1.0,1.0,0.0);
gluQuadricOrientation( glQ, GLU_INSIDE);
glPushMatrix();
glTranslated(light0x,light0y,light0z);
gluSphere(glQ, symb_light0_radius, symb_light0_slices, symb_light0_stacks);
glPopMatrix();
gluQuadricOrientation( glQ, GLU_OUTSIDE);
gluQuadricDrawStyle(glQ, GLU_FILL);
gluQuadricNormals(glQ, GLU_SMOOTH);
gluQuadricOrientation(glQ, GLU_OUTSIDE);
gluQuadricTexture(glQ, GL_FALSE);
for (unsigned int y = 0; y < vSize; ++y) {
for (unsigned int x = 0; x < uSize; ++x) {
float xVal = 5*3.14/gridSize*x;
float yVal = 5*3.14/gridSize*y;
grid[y][x][0] = (float) x/gridSize*10.0;
grid[y][x][1] = sin(xVal + value) + sin(yVal + value);
grid[y][x][2] = (float) y/gridSize*10.0;
}
}
glMap2f(GL_MAP2_VERTEX_3, 0, 1 , 3, uSize, 0, 1, uSize * 3, vSize, &grid[0][0][0]);
glEvalMesh2(GL_FILL, 0, gridSize, 0, gridSize);
value += 3.14/25;
if (value > 3.14*2)
value = 0;
// swapping the buffers causes the rendering above to be shown
glutSwapBuffers();
glFlush();
}
/* Mouse handling */
void processMouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
}
glutPostRedisplay();
}
void processMouseMoved(int x, int y)
{
// pedido de refrescamento da janela
glutPostRedisplay();
}
void processPassiveMouseMoved(int x, int y)
{
// pedido de refrescamento da janela
glutPostRedisplay();
}
void reshape(int w, int h)
{
int tx, ty, tw, th;
GLUI_Master.get_viewport_area( &tx, &ty, &tw, &th );
glViewport( tx, ty, tw, th );
xy_aspect = (float)tw / (float)th;
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27: // tecla de escape termina o programa
exit(0);
break;
}
}
void glut_idle( void )
{
if ( glutGetWindow() != main_window )
glutSetWindow(main_window);
glutPostRedisplay();
}
void init()
{
glQ = gluNewQuadric();
glFrontFace(GL_CCW); // Front faces defined using a counterclockwise rotation
glDepthFunc(GL_LEQUAL); // Por defeito e GL_LESS
glEnable(GL_DEPTH_TEST); // Use a depth (z) buffer to draw only visible objects
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
// Face Culling para aumentar a velocidade
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); // GL_FRONT, GL_BACK, GL_FRONT_AND_BACK
// Define que modelo de iluminacao utilizar; consultar o manual de referencia
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_ambient); // define luz ambiente
glLightModelf (GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
// por defeito a cor de fundo e o preto
// glClearColor(1.0,1.0,1.0,1.0); // cor de fundo a branco
// declaracoes para a fonte luz GL_LIGHT0
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, light0_kc);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, light0_kl);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, light0_kq);
// NOTA: a direccao e a posicao de GL_LIGHT0 estao na rotina display(), pelo
// que as isntrucoes seguntes nao sao necessarias
//glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 90.0);
//glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
//glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_MAP2_VERTEX_3);
glMapGrid2f(gridSize, 0.0, 1.0, gridSize, 0.0, 1.0);
glShadeModel(GL_SMOOTH);
glPolygonMode(GL_FRONT, GL_FILL);
//glPolygonMode(GL_FRONT, GL_LINE);
}
void do_nothing(int key, int x, int y) {}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize (DIMX, DIMY);
glutInitWindowPosition (INITIALPOS_X, INITIALPOS_Y);
main_window = glutCreateWindow (argv[0]);
glutDisplayFunc(display);
GLUI_Master.set_glutReshapeFunc(reshape);
GLUI_Master.set_glutKeyboardFunc (keyboard);
GLUI_Master.set_glutMouseFunc(processMouse);
glutMotionFunc(processMouseMoved);
glutPassiveMotionFunc(processPassiveMouseMoved);
GLUI_Master.set_glutSpecialFunc( do_nothing );
/*** Create the bottom subwindow ***/
glui = GLUI_Master.create_glui_subwindow( main_window, GLUI_SUBWINDOW_BOTTOM );
glui->set_main_gfx_window( main_window );
GLUI_Rotation *view_rot = glui->add_rotation( "Rotation", view_rotate );
view_rot->set_spin( 1.0 );
glui->add_column( false );
GLUI_Translation *trans_z = glui->add_translation( "Zoom", GLUI_TRANSLATION_Z, &obj_pos[2] );
trans_z->set_speed( .1 );
glui->add_column(false);
GLUI_Translation *trans_pan = glui->add_translation("Pan", GLUI_TRANSLATION_XY, &obj_pan[0]);
trans_pan->set_speed(.1);
GLUI_Master.set_glutIdleFunc( glut_idle );
init();
glutMainLoop();
return 0;
}
You say OpenGL evaluators don't need normals to set. This is only partly true. You only don't need to set normals if you enable automatically generated normals for evaluators by calling:
glEnable(GL_AUTO_NORMAL);
Just enabling GL_NORMALIZE won't do it.
But you can of course also specify your own normals by providing control points for GL_MAP2_NORMAL in the same way like for GL_MAP2_VERTEX_3.
And the answer won't be complete without mentioning that OpenGL evaluators are highly deprecated and most probably implemented in softare by the driver. So just rolling your own Bezier evaluation code (which is not very hard) and generating a simple mesh grid drawn as GL_TRIANGLES will surely be a better idea.
Related
I have to make a program which is doing the collision between two spheres. I made this but when the spheres collide everything is blocked. I can't move the sphere anymore. I made only the sphere1 to move and the other to be static. The code is written in VB/ C++.
#include "GLOS.H"
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <glaux.h>
GLfloat max1=0,max2=0,v,v1;
FLOAT d,distanta=0;
int i,j;
void myinit(void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK MutaStanga(void);
void CALLBACK MutaDreapta(void);
int k=0,k1=0;
int dist_ramasa;
static float dx1=200,dy1=300,dz1=0;
int deplasare=100;
float rez;
static int flag=1;
float pxc,pyc,pzc,sum,suma_raze;
void myinit (void) { //iluminating
glClearColor(1.0, 1.0, 1.0, 1.0);
GLfloat mat_ambient[] = { 0.3, 0.3, 0.3, 1.0 };
GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 100.0 };
GLfloat light_ambient[] = { 0.4, 0.4, 0.4, 1.0 };
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_position[] = { 1.0, 1.0, 0.0, 0.0 };
GLfloat lmodel_ambient[] = { 0.5, 0.5, 0.5, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glEnable(GL_LIGHTING); // activare iluminare
glEnable(GL_LIGHT0); // activare sursa 0
glColorMaterial(GL_FRONT,GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}
struct sfera //the spheres
{
GLfloat raza, xcentru, ycentru, zcentru; //the radius and the centers
GLfloat xd1,xd2,yd1,yd2,zd1,zd2;
}sf[2];
void initRaza(){ //radius init
sf[0].raza=100;
sf[1].raza=100;
}
int conditie(void){ //this is where I verify if collide
initRaza();
double xac1,yac1,zac1,xac2,yac2,zac2;//the new centers after the movement
xac1=sf[0].xcentru+dx1;
yac1=sf[0].ycentru+dy1;
zac1=sf[0].zcentru+dz1;
//static sphere
xac2=sf[1].xcentru+700;
yac2=sf[1].ycentru+300;
zac2=sf[1].zcentru;
pxc = pow((xac1-xac2),2);
pyc = pow((yac1-yac2),2);
pzc = pow((zac1-zac2),2);
sum=(pxc + pyc + pzc);
distanta=sqrt(sum); //the distance between the centers
//the sum of the radiuses
suma_raze=sf[0].raza+sf[1].raza;
dist_ramasa=distanta-sf[0].raza-sf[1].raza;
// we compare the distance and the sum of radiuses
//if the distance is lower than the sum -> collide
if(distanta>suma_raze)
return 1;
else
return 0;
}
void CALLBACK MutaStanga(void) //movement left
{
if(conditie()==1){
if(dist_ramasa<deplasare)
dx1=dx1-dist_ramasa;
else
dx1=dx1-deplasare;
}
}
void CALLBACK MutaDreapta(void) //movement right
{
if(conditie()==1){
if(dist_ramasa<deplasare)
dx1=dx1+dist_ramasa;
else
dx1=dx1+deplasare;
}
}
void CALLBACK MutaSus(void) //movement up
{
if(conditie()==1){
if(dist_ramasa<deplasare)
dy1=dy1+dist_ramasa;
else
dy1=dy1+deplasare;
}
}
void CALLBACK MutaJos(void) //movement down
{
if(conditie()==1){
if(dist_ramasa<deplasare)
dy1=dy1-dist_ramasa;
else
dy1=dy1-deplasare;
}
}
void drawBall1() //the first sphere
{
glPushMatrix();
glColor3f(0,1,0);
glTranslatef(dx1, dy1, 0.0);
glRotatef(30,1,0,0);
auxSolidSphere(sf[0].raza);
glPopMatrix();
}
void drawBall2() //the second sphere
{
glPushMatrix();
glColor3f(1,0,0);
glTranslatef(700,300,0);
glRotatef(30,1,0,0);
auxWireSphere(sf[1].raza);
glPopMatrix();
}
void CALLBACK display (void)
{
initRaza();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity ();
drawBall1();
drawBall2();
auxSwapBuffers();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
if (!h) return;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (0, 800.0, 0*(GLfloat)h/(GLfloat)w,
-860.0*(GLfloat)h/(GLfloat)w, -200.0, 200.0);
else
glOrtho (0*(GLfloat)w/(GLfloat)h,
900.0*(GLfloat)w/(GLfloat)h, 0, 900.0, -500.0, 500.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
auxInitPosition (0, 0, 900, 700);
auxInitWindow ("Bounding sphere collision");
myinit ();
auxKeyFunc (AUX_LEFT, MutaStanga);
auxKeyFunc (AUX_RIGHT, MutaDreapta);
auxKeyFunc (AUX_UP, MutaSus);
auxKeyFunc(AUX_DOWN,MutaJos);
auxReshapeFunc (myReshape);
auxMainLoop(display);
return(0);
}
I don't know what is not working. When they collide I want to reject each other . I hope you can help me.
Once the spheres collide, your function conditie will return 1. All your keypress functions check this before modifying the sphere's position, thus, once they collide, you can no longer move the sphere.
Currently, I'm drawing a big room, and it's all good and pretty:
But, it's blue, so I figure, ok, I'll just disable lighting first, and then draw the room, re-enable it later, and it'll work out fine, right?
I suppose not... It loses its "depth" entirely.
Can I not simply do:
glDisable(GL_LIGHTING);
glColor3f(51/255.0, 25/255.0,0.0);
drawstuffhere
glEnable(GL_LIGHTING);
Or is this influenced by my initial lighting setup?
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST); // Enable depth testing.
// Turn on OpenGL lighting.
glEnable(GL_LIGHTING);
// Light property vectors.
float lightAmb[] = { 0.0, 0.0, 0.0, 1.0 };
float lightDifAndSpec0[] = { 1.0, 1.0, 1.0, 1.0 };
float lightDifAndSpec1[] = { 1.0, 1.0, 0.0, 1.0 };
float globAmb[] = { 0.2, 0.2, 0.2, 1.0 };
// Light0 properties.
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDifAndSpec0);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightDifAndSpec0);
// Light1 properties.
glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmb);
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDifAndSpec1);
glLightfv(GL_LIGHT1, GL_SPECULAR, lightDifAndSpec1);
glEnable(GL_LIGHT0); // Enable particular light source.
glEnable(GL_LIGHT1); // Enable particular light source.
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globAmb); // Global ambient light.
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); // Enable local viewpoint
// Cull back faces.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
EDIT: Source code: http://pastebin.com/DKGpWiFB
///////////////////////////////////////////////////////////////////////////////////////////
// main.cpp
//
///////////////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# include <GL/glut.h>
#endif
using namespace std;
//Structures
struct perspectives {
float ex,ey,ez,cx,cy,cz;
int x, y, z;
};
struct coordinates {
float x, y, z;
};
// Globals.
static float a = .1; // Blue ambient reflectance.
static float d = 1.0; // Blue diffuse reflectance.
static float s = 1.0; // White specular reflectance.
static float h = 50.0; // Shininess.
static float e = 0.0; // Blue emittance.
static float t = 0.0; // Quadratic attenuation factor.
static float zMove = 0.0; // z-direction component.
static char theStringBuffer[10]; // String buffer.
static long font = (long)GLUT_BITMAP_8_BY_13; // Font selection.
static bool cameraRotate = false;
struct perspectives camera = {0,0,12,0,0,0,0,1,0};
struct coordinates key = {0,0,11};
// Routine to draw a bitmap character string.
void writeBitmapString(void *font, char *string)
{
char *c;
for (c = string; *c != '\0'; c++) glutBitmapCharacter(font, *c);
}
// Routine to convert floating point to char string.
void floatToString(char * destStr, int precision, float val)
{
sprintf(destStr,"%f",val);
destStr[precision] = '\0';
}
//Routine to draw a ball of light
void drawMoon()
{//TODO
// Light position vectors.
float lightPos[] = { 3, 4, -.2, 1.0 };
glDisable(GL_LIGHTING);
// Light0 and its sphere positioned.
glPushMatrix();
glLightfv(GL_LIGHT1, GL_POSITION, lightPos);
glTranslatef(lightPos[0], lightPos[1], lightPos[2]);
glColor3f(1.0, 1.0, 1.0);
glutSolidSphere(2, 20, 20);
glPopMatrix();
glEnable(GL_LIGHTING);
}
//Routine to draw starry sky
void drawStars()
{
//TODO
}
void drawPumpkin()
{
//TODO
}
void drawKey()
{
//TODO
}
//Routine to draw walls
void drawWalls()
{
//glDisable(GL_LIGHTING);
glColor3f(51/255.0,25/255.0,0);
glPushMatrix();
//glRotatef(0,0,0,1);
glScalef(1,1,3);
glBegin(GL_QUADS);
/* Floor */
glVertex3f(-1,-1,-1);
glVertex3f(-1,-1,1);
glVertex3f(1,-1,1);
glVertex3f(1,-1,-1);
/* Ceiling */
glVertex3f(-1,1,-1);
glVertex3f(1,1,-1);
glVertex3f(1,1,1);
glVertex3f(-1,1,1);
/* Walls */
/* front outer */
/* left half */
glVertex3f(-1,-1,1);
glVertex3f(-.45,-1,1);
glVertex3f(-.45,1,1);
glVertex3f(-1,1,1);
/* right half */
glVertex3f(.45,-1,1);
glVertex3f(1,-1,1);
glVertex3f(1,1,1);
glVertex3f(.45,1,1);
/* top half */
glVertex3f(-1,.5,1);
glVertex3f(1,.5,1);
glVertex3f(1,1,1);
glVertex3f(-1,1,1);
/* end front outer */
/* front door */
//TODO
/* end front door */
/* back inner */
/* left half */
glVertex3f(-1,-1,-1);
glVertex3f(-.45,-1,-1);
glVertex3f(-.45,1,-1);
glVertex3f(-1,1,-1);
/* right half */
glVertex3f(.45,-1,-1);
glVertex3f(1,-1,-1);
glVertex3f(1,1,-1);
glVertex3f(.45,1,-1);
/* top half */
glVertex3f(-1,.5,-1);
glVertex3f(1,.5,-1);
glVertex3f(1,1,-1);
glVertex3f(-1,1,-1);
/* end inner */
glVertex3f(1,1,1);
glVertex3f(1,1,-1);
glVertex3f(1,-1,-1);
glVertex3f(1,-1,1);
glVertex3f(-1,1,1);
glVertex3f(-1,-1,1);
glVertex3f(-1,-1,-1);
glVertex3f(-1,1,-1);
glEnd();
glPopMatrix();
//glEnable(GL_LIGHTING);
}
void drawLight()
{
// Light position vectors.
float lightPos0[] = { 0.0, .75, -.5, 1.0 };
glDisable(GL_LIGHTING);
// Light0 and its sphere positioned.
glPushMatrix();
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
glTranslatef(lightPos0[0], lightPos0[1], lightPos0[2]);
glColor3f(1.0, 1.0, 1.0);
glutWireSphere(0.05, 8, 8);
glPopMatrix();
glEnable(GL_LIGHTING);
}
// Initialization routine.
void setup(void)
{
//Set globals
a = 1- abs(camera.ez/15.0);
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST); // Enable depth testing.
// Turn on OpenGL lighting.
glEnable(GL_LIGHTING);
// Light property vectors.
float lightAmb[] = { 0.0, 0.0, 0.0, 1.0 };
float lightDifAndSpec0[] = { 1.0, 1.0, 1.0, 1.0 };
float lightDifAndSpec1[] = { 1.0, 1.0, 0.0, 1.0 };
float globAmb[] = { 0.2, 0.2, 0.2, 1.0 };
// Light0 properties.
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDifAndSpec0);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightDifAndSpec0);
// Light1 properties.
glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmb);
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDifAndSpec1);
glLightfv(GL_LIGHT1, GL_SPECULAR, lightDifAndSpec1);
glEnable(GL_LIGHT0); // Enable particular light source.
glEnable(GL_LIGHT1); // Enable particular light source.
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globAmb); // Global ambient light.
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); // Enable local viewpoint
// Cull back faces.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
}
// Drawing routine.
void drawScene()
{
// Material property vectors.
float matAmb[] = {0.0, 0.0, a, 1.0};
float matDif[] = {0.0, 0.0, d, 1.0};
float matSpec[] = { s, s, s, 1.0 };
float matShine[] = { h };
float matEmission[] = {0.0, 0.0, e, 1.0};
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// Light quadratic attenuation factor.
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, t);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, t);
//gluLookAt(0.0, ey, ez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
gluLookAt(camera.ex,camera.ey, camera.ez,
camera.cx,camera.cy,camera.cz,
camera.x,camera.y,camera.z);
//gluLookAt(0,0,0,0,0,0,0,1,0);
// Draw light source spheres after disabling lighting.
drawLight();
// Material properties of sphere.
glMaterialfv(GL_FRONT, GL_AMBIENT, matAmb);
glMaterialfv(GL_FRONT, GL_DIFFUSE, matDif);
glMaterialfv(GL_FRONT, GL_SPECULAR, matSpec);
glMaterialfv(GL_FRONT, GL_SHININESS, matShine);
glMaterialfv(GL_FRONT, GL_EMISSION, matEmission);
// Sphere.
glTranslatef(0.0, 0.0, zMove); // Move the sphere.
//glutSolidCube(1.5);
drawWalls();
drawMoon();
glutSwapBuffers();
}
// OpenGL window reshape routine.
void resize (int w, int h)
{
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)w/(float)h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}
// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
int mod = glutGetModifiers();
if (mod!=0)
{
switch(mod)
{
//Shift key
case 1 : cameraRotate=true; break;
//ALT key
case 4 : ; break;
mod = 0;
}
}
switch (key)
{
case 27:
exit(0);
break;
case 'a':
if (a > 0.0) a -= 0.05;
glutPostRedisplay();
break;
case 'A':
if (a < 1.0) a += 0.05;
glutPostRedisplay();
break;
case 'd':
if (d > 0.0) d -= 0.05;
glutPostRedisplay();
break;
case 'D':
if (d < 1.0) d += 0.05;
glutPostRedisplay();
break;
case 's':
if (s > 0.0) s -= 0.05;
glutPostRedisplay();
break;
case 'S':
if (s < 1.0) s += 0.05;
glutPostRedisplay();
break;
case 'e':
if (e > 0.0) e -= 0.05;
glutPostRedisplay();
break;
case 'E':
if (e < 1.0) e += 0.05;
glutPostRedisplay();
break;
case 'h':
if (h > 0.0) h -= 1.0;
glutPostRedisplay();
break;
case 'H':
if (h < 128.0) h += 1.0;
glutPostRedisplay();
break;
case 't':
if (t > 0.0) t -= 0.005;
glutPostRedisplay();
break;
case 'T':
t += 0.005;
glutPostRedisplay();
break;
default:
break;
}
}
// Callback routine for non-ASCII key entry.
void specialKeyInput(int key, int x, int y)
{
if (key == GLUT_KEY_UP){
if(camera.ez - .1 >= 0)
{camera.ez += -0.1;
camera.ex += 0;}
}
if (key == GLUT_KEY_DOWN){
camera.ez += 0.1;
camera.ex += 0;
}
if (key == GLUT_KEY_LEFT){
camera.cx -= .1;
}
if (key == GLUT_KEY_RIGHT){
camera.cx += .1;
}
printf("This is my ez %f\n", camera.ez);
a = 1- abs(camera.ez/5.0);
glutPostRedisplay();
}
// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
}
// Main routine.
int main(int argc, char **argv)
{
printInteraction();
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (600, 600);
glutInitWindowPosition (100, 100);
glutCreateWindow ("scaryRoom.cpp");
setup();
glutDisplayFunc(drawScene);
glutReshapeFunc(resize);
glutKeyboardFunc(keyInput);
glutSpecialFunc(specialKeyInput);
glutMainLoop();
return 0;
}
OpenGL is a state based drawing API. Once you've drawn something OpenGL doesn't remember it. Everything happens at the time of drawing, and if there's no lighting setup at the moment of drawing, that's it.
I have no idea why your room comes out blue; I'd have to see the full code for that. However I can give you the advice, that you should not try to "initialize" things at a certain time, and then "live" with that. OpenGL is a state machine, meant to have every attribute that matters being set right before you actually need it. So I suggest you move the lighting and color setup as close to the actual drawing as possible.
Update
You're setting material state in your drawScene function. Those will effect on everything drawn after setting those states until you change them. You intended them to affect only the sphere, but it will affect also the other stuff. Take note that glColor won't have an effect on illuminated drawing, unless you enable and set a so called color material state.
However I strongly suggest you don't bother with the arcane fixed function pipeline at all. You've run into a few pitfalls already :) I suggest you learn modern OpenGL, which also avoids all those weird peculiarities. A very good tutorial can be found at http://arcsynthesis.org/gltut
I am trying to draw spheres at the mouse locations everytime I click the screen.
I wrote a function to get the 3D mouse coordinates, everytime the mouse is clicked. It works like a charm.
Now how can I create spheres at those locations.
void display()
{
...
...
glColor3f(1,0,0)
glutWireSphere(3,100,100);
glTranslatef(X,Y,Z);
}
void MouseFunc()//where the 3D mouse coordinates are recieved
{
double X,Y,Z// where I store the coordinates.
.....
.....
glutDisplayFunc(display);//Because thats where I create the spheres
}
In MouseFunc store the position of the click into a array/list/vector visible to the drawing function, i.e. not in locally scoped variable. Then you call glutPostRedisplay to make GLUT call the display func you registered once in the initialization code using glutDisplayFunc.
In the display function itself you iterate over the array/list/vector and draw a sphere for each element according to the element's data.
Code sample due to request in comment
clicksphere.cc
#include <GL/glut.h>
#include <GL/gl.h>
#include <list>
typedef union v2f_t {
struct {
float x;
float y;
};
float v[2];
} v2f_t;
typedef std::list<v2f_t> v2flist_t;
v2flist_t sphere_centers;
void display(void)
{
int const window_width = glutGet(GLUT_WINDOW_WIDTH);
int const window_height = glutGet(GLUT_WINDOW_HEIGHT);
float const window_aspect = (float)window_width / (float)window_height;
glClearColor(0.5, 0.5, 1.0, 1.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(window_aspect > 1.) {
glOrtho(-window_aspect, window_aspect, -1, 1, -1, 1);
}
else {
glOrtho(-1, 1, -1/window_aspect, 1/window_aspect, -1, 1);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat const light_pos[4] = {-1.00, 1.00, 1.00, 0.};
GLfloat const light_color[4] = { 0.85, 0.90, 0.70, 1.};
GLfloat const light_ambient[4] = { 0.10, 0.10, 0.30, 1.};
glLightfv(GL_LIGHT0, GL_POSITION, light_pos),
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
for( v2flist_t::iterator sc = sphere_centers.begin();
sc != sphere_centers.end();
sc++ ) {
glPushMatrix();
glTranslatef(sc->x, sc->y, 0);
glutSolidSphere(0.1, 31, 10);
glPopMatrix();
}
glutSwapBuffers();
}
void mouseclick(
int button,
int state,
int mouse_x,
int mouse_y )
{
int const window_width = glutGet(GLUT_WINDOW_WIDTH);
int const window_height = glutGet(GLUT_WINDOW_HEIGHT);
float const window_aspect = (float)window_width / (float)window_height;
v2f_t const sc = {
(window_aspect > 1.0 ? window_aspect : 1.) *
( ((float)mouse_x / (float)window_width )*2. - 1.),
(window_aspect < 1.0 ? 1./window_aspect : 1.) *
( -((float)mouse_y / (float)window_height)*2. + 1.)
};
sphere_centers.push_back(sc);
glutPostRedisplay();
}
int main(
int argc,
char *argv[] )
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutCreateWindow("Click to place spheres");
glutDisplayFunc(display);
glutMouseFunc(mouseclick);
glutMainLoop();
return 0;
};
You need to first create the transformation matrix, then draw. In other words:
glTranslatef(X,Y,Z); /* everything from here below would be translated */
glutWireSphere(3,100,100); /* draw with the current transformation matrix */
I've got an OpenGL program running, and it displays geometry, but it's all "flat," one gray tone, with no diffuse shading or specular reflection:
Pictured are three tori, each made of quad strips. We should see shading, but we don't. What am I doing wrong?
Here is the code where I set the vertices and normals (draw_torus() is called to build a display list):
/* WrapTorus, adapted from
http://www.math.ucsd.edu/~sbuss/MathCG/OpenGLsoft/WrapTorus/WrapTorus.html
by Sam Buss */
/*
* Issue vertex command for segment number j of wrap number i.
* Normal added by Lars Huttar.
* slices1 = numWraps; slices2 = numPerWrap.
*/
void putVert(float i, float j, float slices1, float slices2, float majR, float minR) {
float wrapFrac = j / slices2;
/* phi is rotation about the circle of revolution */
float phi = PI2 * wrapFrac;
/* theta is rotation about the origin, in the xz plane. */
float theta = PI2 * (i + wrapFrac) / slices1;
float y = minR * (float)sin(phi);
float r = majR + minR * (float)cos(phi);
float x = (float)sin(theta) * r;
float z = (float)cos(theta) * r;
/* normal vector points to (x,y,z) from: */
float xb = (float)sin(theta) * majR;
float zb = (float)cos(theta) * majR;
glNormal3f(x - xb, y, z - zb);
glVertex3f(x, y, z);
}
static void draw_torus(int numPerWrap, int numWraps, float majR, float minR) {
int i, j;
glBegin( GL_QUAD_STRIP );
for (i=0; i < numWraps; i++ ) {
for (j=0; j < numPerWrap; j++) {
putVert((float)i, (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
putVert((float)(i + 1), (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
}
}
putVert(0.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
putVert(1.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
glEnd();
}
Is there something wrong with the order of vertices?
Here is the part of the init function where the display list is built:
GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat color[4] = { 0.5, 0.6, 0.7, 1.0 };
...
glShadeModel(GL_SMOOTH);
torusDL = glGenLists (1);
glNewList(torusDL, GL_COMPILE);
setMaterial(color, white, 100);
draw_torus(8, 45, 1.0, 0.05);
glEndList();
where setMaterial() just does:
static void setMaterial(const GLfloat color[3], const GLfloat hlite[3], int shininess) {
glColor3fv(color);
glMaterialfv(GL_FRONT, GL_SPECULAR, hlite);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
glMateriali(GL_FRONT, GL_SHININESS, shininess); /* [0,128] */
}
Here is lighting that's also done during initialization:
GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
GLfloat color[4] = {0.20, 0.20, 0.20, 1.00};
GLfloat spec[4] = {0.30, 0.30, 0.30, 1.00};
GLfloat shiny = 8.0;
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
Here is where the display list gets called, in the draw function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
glScalef(3.5, 3.5, 3.5);
for (i = 0; i < ac->nrings; i++) {
glScalef(0.8, 0.8, 0.8);
glRotatef(...);
glCallList(torusDL);
}
glFlush();
glPopMatrix();
glXSwapBuffers(dpy, window);
The full .c source file for this "glx hack" is here. In case it makes a difference, this code is in the context of xscreensaver.
As you see, glEnable(GL_NORMALIZE) normalizes the normal vectors after the transformations used for lighting calculations (in fixed-function pipelines). These calculations rely on unit length normals for correct results.
It's worth pointing out that the transforms applied to normal vectors are not the same as the transforms applied to vertex geometry. The OpenGL 2.1 specification describes the transform, as do many other resources. As a vector, a normal has the homogeneous representation: [nx, ny, nz, 0] - a point at 'infinity', and a mathematically elegant way to unify matrix and 4-vector operations in the GL pipeline.
Of course, you could perform this normalization yourself, and it may be more efficient to do so, as your torus geometry is only generated once for a pre-compiled display list:
nx = x - b, ny = y, nz = z - zb;
nl = 1.0f / sqrtf(nx * nx + ny * ny + nz * nz);
glNormal3f(nx * nl, ny * nl, nz * nl);
Be sure to check (nl) for division by zero (or some epsilon), if that's a possibility.
I have looked for this error and tried a few of the solutions, but have not found anything, at this point I would just like to compile it.
The error I am getting is:
/usr/lib/gcc/i486-linux-gnu/4.4.1/../../../../lib/crt1.o: In function `_start':
/build/buildd/eglibc-2.10.1/csu/../sysdeps/i386/elf/start.S:115: undefined reference to `main'
using:
g++ -lglut Solar.cpp
the code is here:
using namespace std;
#include <stdio.h>
#include <GL/glut.h>
#include "math.h"
class Solar {
int main(){
initializeGL();
//Stars Alpha = new Stars(5.0);
//Stars *Alpha = new Stars(5.0);
//Planets *Awe = new Planets(.6,2,30,"Awe",0.0,0.0,0.0);
paintGL();
return 0;
}
vid initializeGL(){
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
// lighting stuff
GLfloat ambient[] = {0.0, 0.0, 0.0, 1.0};
GLfloat diffuse[] = {0.9, 0.9, 0.9, 1.0};
GLfloat specular[] = {0.4, 0.4, 0.4, 1.0};
GLfloat position0[] = {1.0, 1.0, 1.0, 0.0};
glLightfv( GL_LIGHT0, GL_POSITION, position0 );
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
GLfloat position1[] = {-1.0, -1.0, -1.0, 0.0};
glLightfv( GL_LIGHT1, GL_POSITION, position1 );
glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT1, GL_SPECULAR, specular );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glEnable( GL_LIGHT1 );
glEnable( GL_COLOR_MATERIAL );
/* Draws the Grid*/
drawRGrid();
}
void resizeGL( int width, int height ){
height = height?height:1;
glViewport( 0, 0, (GLint)width, (GLint)height );
// update projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,.10f,200.0f);
// modeview matrix is simply identity
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void paintGL(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//set camera position using gluLookAt
glLoadIdentity();
gluLookAt(0.0f,0.0f,0.0f,0.0f,0.0f,-200.0f,0.0f,1.0f,0.0f);
}
void doCircle(double x, double y, double radius){
glEnable(GL_BLEND);
double y1=y+radius;
double x1=x;
glBegin(GL_LINE_STRIP);
for(double angle=0.0f;angle<=(2.0f*3.14159);angle+=0.01f){
double x2=x+(radius*(float)sin((double)angle));
double y2=y+(radius*(float)cos((double)angle));
glColor3f(1.0,1.0,1.0); //White
glVertex2d(x1,y1);
y1=y2;
x1=x2;
}
glEnd();
glDisable(GL_BLEND);
}
void drawRGrid(){
float xCirc = 0;
float yCirc = 0;
int numCircles = 5;
int threesixty = 360;
int numLines = 20;
//draws my circles
for (int i=0; i < numCircles;i++ ){
doCircle(1.0,1.0,i);
}
//draws my lines
for (int j=0; j < threesixty / numLines;j+= numLines){
// multiply by numCircles to get to extend to
// that length
drawLines(sin(j)*numCircles,sin(j)*numCircles);
}
}
void drawLines(float xCirc, float yCirc){
glBegin(GL_LINES);
glVertex2f(0,0);
glVertex2f(xCirc,yCirc);
glEnd();
}
};
Any help will be great appreciated!
You have declared main() as a member function.
The main() function called when the application starts up needs to be a non-member function in the global namespace.
A good introductory C++ book would explain this.
You declared main in class Solar. main is supposed to be a free function, i.e. not contained within a class.
main cannot be found because the function you wrote is called Solar::main (in truth, it has a much funnier name). You need to move it below class Solar. Then you probably want to change class Solar into struct Solar until you introduce member variables. At last, you may want to rewrite main to be
extern "C" int main (int /* argc */, char *const * /* argv */) {
Solar solar;
solar.initializeGL();
//Stars Alpha = new Stars(5.0);
//Stars *Alpha = new Stars(5.0);
//Planets *Awe = new Planets(.6,2,30,"Awe",0.0,0.0,0.0);
solar.paintGL();
return 0;
}