I'm using opengl for educational purposes, but I'm having trouble creating multiple spotlights to represent street lamps. I use an iterator to create several however in the end only the last spotlight gets the light, I believe the problem is in the addlight method however I do not know what is happening.
In image below you can see happen.
https://imgur.com/Y77eHln
#include "CreateLamps.h"
std::vector<SpotLight> lamp;
CreateLamps::CreateLamps(int number) {
for (int i = 0; i < number; i++) {
SpotLight *spot = new SpotLight(-8.0f, 5.f, (i*10) + 30.0f, 1.f);
lamp.push_back(*spot);
}
}
void CreateLamps::Add() {
std::vector<SpotLight>::iterator it = lamp.begin();
while (it != lamp.end())
{
glPushMatrix();
glTranslatef(1, 0, 30.0);
glTranslatef(it->position[0], it->position[3] * 3, it->position[2]);
glRotatef(100.f, -5.0, -10, 0);
it->addlight();
it->draw();
it++;
glPopMatrix();
}
}
#include "SpotLight.h"
using namespace std;
GLfloat target[3] = { 0.0f, 0.0f, 0.0f };
GLfloat color[3] = { 1.0f, 1.0f, 1.0f };
GLfloat cutoff(5.0f);
GLfloat exponent(15.0f);
SpotLight::SpotLight(GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
position[0] = x;
position[1] = y;
position[2] = z;
position[3] = w;
direction[0] = target[0] - position[0];
direction[1] = target[1] - position[1];
direction[2] = (target[2] - position[2]);
}
void SpotLight::addlight() {
glEnable(GL_LIGHT1);
glLightfv(GL_LIGHT1, GL_DIFFUSE, color);
glLightfv(GL_LIGHT1, GL_SPECULAR, color);
glLightfv(GL_LIGHT1, GL_POSITION, position);
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, direction);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, cutoff);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, exponent);
}
void SpotLight::draw() {
if (!glIsEnabled(GL_LIGHT1))
return;
glPushMatrix();
GLfloat up[3] = { 0, 1, 0 };
lookAt(position, target, up);
GLfloat ambient[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat diffuse[4] = { 0.01f, 0.01f, 0.01f, 1.0f };
GLfloat specular[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat shininess = 32.0f;
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
glutSolidCone(0.3, 0.6, 10, 10);
glPushMatrix();
glTranslatef(0, 0, 0.1f);
glutSolidCylinder(0.2, 0.39, 10, 10);
glPopMatrix();
glDisable(GL_LIGHTING);
glColor3fv(color);
glutSolidSphere(0.2, 100, 100);
glEnable(GL_LIGHTING);
glPopMatrix();
}
void SpotLight::normalize(const GLfloat* vec, GLfloat* output)
{
GLfloat length = sqrtf(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
output[0] /= length;
output[1] /= length;
output[2] /= length;
}
void SpotLight::cross(const GLfloat* vec1, const GLfloat* vec2, GLfloat * output) {
output[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
output[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
output[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
}
void SpotLight::lookAt(GLfloat* eye, GLfloat* center, GLfloat* up)
{
GLfloat f[3] = { center[0] - eye[0],
center[1] - eye[1],
center[2] - eye[2] };
normalize(f, f);
GLfloat u[3];
normalize(up, u);
GLfloat s[3];
cross(f, u, s);
normalize(s, s);
cross(s, f, u);
normalize(u, u);
}
void drawScene() {
glPushMatrix();
glTranslatef(pointlight.position[0], pointlight.position[1], pointlight.position[2]);
pointlight.addLight();
glPopMatrix();
// Draw road
glPushMatrix();
glScalef(10, 10, 8.5);
glTranslatef(-0.018f, 0, 0.75);
glRotatef(180.f, 0, 1, 0);
models[0]->renderTheModel();
glPopMatrix();
//Draw Car Model
glPushMatrix();
glMultMatrixf(carros[0]->local);
carros[0]->draw();
glPopMatrix();
//Draw spotlights
glPushMatrix();
lamps->Add();
glPopMatrix();
}
You are only ever setting LIGHT1, which means only 1 light is going to have been enabled (the last one). If you specify GL_LIGHT0 + index, you'll be able to enable more.
void SpotLight::addlight(int index) {
glEnable(GL_LIGHT0 + index);
glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, color);
glLightfv(GL_LIGHT0 + index, GL_SPECULAR, color);
glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, cutoff);
glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, exponent);
}
And then you simply need to pass the index in when enabling
void CreateLamps::Add() {
std::vector<SpotLight>::iterator it = lamp.begin();
while (it != lamp.end())
{
glPushMatrix();
glTranslatef(1, 0, 30.0);
glTranslatef(it->position[0], it->position[3] * 3, it->position[2]);
glRotatef(100.f, -5.0, -10, 0);
it->addlight(it - lamp.begin());
it->draw();
it++;
glPopMatrix();
}
}
Just be aware that you might run out of lights after 8, so you might want to check the value of GL_MAX_LIGHTS...
int numLights = 0;
glGetIntegerv(GL_MAX_LIGHTS, &numLights);
std::cout << "GL_MAX_LIGHTS " << numLights << std::endl;
Presumably you are drawing the road after drawing all of the lights.
Your code does this:
For each light:
Set light 1 according to that light's parameters
Draw the shape of the light itself
Draw the road.
When the road gets drawn, light 1 is set up with the parameters of the last light that was drawn. So it uses these light parameters to draw the road. You overwrote all the parameters of the other lights already.
If you want to draw the road with all the lights, then all the lights have to be set up when you draw the road. Not just the last one.
Note that you can only set up 8 lights at once in OpenGL. If have more than 8 lights pointing at the road, you will have to split up the road into different sections so that each section has up to 8 lights.
Standard disclaimer in case you aren't aware already: You are using old-style (fixed-function) OpenGL which has been superseded by shader-based OpenGL (version 3 and 4). This API is okay for simple programs but it won't let you use the full flexibility and performance of your graphics card.
Related
I have a problem in my project, when I move the camera in a location near the image for me is perfect, but as far I move or rotate the camera, it gives me error like this.
I do not know where my error is. How can I correct this?
http://nr7.upanh.com/b5.s32.d2/b7f577d38c0b23cbb35ca367e253b716_50312137.orr.png
http://nr9.upanh.com/b2.s11.d1/0be16f4300e3a84aba3a56e5e2bf008d_50312139.perfec.png
code:
ButtonEndRollVV KeyPessUp;
VeKhungCanh Draw;
GLint ListDraw[100];
void glintIn()
{
glutWarpPointer(400,300);
KeyPessUp.lastx=400;
KeyPessUp.lasty=300;
KeyPessUp.xrot=ROLL_X;
KeyPessUp.yrot=ROLL_Y;
KeyPessUp.xpos=-DEFAUTCAMERAX;
KeyPessUp.ypos=-DEFAUTCAMERAY;
KeyPessUp.zpos=-DEFAUTCAMERAZ;
/////////////////////////////////set defual/////////////////////////////////////
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);// Enables Depth Testing
glClearDepth(1.0f); // Depth Buffer Setup
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glClearStencil(0);//gia phong bo dem dat no bang 0
glEnable(GL_STENCIL_TEST);//kich hoat bo dem stencil
////////////////////////////////create list grid///////////////////////////////
ListDraw[0]=glGenLists(1);
glNewList(ListDraw[0],GL_COMPILE);
{
Draw.CreateKhongGian();
}
glEndList();
/////////////////////////////////create cong hang hai//////////////////////////
ListDraw[1]=glGenLists(1);
glNewList(ListDraw[1],GL_COMPILE);
{
Draw.CreateCongHangHai();
}
glEndList();
/////////////////////////////create hang giao/////////////////////////////////
ListDraw[2]=glGenLists(1);
glNewList(ListDraw[2],GL_COMPILE);
{
Draw.CreateHangGiao();
}
glEndList();
//////////////////////////////////anh sang va thong so vat lieu////////////////////////////
float Al[4] = {0.6f, 0.6f, 0.6f, 1.0f };
glLightfv( GL_LIGHT0, GL_AMBIENT, Al );
float Dl[4] = {1.0f, 1.0f, 1.0f, 1.0f };
glLightfv( GL_LIGHT0, GL_DIFFUSE, Dl );
float Sl[4] = {1.0f, 1.0f, 1.0f, 1.0f };
glLightfv( GL_LIGHT0, GL_SPECULAR, Sl );
float Am[4] = {0.6f,0.6f, 0.6f, 1.0f };
glMaterialfv(GL_FRONT, GL_AMBIENT, Am );
float Dm[4] = {1.0f, 1.0f, 1.0f, 1.0f };
glMaterialfv(GL_FRONT, GL_DIFFUSE, Dm );
float Sm[4] = {1.0f, 1.0f, 1.0f, 1.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, Sm );
glMaterialf(GL_FRONT, GL_SHININESS, 45);
glColorMaterial(GL_FRONT, GL_DIFFUSE);//bo cai nay neu bumapping
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
void display()
{
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity ();
glPushMatrix();
glRotatef(KeyPessUp.xrot,1.0,0.0,0.0);
glRotatef(KeyPessUp.yrot,0.0,1.0,0.0);
glTranslatef(KeyPessUp.xpos,KeyPessUp.ypos,KeyPessUp.zpos);
glCallList(ListDraw[0]);//draw grid
glColor3f(1,1,0);
glCallList(ListDraw[1]);//draw Cong Hang Hai pt parabol:
glCallList(ListDraw[2]);//draw Hang Giao
glPopMatrix();
glFinish();
glutSwapBuffers();
}
void resize(int w,int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
//SIZE_KHUNG_CANH*2
float DefaultFus=0.001f;
glFrustum (-DefaultFus, DefaultFus, -DefaultFus, DefaultFus, DefaultFus,SIZE_KHUNG_CANH*3 );
glMatrixMode (GL_MODELVIEW);
glutPostRedisplay();
KeyPessUp.sizeH=h;
KeyPessUp.sizeW=h;
}
void idle()
{
if(KeyPessUp.keyStates[GLUT_KEY_UP]==true)
{
float xrotrad, yrotrad;
yrotrad = (KeyPessUp.yrot / 180 * pi);
xrotrad = (KeyPessUp.xrot / 180 * pi);
KeyPessUp.xpos -= float(sin(yrotrad)/SPEED) ;
KeyPessUp.zpos += float(cos(yrotrad)/SPEED) ;
if(DISABLEUPDOWNCAMERA==0)
KeyPessUp.ypos += float(sin(xrotrad)/SPEED) ;//bỏ đi nếu nhập vai
}
if(KeyPessUp.keyStates[GLUT_KEY_LEFT]==true)
{
float xrotrad, yrotrad;
yrotrad = ((KeyPessUp.yrot+90) / 180 * pi);
xrotrad = ((KeyPessUp.xrot) / 180 * pi);
KeyPessUp.xpos += float(sin(yrotrad)/SPEED) ;
KeyPessUp.zpos -= float(cos(yrotrad)/SPEED) ;
if(DISABLEUPDOWNCAMERA==0)
KeyPessUp.ypos -= float(sin(xrotrad)/SPEED) ;//bỏ đi nếu nhập vai
}
if(KeyPessUp.keyStates[GLUT_KEY_DOWN]==true)
{
float xrotrad, yrotrad;
yrotrad = (KeyPessUp.yrot / 180 * pi);
xrotrad = (KeyPessUp.xrot / 180 * pi);
KeyPessUp.xpos += float(sin(yrotrad)/SPEED);
KeyPessUp.zpos -= float(cos(yrotrad)/SPEED) ;
if(DISABLEUPDOWNCAMERA==0)
KeyPessUp.ypos -= float(sin(xrotrad)/SPEED); //bỏ đi nếu nhập vai
}
if(KeyPessUp.keyStates[GLUT_KEY_RIGHT]==true)
{
float xrotrad, yrotrad;
yrotrad = ((KeyPessUp.yrot+90) / 180 * pi);
xrotrad = ((KeyPessUp.xrot) / 180 * pi);
KeyPessUp.xpos -= float(sin(yrotrad)/SPEED);
KeyPessUp.zpos += float(cos(yrotrad)/SPEED) ;
if(DISABLEUPDOWNCAMERA==0)
KeyPessUp.ypos += float(sin(xrotrad)/SPEED);//bỏ đi nếu nhập vai
}
glutPostRedisplay();
}
void KeyPess(int Key,int x,int y)
{
if(KeyPessUp.acted==0)
{
glutIdleFunc(idle);
KeyPessUp.acted=1;
}
KeyPessUp.keyStates[Key]=true;
}
void KeyUp(int Key,int x,int y)
{
int check=0;
KeyPessUp.keyStates[Key]=false;
for(int i=0;i<255;i++)
{
if(KeyPessUp.keyStates[i]==true)
{
check=1;
}
}
if(KeyPessUp.acted==1&&check==0)
{
glutIdleFunc(NULL);
KeyPessUp.acted=0;
}
}
void KeyExit(unsigned char Key,int x,int y)
{
if(Key==27)
{
exit(0);
}
}
void MouseMove(int x,int y)
{
int xpoint=x-KeyPessUp.lastx;
int ypoint=y-KeyPessUp.lasty;
KeyPessUp.lastx=x;
KeyPessUp.lasty=y;
KeyPessUp.yrot += xpoint*.3;
KeyPessUp.xrot += ypoint*.3;
if (KeyPessUp.xrot >=89) KeyPessUp.xrot = 89;
if (KeyPessUp.xrot <= -89) KeyPessUp.xrot =-89;
if (KeyPessUp.yrot >360) KeyPessUp.yrot -= 360;
if (KeyPessUp.yrot < -360)KeyPessUp.yrot += 360;
glutPostRedisplay();
if(x>450 || x<350 ||y>350 || y<250)
{
glutWarpPointer(400,300);
KeyPessUp.lastx=400;
KeyPessUp.lasty=300;
}
}
int main(int argc,char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowPosition(100,100);
glutInitWindowSize(800,600);
glutCreateWindow("De Tai Nghien Cuu Khoa Hoc");
glintIn();
glutDisplayFunc(display);
glutReshapeFunc(resize);
glutSpecialFunc(KeyPess);
glutSpecialUpFunc(KeyUp);
glutKeyboardFunc(KeyExit);
glutPassiveMotionFunc(MouseMove);
glutMotionFunc(MouseMove);
glutSetCursor(GLUT_CURSOR_NONE);
glewInit();
if(ENDABLE_FULL_SCREEN==TRUE)
glutFullScreen();
glutMainLoop();
return 0;
}
float DefaultFus=0.001f;
glFrustum (-DefaultFus, DefaultFus, -DefaultFus, DefaultFus, DefaultFus,SIZE_KHUNG_CANH*3 );
That's your problem right there: The near clipping place distance is very small compared to the scale to the scene. However the bigger the "scene scale"/"near clip" ratio is, the lower is the effective Z-buffer resolution.
Solution: Choose the near clip plane distance as large, i.e. far away as possible. Ideally you choose the value dynamically depending on the contents of the visible scene and the position of the view point.
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'm trying to create my own torus with smooth shading. However, the normal seems to be wrong. Here is my code.
GLfloat NoMat[] = { 0.0f, 0.0f, 0.0f, 1.0f };
GLfloat MatAmbient[] = { 0.7f, 0.7f, 0.7f, 1.0f };
GLfloat MatAmbientColor[] = { 0.21f, 0.13f, 0.05f, 1.0f };
GLfloat MatDiffuse[] = { 0.71f, 0.43f, 0.18f, 1.0f };
GLfloat Shine = 100.0f;
GLfloat NoShine = 0.0f;
glMaterialfv(GL_FRONT, GL_AMBIENT, MatAmbientColor);
glMaterialfv(GL_FRONT, GL_DIFFUSE, MatDiffuse);
glEnable(GL_NORMALIZE);
glMaterialfv(GL_FRONT, GL_SPECULAR, MatAmbient);
glMaterialf(GL_FRONT, GL_SHININESS, Shine);
int i, j, k;
double s, t, x, y, z;
for (i = 0; i < nsides; i++) {
glBegin(GL_QUAD_STRIP);
for (j = 0; j <= rings + 1; j++) {
for (k = 1; k >= 0; k--) { //for both negative and positive
s = (i + k) % nsides + 0.5;
t = j % rings;
x = (totalRadius + centerRadius * cos(s*2*M_PI/nsides)) * cos(t*2*M_PI/rings);
z = (totalRadius + centerRadius * cos(s*2*M_PI/nsides)) * sin(t*2*M_PI/rings);
y = centerRadius * sin(s*2*M_PI/nsides);
glVertex3f(x, y, z);
glNormal3f(x, y, z);
}
}
glEnd();
}
However, the lighting does not work properly, as it behaves like flat shading instead of smooth shading. I've did some googling, but apparantly it seems that I need to use differention. However, I'm not too sure how to do this. Anyone has any idea?
You're using the vertex positions for normals? This will work only (and only) for a unit radius sphere!
You need to calculate the normal. That is
The nice thing about a torus is, that you can evaluate this easily on paper, giving you an exact formula, instead of working with a numerical approximation.
I'm trying to make 'spotlights' over a pool table in openGL. This should be fairly simple, but something is going wrong, and I can't work out what.
I have a class 'PoolLight' that I'm using as a sort of holding class for the lights. Here is is:
#include "PoolLight.h"
#include "Glut/glut.h"
#include "GL/gl.h"
#include "GL/glu.h"
PoolLight::PoolLight() {
}
PoolLight::PoolLight(GLenum lightNumber, GLenum lightType, float red, float green, float blue, bool distant, float posX, float posY, float posZ)
{
this->lightNumber = lightNumber;
this->lightType = lightType;
color[0] = red; color[1] = green; color[2] = blue; color[3] = 1;
position[0] = posX; position[1] = posY; position[2] = posZ; position[3] = (int) (!distant);
glLightfv(lightNumber, lightType, color);
glLightfv(lightNumber, GL_POSITION, position);
enabled(true);
}
PoolLight::~PoolLight(void)
{
}
void PoolLight::setSpotlight(float angle, float attenuation, float dirX, float dirY, float dirZ) {
glLightf(lightNumber, GL_SPOT_EXPONENT, angle);
glLightf(lightNumber, GL_CONSTANT_ATTENUATION, attenuation);
glLightf(lightNumber, GL_LINEAR_ATTENUATION, 0.0f);
glLightf(lightNumber, GL_QUADRATIC_ATTENUATION, 0.0f);
spotDirection[0] = dirX; spotDirection[1] = dirY; spotDirection[2] = dirZ;
glLightfv(lightNumber, GL_SPOT_DIRECTION, spotDirection);
glLightf(lightNumber, GL_SPOT_CUTOFF, 60);
}
void PoolLight::enabled(bool enabled) {
if (enabled) glEnable(lightNumber);
else glDisable(lightNumber);
}
void PoolLight::reposition() {
glLightfv(lightNumber, GL_POSITION, position);
}
And in Display::Init, I have this code:
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glPointSize(6);
//Lighting
middleSpotlight = PoolLight(GL_LIGHT0, GL_DIFFUSE, .3, .3, 0.15, false, 0, 0, 50);
middleSpotlight.setSpotlight(60, 1, 0, 0, -1);
upperSpotlight = PoolLight(GL_LIGHT1, GL_DIFFUSE, .3, .3, 0.15, false, 0, 45, 50);
upperSpotlight.setSpotlight(60, 1, 0, 0, -1);
lowerSpotlight = PoolLight(GL_LIGHT2, GL_DIFFUSE, .3, .3, 0.15, false, 0, -45, 50);
lowerSpotlight.setSpotlight(60, 1, 0, 0, -1);
However, even when disabling all but the middle spotlight my scene is uniformly lit with a sort of 'blanket' lighting.
I feel like I'm probably missing something obvious, but I just can't see what.
This is due to how OpenGL default fixed function pipeline implements lighting: Lighting is evaluated only at the vertices, the resulting colour interpolated over the surface. If your whole table consists of just one large quad, exactly this happens.
Solution 1: Subdivide the mesh to a high degree.
Solution 2: Replace fixed function lighting with a per-fragment-illumination shader.
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;
}