Eric F
Eric F

Reputation: 948

Open GL Positioning Lighting at camera always

Background

I am attempting to make a CAD viewer to which I can bring in an STL file and simply rotate, pan, etc. This shouldn't be anything that advanced like a game.

I was having difficulty with lighting which can be seen in a previous post: Previous Post

Problem

Basically I have light on now, and I have my pop and push matrix call outs in the right place. All I am trying to do now is to optimize my lighting to be like a CAD environment. Correct me if I am wrong but I believe the best lighting for viewing a part is always having the light at the camera pointing in the direction of the object. If this is not the optimal way to do lighting, by all means feel free to suggest a better way.

I think this mostly comes down to math. I don't know if there are any built in functions to simply get where the camera is, or if you have to keep track of it.

Here is what I have for my display function:

Private Sub display()

    Gl.glEnable(Gl.GL_DEPTH_TEST)
    Gl.glClear(Gl.GL_COLOR_BUFFER_BIT)
     Gl.glClear(Gl.GL_DEPTH_BUFFER_BIT)


    Gl.glPushMatrix()

    Gl.glRotatef(rotX, 1.0F, 0.0F, 0.0F)
    ' Rotate on x
    Gl.glRotatef(rotY, 0.0F, 1.0F, 0.0F)
    ' Rotate on y
    Gl.glRotatef(rotZ, 0.0F, 0.0F, 1.0F)
    ' Rotate on z
    Gl.glTranslatef(X, Y, Z)



    'Draw x,y,z axis 
    Gl.glBegin(Gl.GL_LINES)
    Gl.glColor4f(0.0F, 1.0F, 0.0F, 1.0F)

    ' Green for x axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(5000.0F, 0.0F, 0.0F)
    Gl.glColor3f(1.0F, 0.0F, 0.0F)
    ' Red for y axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 5000.0F, 0.0F)
    Gl.glColor3f(0.0F, 0.0F, 1.0F)
    ' Blue for z axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 0.0F, 15.0F)
    Gl.glEnd()

    ' Dotted lines for the negative sides of x,y,z
    Gl.glEnable(Gl.GL_LINE_STIPPLE)
    ' Enable line stipple to
    ' use a dotted pattern for
    ' the lines
    Gl.glLineStipple(1, &H101)
    ' Dotted stipple pattern for
    ' the lines
    Gl.glBegin(Gl.GL_LINES)
    Gl.glColor3f(0.0F, 1.0F, 0.0F)
    ' Green for x axis
    Gl.glVertex3f(-5000.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glColor3f(1.0F, 0.0F, 0.0F)
    ' Red for y axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, -5000.0F, 0.0F)
    Gl.glColor3f(0.0F, 0.0F, 1.0F)
    ' Blue for z axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 0.0F, -5000.0F)
    Gl.glEnd()

    Gl.glDisable(Gl.GL_LINE_STIPPLE)

    ' Disable the line stipple

    Gl.glColor3f(1.0F, 1.0F, 1.0F)
    Glut.glutSolidTeapot(5)


    Gl.glEnable(Gl.GL_LIGHTING)

    Label1.Text = "X=" & lighting_x & ", Y=" & lighting_y & " Z=" & lighting_z
    Light1Position = {lighting_x, lighting_y, lighting_z, 0.0F}

    ' Enable Default Light
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_AMBIENT, Light1Ambient)
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, Light1Diffuse)
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, Light1Position)
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_SPECULAR, Light1Specular)
    Gl.glEnable(Gl.GL_LIGHT1)

    Gl.glPopMatrix()

    draw_extras()

    Gl.glEnable(Gl.GL_COLOR_MATERIAL)
    Gl.glColorMaterial(Gl.GL_FRONT, Gl.GL_AMBIENT_AND_DIFFUSE)
    Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_SPECULAR, MaterialSpecular)
    Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_SHININESS, SurfaceShininess)

    Gl.glEnable(Gl.GL_COLOR_MATERIAL)
    Glut.glutSwapBuffers()
End Sub

Basically I have lighting_x, lighting_y, and lighting_z as variables to move my light around. I have a variables X, Y, and Z that establish the panning (Gl.glTranslatef(X, Y, Z)). The variables rotx, roty, and rotz set the rotation in the main function using Gl.glRotatef(rotX, 1.0F, 0.0F, 0.0F).

These variables are being applied to the whole scene which makes sense in a CAD environment so that my axis moves as well.

On top of this, I am using the gluLookAt function to create a "zoom to fit" function. From what I understand, the functions in my display function move and rotate my environment but the gluLookAt is moving my camera. Keeping the relation between these must be what is needed for my lighting calculation:

Private Sub zoom_fit()
    rotX = 0
    rotY = 0
    rotZ = 0
    rotLx = 0
    rotLy = 0
    rotLz = 0


    Dim i As Integer = 1
    Dim maxz As Decimal = -10000

    Do Until i >= ListView1.Items.Count
        If Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text) > maxz Then
            maxz = Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text)
        End If
        If Convert.ToDecimal(ListView1.Items.Item(i + 1).SubItems(2).Text) > maxz Then
            maxz = Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text)
        End If
        If Convert.ToDecimal(ListView1.Items.Item(i + 2).SubItems(2).Text) > maxz Then
            maxz = Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text)
        End If
        i = i + 4
    Loop




    rotLz = Convert.ToSingle((maxz - avgz) * 10)

    Gl.glMatrixMode(Gl.GL_MODELVIEW)
    Gl.glLoadIdentity()
    Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, _
        0.0, 1.0, 0.0)


    Glut.glutPostRedisplay()
End Sub

I don't know where the environment puts the camera relative to the origin when it initially runs but I would think that this too would need to be taken into account.

What I can see so far:

The light side of the teapot:

enter image description here

Dark side of the moon (teapot):

enter image description here

All code is written in VB.NET but C# answers would work too.

Upvotes: 0

Views: 1550

Answers (1)

Reto Koradi
Reto Koradi

Reputation: 54572

The code looks a bit rough, and I will not comment on every detail that you may have to fix. But here are some important aspects that will hopefully get you up and running:

  • All state needs to be set before the draw calls. In other words, each draw call uses the exact state that was in place at the time of the call. For example, you set some material properties at the end of the display() function, after all the draw calls have already been made. Those state changes will not affect anything until the next draw call.

  • You need to be careful about the current transformation when you specify light positions. From the spec:

    The current model-view matrix is applied to the position parameter indicated with Light for a particular light source when that position is specified.

    So if you want a light source that is stationary relative to the camera, you need to make the glLightfv(.., GL_POSITION, ..) call while no model transformations are on the matrix stack.

I don't think putting the light exactly at the camera position is very common. For CAD type systems, what I have seen most is a light source positioned at the top left. Or in other words, the light source is placed with a negative x-offset and a positive y-offset relative to the camera position. For better results, it can be beneficial to use more than one light source. For example, placing a (possibly weaker) light source in the opposite direction behind the objects can look really good. But you'll have to play with it to see what works best for you.

Also, even though you probably know this already, but I'll have to add the (almost) obligatory: Most of the OpenGL functionality you are using is obsolete and deprecated. If you are learning, I would strongly recommend to learn "modern OpenGL", meaning a version that is not using the fixed pipeline anymore, and is based on programmable shaders.

Upvotes: 2

Related Questions