5

I've written an OpenGL screensaver for Mac OS X 10.5 and higher which shows a spinning heart constructed using marching cubes. It works fine on my black 13.3" development Macbook running Snow Leopard (10.6), nice and glossy.

But when I try it on a newer Macbook Pro but running leopard (10.5), the heart isn't glossy. It appears as though it's only lit with ambient/diffuse light, but no specular light. It's as if I had set the specular component of the light to 0. The newer Macbook has an Nvidia graphics card. The one older one running 10.6 has an Intel XMA3100.

Here is my OpenGL initialization code. The heart is created using marching cubes and I am computing the normal vectors as well.

- (void)setUpOpenGL
{ 
    [[glView openGLContext] makeCurrentContext];

    // Synchronize buffer swaps with vertical refresh rate
    GLint swapInterval = 1;
    [[glView openGLContext] setValues:&swapInterval
                         forParameter:NSOpenGLCPSwapInterval];

    glShadeModel(GL_SMOOTH);
    glClearDepth(1.0);
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);

    // Light
    GLfloat ambient_light[] = { 0.2f, 0.2f, 0.2f, 1.0f };
    GLfloat diffuse_light[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    GLfloat specular_light[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    GLfloat position_light[] = { 0.0f, 0.0f, -1.0f, 0.0f };

    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular_light);
    glLightfv(GL_LIGHT0, GL_POSITION, position_light);

    // Material
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

    GLfloat mat_ambient[] = {0.7, 0.0, 0.0, 1.0};
    GLfloat mat_diffuse[] = { 0.7, 0.0, 0.0, 1.0 };
    GLfloat mat_specular[] = { 0.0, 0.0, 0.0, 0.0 };
    GLfloat mat_shininess[] = { 100.0 };

    glColor3f(1.0, 0.0, 0.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);

    // Copy isosurface vertices to graphics array
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, [marchingCubes vertices]);
    glNormalPointer(GL_FLOAT, 0, [marchingCubes normals]);
}

The actual drawing code looks like this:

- (void)drawRect:(NSRect)rect
{
    [super drawRect:rect];

    [[glView openGLContext] makeCurrentContext];

    glDrawBuffer(GL_BACK);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Adjust viewpoint to give heart beat effect
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, radius, 2*radius/3,
              0, 0, 0,
              0, 0, 1);

    // Adjust rotation to make heart spin
    glRotatef(rotation, 0.0f, 0.0f, 1.0f);

    // Draw heart
    glDrawArrays(GL_TRIANGLES, 0, [marchingCubes vertexCount]/3);

    glFlush();

    [[glView openGLContext] flushBuffer];

    // Rotate and scale a bit
    rotation += 1.0f;
    radius = 4.0 + 0.25*sin(rotation/4);
}

Any ideas why the specular lighting difference? Is specular lighting simply not supported on some graphics cards? Any pointers are much appreciated.

thinkski
  • 1,306
  • 1
  • 15
  • 25

1 Answers1

1

The default for GL_SPECULAR (and other colors) is { 0.0,0.0,0.0,1.0 }

GLfloat mat_specular[] = { 0.0, 0.0, 0.0, 1.0 };

You may also do this at the end of your setup func to 1. optimize drawing and 2. to double check if lighting is actually applied to the front face as you set it up.

glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
Sam
  • 7,778
  • 1
  • 23
  • 49
  • Thanks for the suggestion. I added culling on the back face and indeed found that the front face was on the inside. So I added a call to glFrontFace(GL_CW) right after I "synchronize the buffer swaps with the vertical refresh rate" in setUpOpenGL, but still no shine. Both the light and material specular components are set to { 1.0, 1.0, 1.0, 1.0 } as in the code above. If I set either to { 0.0, 0.0, 0.0, 1.0 } the shine goes away on 10.6 as well. – thinkski Jan 30 '12 at 04:27
  • This has to do with multiplications when the material and light colors are mixed. Black * other color gives black, when alpha is also 0.0, then the result is fully transparent, whatever the 3 color componentns may be. I Suggest you explicitly define the light attenuation and other values accessible using glLight(). – Sam Jan 30 '12 at 09:41
  • I'll give that a try. I don't have access to the 10.5 test machine any more so testing will be slower. One other thing I thought of was that 10.5 is a 32-bit operating system whereas 10.6 is 64-bit, so I wrote the normal vectors and vertices to a file on each and compared. They were identical, so that's not the problem. – thinkski Feb 01 '12 at 05:17