JOGL: Lighting the Inside of a Cube

I originally posted this on the JOGL board here, but I haven’t had any replies there, so I’m trying my luck here.

I’m using JOGL, and I am trying to create a simple scene: an area surrounded by a cube, a camera that moves (arrow keys to rotate, p key to go forward), and a light that follows the camera.

I’ve got the cube in place, but I’m having quite a bit of trouble getting the lights to function how I expect them to. I would expect the sides of the cube to get brighter in areas that are closer to the light. Instead, I get strange artifacts on each side of the cube. Here is the camera looking into a corner:

http://forum.jogamp.org/file/n4033471/ss.png

I would expect the corner to be lit up, with the sides getting darker the further away from the light they got.

I thought this might be a result of only using a single polygon for each side of the cube, so I split one of the sides into a bunch of polygons. That side looks like this:

http://forum.jogamp.org/file/n4033471/ss1.png

This is closer to what I’m looking for, but it’s still not quite right. The light seems to be focused in one location instead of spreading out evenly.

I’ve posted the code below. Is there anything obvious I’m doing wrong? Can anybody show me a little example that does what I’m describing?


import java.awt.BorderLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.swing.JFrame;

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.FPSAnimator;

public class CameraTest implements GLEventListener {


	private final GLCanvas canvas = new GLCanvas();

	private final int worldX = -400;
	private final int worldY = -400;
	private final int worldWidth = 800;
	private final int worldHeight = 800;
	private final int worldZ = 100;
	private final int worldDepth = 800;

	private GL gl;

	private boolean upPressed = false;
	private boolean downPressed = false;
	private boolean leftPressed = false;
	private boolean rightPressed = false;
	private boolean pPressed = false;

	double speed = 5;

	private double pitchAngle = 0;
	private double rollAngle = 0;

	Vector3D cameraPos = new Vector3D(0, 0, 400);
	Vector3D cameraDirection = new Vector3D(0, 0, -1);

	public CameraTest(){



		canvas.addGLEventListener(this);
		gl = canvas.getGL();



		Animator animator = new FPSAnimator(canvas, 60);
		animator.start();

		canvas.addKeyListener(new KeyAdapter(){

			@Override
			public void keyReleased(KeyEvent e) {

				if(e.getKeyCode() == KeyEvent.VK_UP){
					upPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_DOWN){
					downPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_LEFT){
					leftPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
					rightPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_P){
					pPressed = false;
				}
			}

			@Override
			public void keyPressed(KeyEvent e) {


				if(e.getKeyCode() == KeyEvent.VK_UP){
					upPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_DOWN){
					downPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_LEFT){
					leftPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
					rightPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_P){
					pPressed = true;
				}

				System.out.println();
				System.out.println("Pos: " + cameraPos.toString());
				System.out.println("Dir: " + cameraDirection.toString());
			}
		});

		JFrame frame = new JFrame("Camera Test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(canvas, BorderLayout.CENTER);

		frame.setSize(500, 500);
		frame.setLocation(1500, 500);
		frame.setVisible(true);

		canvas.requestFocusInWindow();
	}


	public void init(GLAutoDrawable drawable) {

	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glEnable(GL.GL_BLEND);
		gl.glEnable(GL.GL_NORMALIZE);

		gl.glEnable(GL.GL_LIGHTING);
		gl.glEnable(GL.GL_LIGHT0);

		gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, new float[]{1f, 1f, 1f, 1},0);
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_EMISSION, new float[]{.1f, .1f, .1f, 1},0);
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, new float[]{0f, 0f, 0f, 1},0);
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);

		gl.glEnable(GL.GL_LIGHT1);
		gl.glLightf(GL.GL_LIGHT1, GL.GL_SPOT_CUTOFF, 45f);
		gl.glLightf(GL.GL_LIGHT1, GL.GL_SPOT_EXPONENT, 2f);
	    gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT,  new float[]{1f, 1f, 1f, 1},0);
	    gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE,  new float[]{1f, 1f, 1f, 1},0);
	    gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR,  new float[]{1f, 1f, 1f, 1},0);
	    gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);

		gl.glBlendFunc(GL.GL_SRC_ALPHA,  GL.GL_ONE_MINUS_SRC_ALPHA);

		gl.glEnable(GL.GL_CULL_FACE);
		gl.glCullFace(GL.GL_BACK);

		gl.glLoadIdentity();
		gl.glFrustum(-1, 1, -1, 1, 1, worldZ + worldDepth + 10);
		gl.glViewport(0, 0, width, height);

		gl.glClearColor(.25f, .25f, .25f, 1f);
	}


	public void display(GLAutoDrawable drawable){
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		step();
		displayFromCamera(drawable);
	}

	private void step(){

		gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, new float[]{(float)cameraPos.x, (float)cameraPos.y, (float)cameraPos.z}, 0);

		
		float dirX = (float) (Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle )));
		float dirY = (float) (-Math.sin(Math.toRadians(pitchAngle) ));
		float dirZ = (float) (Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle)));
		
		gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPOT_DIRECTION, new float[]{dirX, dirY, dirZ},0);
	    gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, new float[]{(float)cameraPos.x, (float)cameraPos.y, (float)cameraPos.z},0);


		if(upPressed){
			pitchAngle+=1;
		}
		if(downPressed){
			pitchAngle-=1;
		}

		while(pitchAngle < 0){
			pitchAngle += 360;
		}
		while(pitchAngle > 360){
			pitchAngle -= 360;
		}

		if(leftPressed){
			if(pitchAngle < 270 && pitchAngle > 90){
				rollAngle+=1;
			}
			else{
				rollAngle-=1;
			}

		}
		if(rightPressed){
			if(pitchAngle < 270 && pitchAngle > 90){
				rollAngle-=1;
			}
			else{
				rollAngle+=1;
			}
		}

		if(pPressed){
			double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
			double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
			double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

			cameraPos = cameraPos.add(new Vector3D(newPosX, newPosY, newPosZ));
		}
	}

	public void displayFromCamera(GLAutoDrawable drawable){
		gl.glPushMatrix();


		gl.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());

		gl.glLoadIdentity();

		gl.glFrustum(-1, 1, -1, 1, 1, 100000);

		gl.glRotated(pitchAngle, 1, 0, 0);
		gl.glRotated(rollAngle, 0, 1, 0);

		gl.glTranslated(-cameraPos.x, -cameraPos.y, cameraPos.z);

		displayWholeScene(drawable, false);

		gl.glPopMatrix();
	}


	public void material(float r, float g, float b){

		float[] m = {r, g, b, 1};

			gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, m,0);
		//	gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 100.0f);
		gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, m, 0);
		//gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, m, 0);
		//gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, m, 0);
	}

	public void displayWholeScene(GLAutoDrawable drawable, boolean drawSnake){


		gl.glLineWidth(5f);

		gl.glPolygonMode(GL.GL_BACK, GL.GL_LINES);
		gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL);

		//front

		gl.glColor3f(1, 0, 0);
		material(.1f, 0, 0);
		gl.glBegin(GL.GL_POLYGON);
		gl.glNormal3d(0, 0, -1);
		gl.glVertex3d(worldX, worldY+worldHeight, -worldZ);
		gl.glVertex3d(worldX+worldWidth, worldY+worldHeight, -worldZ);
		gl.glVertex3d(worldX+worldWidth, worldY, -worldZ);
		gl.glVertex3d(worldX, worldY, -worldZ);
		gl.glEnd();

		//back
		//		gl.glBegin(GL.GL_POLYGON);
		//		gl.glColor3f(0, 1, 0);
		//		material(0, 0, 1);
		//		gl.glNormal3d(0, 0, 1);
		//		gl.glVertex3d(worldX, worldY, -(worldZ+worldDepth));
		//		gl.glVertex3d(worldX+worldWidth, worldY, -(worldZ+worldDepth));
		//		gl.glVertex3d(worldX+worldWidth, worldY+worldHeight, -(worldZ+worldDepth));
		//		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ+worldDepth));
		//		gl.glEnd();

		double w = (worldWidth)/25;
		double h = (worldHeight)/25;

		for(double x = worldX; x < worldX+worldWidth; x+=w){
			for(double y = worldY; y < worldY+worldHeight; y+=h){

				gl.glBegin(GL.GL_POLYGON);

				gl.glColor3f(0, 1, 0);
				material(0, .5f, 0);
				gl.glNormal3d(0, 0, 1);

				gl.glVertex3d(x, y, -(worldZ+worldDepth));
				gl.glVertex3d(x+w, y, -(worldZ+worldDepth));
				gl.glVertex3d(x+w, y+h, -(worldZ+worldDepth));
				gl.glVertex3d(x, y+h, -(worldZ+worldDepth));
				gl.glEnd();
			}
		}



		//left side

		gl.glBegin(GL.GL_POLYGON);
		gl.glColor3f(0, 0, 1);
		material(0, 0, 1);
		gl.glNormal3d(1, 0, 0);
		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ+worldDepth));
		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ));
		gl.glVertex3d(worldX, worldY, -(worldZ));
		gl.glVertex3d(worldX, worldY, -(worldZ+worldDepth));
		gl.glEnd();


		//right side
		gl.glBegin(GL.GL_POLYGON);
		gl.glColor3f(1, 1, 0);
		material(1, 1, 0);
		gl.glNormal3d(0, -1, 0);
		gl.glVertex3d(worldX+worldWidth, worldY, -(worldZ+worldDepth));
		gl.glVertex3d(worldX+worldWidth, worldY, -(worldZ));
		gl.glVertex3d(worldX+worldWidth, worldY+worldHeight, -(worldZ));
		gl.glVertex3d(worldX+worldWidth, worldY+worldHeight, -(worldZ+worldDepth));
		gl.glEnd();

		//bottom
		gl.glBegin(GL.GL_POLYGON);
		gl.glColor3f(0, 1, 1);
		material(0, 1, 1);
		gl.glNormal3d(0, 1, 0);
		gl.glVertex3d(worldX+worldHeight, worldY, -worldZ);
		gl.glVertex3d(worldX+worldWidth, worldY, -(worldZ+worldDepth));
		gl.glVertex3d(worldX, worldY, -(worldZ+worldDepth));
		gl.glVertex3d(worldX, worldY, -worldZ);
		gl.glEnd();

		//top
		gl.glBegin(GL.GL_POLYGON);
		gl.glNormal3d(0, -1, 0);
		gl.glColor3f(1, 0, 1);
		material(1, 0, 1);
		gl.glVertex3d(worldX, worldY+worldHeight, -worldZ);
		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ+worldDepth));
		gl.glVertex3d(worldX+worldWidth, worldY+worldHeight, -(worldZ+worldDepth));
		gl.glVertex3d(worldX+worldHeight, worldY+worldHeight, -worldZ);
		gl.glEnd();
	}

	public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
	}


	private static class Vector3D{
		private final double x;
		private final double y;
		private final double z;

		public Vector3D(double x, double y, double z){
			this.x = x;
			this.y = y;
			this.z = z;
		}

		public Vector3D add(Vector3D delta) {
			return new Vector3D(x+delta.x, y+delta.y, z+delta.z);
		}

		public String toString(){
			return x + ", " + y + ", " + z;
		}

	}

	public static void main(String[] args) {
		new CameraTest();
	}
}

Are you looking to have a point light and spot light? Kind of like a flashlight in the dark?

Your code does not compile which version of Jogl are you using?

Also, is there any reason you’re using fixed function and not a shader for this? I know people ask that a lot, but it’s seriously easier in all respects

Anyway my only idea is that your rotations are off, I don’t see anything glaring.

Two things I did notice…
gl.glTranslated(-cameraPos.x, -cameraPos.y, cameraPos.z); <- z should probably be inverted as well

you set diffuse twice instead of emission
gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, new float[]{1f, 1f, 1f, 1},0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, new float[]{1f, 1f, 1f, 1},0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);

Thanks for the reply.

I’m using JOGL 1.1, for the same reason I’m not using shaders: this is for a class that requires 1.1, and we haven’t covered shaders yet.

I’m not sure what kind of light I’m going for. The project is pretty vague and just says “add some lights”, so I was just going for something basic to start with. When it didn’t work how I expected it to, I figured I’d check here to see what I’m doing wrong.

Reversing the sign of Z doesn’t really seem to change the behavior at all. And the light that I set the diffuse property on twice isn’t even active. Activating it and setting the emission instead of the diffuse property also does not seem to change the behavior.

Mostly I’m just going for something basic and “realistic looking” to start. I would expect the walls of the cube to be brighter closer to the light, but what I’m seeing is mostly dark walls with a small spot of light only where the normal lines up with the camera angle. I have to be doing something wrong, I just don’t know what it is.

That’s exactly why you’re not getting any light, you need all your normals to be facing inwards to the center of the cube. That’s probably why you don’t see the area getting brighter. Disable backface culling and go outside of your cube, if the areas that are dark are instead bright on the outside of your cube…

Also, if I remember correctly you’re going to need more than one normal per face, add normals so there is one normal per vertex.

I do have all my normals facing inwards, and disabling backface culling only results in a similar small light displaying on the outside of the cube.

I’ve added normals for each vertex, but it doesn’t change anything. All of the vertices should have the same normal since they’re all facing the same direction anyway.

Lighting code’s fine, your camera seems to be kinda jacked, anyway it works for me here’s what I’m working with (had to use GL2 to get it to compile for me).

Run it and move toward the polygon in front of you, works like a charm.

package CameraTest;

import java.awt.BorderLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;

import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.FPSAnimator;

public class CameraTest implements GLEventListener {


   private final GLCanvas canvas = new GLCanvas();

   private final int worldX = -400;
   private final int worldY = -400;
   private final int worldWidth = 800;
   private final int worldHeight = 800;
   private final int worldZ = 100;
   private final int worldDepth = 800;

   public GL2 gl;

   private boolean upPressed = false;
   private boolean downPressed = false;
   private boolean leftPressed = false;
   private boolean rightPressed = false;
   private boolean pPressed = false;

   double speed = 5;

   private double pitchAngle = 0;
   private double rollAngle = 0;

   Vector3D cameraPos = new Vector3D(0, 0, 400);
   Vector3D cameraDirection = new Vector3D(0, 0, -1);

   public CameraTest(){



      canvas.addGLEventListener(this);
      gl = (GL2) canvas.getGL();



      FPSAnimator animator = new FPSAnimator(canvas, 60);
      animator.start();

      canvas.addKeyListener(new KeyAdapter(){

         @Override
         public void keyReleased(KeyEvent e) {

            if(e.getKeyCode() == KeyEvent.VK_UP){
               upPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_DOWN){
               downPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_LEFT){
               leftPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
               rightPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_P){
               pPressed = false;
            }
         }

         @Override
         public void keyPressed(KeyEvent e) {


            if(e.getKeyCode() == KeyEvent.VK_UP){
               upPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_DOWN){
               downPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_LEFT){
               leftPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
               rightPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_P){
               pPressed = true;
            }

            System.out.println();
            System.out.println("Pos: " + cameraPos.toString());
            System.out.println("Dir: " + cameraDirection.toString());
         }
      });

      JFrame frame = new JFrame("Camera Test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(canvas, BorderLayout.CENTER);

      frame.setSize(500, 500);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);

      canvas.requestFocusInWindow();
   }


   public void init(GLAutoDrawable drawable) {

   }

   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
      gl = (GL2) canvas.getGL();
	   
	   gl.glEnable(GL.GL_DEPTH_TEST);
      gl.glMatrixMode(GL2.GL_MODELVIEW);
      gl.glEnable(GL.GL_BLEND);

      gl.glEnable(GL2.GL_LIGHTING);
      gl.glEnable(GL2.GL_LIGHT0);

      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, new float[]{1f, 1f, 1f, 1},0);
      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_EMISSION, new float[]{.1f, .1f, .1f, 1},0);
      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, new float[]{0f, 0f, 0f, 1},0);
      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);

      gl.glBlendFunc(GL.GL_SRC_ALPHA,  GL.GL_ONE_MINUS_SRC_ALPHA);

      gl.glLoadIdentity();
      gl.glFrustum(-1, 1, -1, 1, 1, worldZ + worldDepth + 10);
      gl.glViewport(0, 0, width, height);

      gl.glClearColor(.25f, .25f, .25f, 1f);
   }


   public void display(GLAutoDrawable drawable){
      gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
      step();
      displayFromCamera(drawable);
   }

   private void step(){

      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, new float[]{(float)cameraPos.x, (float)cameraPos.y, (float)cameraPos.z}, 0);

      if(upPressed){
         pitchAngle+=1;
      }
      if(downPressed){
         pitchAngle-=1;
      }

      while(pitchAngle < 0){
         pitchAngle += 360;
      }
      while(pitchAngle > 360){
         pitchAngle -= 360;
      }

      if(leftPressed){
         if(pitchAngle < 270 && pitchAngle > 90){
            rollAngle+=1;
         }
         else{
            rollAngle-=1;
         }

      }
      if(rightPressed){
         if(pitchAngle < 270 && pitchAngle > 90){
            rollAngle-=1;
         }
         else{
            rollAngle+=1;
         }
      }
      float dirX = (float) (Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle )));
      float dirY = (float) (-Math.sin(Math.toRadians(pitchAngle) ));
      float dirZ = (float) (Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle)));
      
      cameraDirection = new Vector3D(dirX, dirY, dirZ);
      
      if(pPressed){
         double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
         double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
         double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

         cameraPos = cameraPos.add(new Vector3D(newPosX, newPosY, -newPosZ));
      }
   }

   public void displayFromCamera(GLAutoDrawable drawable){
      gl.glPushMatrix();


      gl.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());

      gl.glLoadIdentity();

      gl.glFrustum(-1, 1, -1, 1, 1, 100000);

      gl.glRotated(pitchAngle, 1, 0, 0);
      gl.glRotated(rollAngle, 0, 1, 0);

      gl.glTranslated(-cameraPos.x, -cameraPos.y, -cameraPos.z);

      displayWholeScene(drawable, false);

      gl.glPopMatrix();
   }


   public void material(float r, float g, float b){

      float[] m = {r, g, b, 1};

         gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, m,0);
      //   gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 100.0f);
      gl.glMaterialfv(GL.GL_FRONT, GL2.GL_DIFFUSE, m, 0);
      //gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, m, 0);
      //gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, m, 0);
   }

   public void displayWholeScene(GLAutoDrawable drawable, boolean drawSnake){

      double w = (worldWidth)/25;
      double h = (worldHeight)/25;

      for(double x = worldX; x < worldX+worldWidth; x+=w){
         for(double y = worldY; y < worldY+worldHeight; y+=h){

            gl.glBegin(GL2.GL_POLYGON);

            gl.glColor3f(0, 1, 0);
            material(0, .5f, 0);
            gl.glNormal3d(0, 0, 1);
            gl.glVertex3d(x, y, -(worldZ+worldDepth));
            gl.glVertex3d(x+w, y, -(worldZ+worldDepth));
            gl.glVertex3d(x+w, y+h, -(worldZ+worldDepth));
            gl.glVertex3d(x, y+h, -(worldZ+worldDepth));
            gl.glEnd();
         }
      }
	   

	      gl.glBegin(GL2.GL_POLYGON);
	      gl.glColor3f(0, 0, 1);
	      material(0, 0, 1);
	      gl.glNormal3d(-1, 0, 0);
	      gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ+worldDepth));
	      gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ));
	      gl.glVertex3d(worldX, worldY, -(worldZ));
	      gl.glVertex3d(worldX, worldY, -(worldZ+worldDepth));
	      gl.glEnd();
	      
   }

   public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
   }


   private static class Vector3D{
      private final double x;
      private final double y;
      private final double z;

      public Vector3D(double x, double y, double z){
         this.x = x;
         this.y = y;
         this.z = z;
      }

      public Vector3D add(Vector3D delta) {
         return new Vector3D(x+delta.x, y+delta.y, z+delta.z);
      }

      public String toString(){
         return x + ", " + y + ", " + z;
      }

   }

   public static void main(String[] args) {
      new CameraTest();
   }


@Override
public void dispose(GLAutoDrawable arg0)
{
	// TODO Auto-generated method stub
	
}
}

Thanks again for the reply and for taking the time to convert it over to GL2. The green wall is much closer to what I’m looking for now:

However, why is it all black until I reach some threshold distance from the wall? Is there a way to change that threshold?

It also still has some strange artifacts when I’m not looking at it head-on:

I’m also trying to split the blue wall into multiple polygons just like the green one, and it seems to work as long as I’m very close to the wall:

But from almost every other position, the wall is entirely black:

I’ve checked the other side, and I’m pretty sure my polygon and its normal are facing the correct direction.

I’ve posted my updated code below (all I’ve added is the ability to go backwards by pressing O, and the splitting of the blue wall), can you see anything else I’m doing wrong?


import java.awt.BorderLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;

import com.jogamp.opengl.util.FPSAnimator;

public class CameraTest implements GLEventListener {


	private final GLCanvas canvas = new GLCanvas();

	private final int worldX = -400;
	private final int worldY = -400;
	private final int worldWidth = 800;
	private final int worldHeight = 800;
	private final int worldZ = 100;
	private final int worldDepth = 800;

	public GL2 gl;

	private boolean upPressed = false;
	private boolean downPressed = false;
	private boolean leftPressed = false;
	private boolean rightPressed = false;
	private boolean pPressed = false;
	private boolean oPressed = false;

	double speed = 5;

	private double pitchAngle = 0;
	private double rollAngle = 0;

	Vector3D cameraPos = new Vector3D(0, 0, 400);
	Vector3D cameraDirection = new Vector3D(0, 0, -1);

	public CameraTest(){



		canvas.addGLEventListener(this);
		gl = (GL2) canvas.getGL();



		FPSAnimator animator = new FPSAnimator(canvas, 60);
		animator.start();

		canvas.addKeyListener(new KeyAdapter(){

			@Override
			public void keyReleased(KeyEvent e) {

				if(e.getKeyCode() == KeyEvent.VK_UP){
					upPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_DOWN){
					downPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_LEFT){
					leftPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
					rightPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_P){
					pPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_O){
					oPressed = false;
				}
			}

			@Override
			public void keyPressed(KeyEvent e) {


				if(e.getKeyCode() == KeyEvent.VK_UP){
					upPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_DOWN){
					downPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_LEFT){
					leftPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
					rightPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_P){
					pPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_O){
					oPressed = true;
				}

				System.out.println();
				System.out.println("Pos: " + cameraPos.toString());
				System.out.println("Dir: " + cameraDirection.toString());
			}
		});

		JFrame frame = new JFrame("Camera Test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(canvas, BorderLayout.CENTER);

		frame.setSize(500, 500);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);

		canvas.requestFocusInWindow();
	}


	public void init(GLAutoDrawable drawable) {

	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		gl = (GL2) canvas.getGL();

		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glMatrixMode(GL2.GL_MODELVIEW);
		gl.glEnable(GL.GL_BLEND);

		gl.glEnable(GL2.GL_LIGHTING);
		gl.glEnable(GL2.GL_LIGHT0);

		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, new float[]{1f, 1f, 1f, 1},0);
		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_EMISSION, new float[]{.1f, .1f, .1f, 1},0);
		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, new float[]{0f, 0f, 0f, 1},0);
		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);

		gl.glBlendFunc(GL.GL_SRC_ALPHA,  GL.GL_ONE_MINUS_SRC_ALPHA);

		gl.glLoadIdentity();
		gl.glFrustum(-1, 1, -1, 1, 1, worldZ + worldDepth + 10);
		gl.glViewport(0, 0, width, height);

		gl.glClearColor(.25f, .25f, .25f, 1f);
	}


	public void display(GLAutoDrawable drawable){
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		step();
		displayFromCamera(drawable);
	}

	private void step(){

		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, new float[]{(float)cameraPos.x, (float)cameraPos.y, (float)cameraPos.z}, 0);

		if(upPressed){
			pitchAngle+=1;
		}
		if(downPressed){
			pitchAngle-=1;
		}

		while(pitchAngle < 0){
			pitchAngle += 360;
		}
		while(pitchAngle > 360){
			pitchAngle -= 360;
		}

		if(leftPressed){
			if(pitchAngle < 270 && pitchAngle > 90){
				rollAngle+=1;
			}
			else{
				rollAngle-=1;
			}

		}
		if(rightPressed){
			if(pitchAngle < 270 && pitchAngle > 90){
				rollAngle-=1;
			}
			else{
				rollAngle+=1;
			}
		}
		float dirX = (float) (Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle )));
		float dirY = (float) (-Math.sin(Math.toRadians(pitchAngle) ));
		float dirZ = (float) (Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle)));

		cameraDirection = new Vector3D(dirX, dirY, dirZ);

		if(pPressed){
			double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
			double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
			double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

			cameraPos = cameraPos.add(new Vector3D(newPosX, newPosY, -newPosZ));
		}
		
		if(oPressed){
			double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
			double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
			double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

			cameraPos = cameraPos.add(new Vector3D(-newPosX, -newPosY, newPosZ));
		}
	}

	public void displayFromCamera(GLAutoDrawable drawable){
		gl.glPushMatrix();


		gl.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());

		gl.glLoadIdentity();

		gl.glFrustum(-1, 1, -1, 1, 1, 100000);

		gl.glRotated(pitchAngle, 1, 0, 0);
		gl.glRotated(rollAngle, 0, 1, 0);

		gl.glTranslated(-cameraPos.x, -cameraPos.y, -cameraPos.z);

		displayWholeScene(drawable, false);

		gl.glPopMatrix();
	}


	public void material(float r, float g, float b){

		float[] m = {r, g, b, 1};

		gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, m,0);
		//   gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 100.0f);
		gl.glMaterialfv(GL.GL_FRONT, GL2.GL_DIFFUSE, m, 0);
		//gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, m, 0);
		//gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, m, 0);
	}

	public void displayWholeScene(GLAutoDrawable drawable, boolean drawSnake){

		double w = (worldWidth)/10;
		double h = (worldHeight)/10;
	      double d = worldDepth/10;

		for(double x = worldX; x < worldX+worldWidth; x+=w){
			for(double y = worldY; y < worldY+worldHeight; y+=h){

				gl.glBegin(GL2.GL_POLYGON);

				gl.glColor3f(0, 1, 0);
				material(0, .5f, 0);
				gl.glNormal3d(0, 0, 1);
				gl.glVertex3d(x, y, -(worldZ+worldDepth));
				gl.glVertex3d(x+w, y, -(worldZ+worldDepth));
				gl.glVertex3d(x+w, y+h, -(worldZ+worldDepth));
				gl.glVertex3d(x, y+h, -(worldZ+worldDepth));
				gl.glEnd();
			}
		}
		
	      for(double z = worldZ; z < worldZ + worldDepth; z+=d){
	    	  for(double y = worldY; y < worldY+worldHeight; y+=h){
	    	         gl.glBegin(GL2.GL_POLYGON);
	    	         gl.glColor3f(0, 0, 1);
	    	         material(0, 0, .5f);
	    	         gl.glNormal3d(1, 0, 0);
	    	         gl.glVertex3d(worldX, y, -(z+d));
	    	         gl.glVertex3d(worldX, y, -(z));
	    	         gl.glVertex3d(worldX, y+h, -(z));
	    	         gl.glVertex3d(worldX, y+h, -(z+d));
	  
	    	         gl.glEnd();
	    	  }
	      }


//		gl.glBegin(GL2.GL_POLYGON);
//		gl.glColor3f(0, 0, 1);
//		material(0, 0, 1);
//		gl.glNormal3d(-1, 0, 0);
//		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ+worldDepth));
//		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ));
//		gl.glVertex3d(worldX, worldY, -(worldZ));
//		gl.glVertex3d(worldX, worldY, -(worldZ+worldDepth));
//		gl.glEnd();

	}

	public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
	}


	private static class Vector3D{
		private final double x;
		private final double y;
		private final double z;

		public Vector3D(double x, double y, double z){
			this.x = x;
			this.y = y;
			this.z = z;
		}

		public Vector3D add(Vector3D delta) {
			return new Vector3D(x+delta.x, y+delta.y, z+delta.z);
		}

		public String toString(){
			return x + ", " + y + ", " + z;
		}

	}

	public static void main(String[] args) {
		new CameraTest();
	}


	@Override
	public void dispose(GLAutoDrawable arg0)
	{
		// TODO Auto-generated method stub

	}
}

You should use JOGL 2 as JOGL 1 is no longer maintained (since 2010). JOGL 2 still supports OpenGL 1.1. Please don’t post any source code using JOGL 1 in order to avoid causing any confusion. Imagine that a beginner copies/pastes your code, (s)he will waste some precious time to understand why it doesn’t work with JOGL 2.

Use JOGL 2 and you might get much luck next time.

I would love to use JOGL 2, unfortunately the class requires that I use JOGL 1.

However, the latest code I posted is all JOGL 2, in an attempt to make it easier for folks to take a look. I’m still having issues even after switching to JOGL 2, so I’d definitely appreciate any insights you can offer!

Which class? Sorry, English isn’t my mother tongue. Sometimes I don’t understand what people mean even though it is obvious. JOGL 1 must NOT be used, it’s obsolete, it’s unmaintained, it’s not guaranteed to work on any OS or OS version released after 2010. Going on using JOGL 1 is dangerous and causes confusion. If a teacher asks you to use it, you should question his knowledge of computer graphics. I’m fed up because if something goes wrong, it will be our fault again. Several months ago, a guy came on our official forum to insult us because he found tons of “obsolete” examples based on JOGL 1.

If I were you, I would just modify the normals or the winding in order to confirm or infirm that this is the root cause of your troubles… and I would use JOGL 2 exclusively of course.

I’m in a graduate-level computer graphics course, and the course requires that we use JOGL 1 for our homework and projects. I don’t want to get into a big debate (especially since it’s not my decision), but the latest code I posted only uses JOGL 2 anyway, so hopefully it should be a moot point.

That’s the first thing I tried. The winding seems to be correct, and the normals seem to be pointing the correct direction.

And just so I’m clear, the latest code does only use JOGL 2.

i havn’t done fixed pipeline lightning for ages but i remember trouble like that … maybe it’s the wrong space :

Sorry if this is a stupid question, but does that mean this might be a result of having the light follow the camera position?

I don’t actually need to have the light follow the camera, I just figured it was the easiest way to get started as an example. In my final project, the lights will be independent of the camera’s movement.

Detach your light from the camera and place it a the origin, draw it and give controls to modify its location. I’m almost certain that the issues you have are with both your camera, not the lighting itself.

side note: May I ask which class? I see zero reason to writing openGL 1 code. Like gouessej says it’s not supported or even guarenteed to work on modern hardware. I don’t want to argue about it, just curious.

@gouessej: jogl is awesome (except lazy init of openGL), don’t listen to all the haters haha

Okay, I’ve made it so the light position is independent of the camera position. The light position is rendered as a small pixel, and you can move it with the number keys (1+2 control X, 3+4 control Y, 5+6 control Z). The camera movement works as before.

However, I’m still getting similar artifacts. I’ve checked and rechecked the winding and the normals, and they all seem correct. Here’s the updated code if anybody wants to point out anything I’ve done wrong:


import java.awt.BorderLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;


import com.jogamp.opengl.util.FPSAnimator;

public class CameraTest implements GLEventListener {


	private final GLCanvas canvas = new GLCanvas();

	private final int worldX = -400;
	private final int worldY = -400;
	private final int worldWidth = 800;
	private final int worldHeight = 800;
	private final int worldZ = 100;
	private final int worldDepth = 800;

	public GL2 gl;

	private boolean upPressed = false;
	private boolean downPressed = false;
	private boolean leftPressed = false;
	private boolean rightPressed = false;
	private boolean pPressed = false;
	private boolean oPressed = false;

	double speed = 5;

	private double pitchAngle = 0;
	private double rollAngle = 210;

	Vector3D cameraPos = new Vector3D((worldX + worldWidth)/2, (worldY+worldHeight)/2, (worldZ + worldDepth)/2);

	Vector3D lightPos = new Vector3D((worldX + worldWidth)/2-10, (worldY+worldHeight)/2-10, (worldZ + worldDepth)/2+100);

	public CameraTest(){



		canvas.addGLEventListener(this);
		gl = (GL2) canvas.getGL();



		FPSAnimator animator = new FPSAnimator(canvas, 60);
		animator.start();

		canvas.addKeyListener(new KeyAdapter(){

			@Override
			public void keyReleased(KeyEvent e) {

				if(e.getKeyCode() == KeyEvent.VK_UP){
					upPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_DOWN){
					downPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_LEFT){
					leftPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
					rightPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_P){
					pPressed = false;
				}
				else if(e.getKeyCode() == KeyEvent.VK_O){
					oPressed = false;
				}
			}

			@Override
			public void keyPressed(KeyEvent e) {


				if(e.getKeyCode() == KeyEvent.VK_UP){
					upPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_DOWN){
					downPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_LEFT){
					leftPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
					rightPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_P){
					pPressed = true;
				}
				else if(e.getKeyCode() == KeyEvent.VK_O){
					oPressed = true;
				}

				else if(e.getKeyCode() == KeyEvent.VK_1){
					lightPos = lightPos.add(new Vector3D(-10, 0, 0));
				}
				else if(e.getKeyCode() == KeyEvent.VK_2){
					lightPos = lightPos.add(new Vector3D(10, 0, 0));
				}
				else if(e.getKeyCode() == KeyEvent.VK_3){
					lightPos = lightPos.add(new Vector3D(0, -10, 0));
				}
				else if(e.getKeyCode() == KeyEvent.VK_4){
					lightPos = lightPos.add(new Vector3D(0, 10, 0));
				}
				else if(e.getKeyCode() == KeyEvent.VK_5){
					lightPos = lightPos.add(new Vector3D(0, 0, -10));
				}
				else if(e.getKeyCode() == KeyEvent.VK_6){
					lightPos = lightPos.add(new Vector3D(0, 0, 10));
				}

				//System.out.println();
				System.out.println("Pos: " + lightPos.toString());
			}
		});

		JFrame frame = new JFrame("Camera Test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(canvas, BorderLayout.CENTER);

		frame.setSize(500, 500);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);

		canvas.requestFocusInWindow();
	}


	public void init(GLAutoDrawable drawable) {

	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		gl = (GL2) canvas.getGL();

		gl.glEnable(GL.GL_CULL_FACE);
		gl.glCullFace(GL.GL_BACK);

		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glMatrixMode(GL2.GL_MODELVIEW);
		gl.glEnable(GL.GL_BLEND);

		gl.glEnable(GL2.GL_LIGHTING);
		gl.glEnable(GL2.GL_LIGHT0);

		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, new float[]{1f, 1f, 1f, 1},0);
		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_EMISSION, new float[]{.1f, .1f, .1f, 1},0);
		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, new float[]{0f, 0f, 0f, 1},0);
		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);

		gl.glBlendFunc(GL.GL_SRC_ALPHA,  GL.GL_ONE_MINUS_SRC_ALPHA);

		gl.glLoadIdentity();
		gl.glFrustum(-1, 1, -1, 1, 1, worldZ + worldDepth + 10);
		gl.glViewport(0, 0, width, height);

		gl.glClearColor(.25f, .25f, .25f, 1f);
	}


	public void display(GLAutoDrawable drawable){
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		step();
		displayFromCamera(drawable);
	}

	private void step(){

		gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, new float[]{(float)lightPos.x, (float)lightPos.y, (float)lightPos.z}, 0);

		if(upPressed){
			pitchAngle+=1;
		}
		if(downPressed){
			pitchAngle-=1;
		}

		while(pitchAngle < 0){
			pitchAngle += 360;
		}
		while(pitchAngle > 360){
			pitchAngle -= 360;
		}

		if(leftPressed){
			if(pitchAngle < 270 && pitchAngle > 90){
				rollAngle+=1;
			}
			else{
				rollAngle-=1;
			}

		}
		if(rightPressed){
			if(pitchAngle < 270 && pitchAngle > 90){
				rollAngle-=1;
			}
			else{
				rollAngle+=1;
			}
		}
		
		if(pPressed){
			double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
			double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
			double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

			cameraPos = cameraPos.add(new Vector3D(newPosX, newPosY, -newPosZ));
		}

		if(oPressed){
			double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
			double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
			double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

			cameraPos = cameraPos.add(new Vector3D(-newPosX, -newPosY, newPosZ));
		}
	}

	public void displayFromCamera(GLAutoDrawable drawable){
		gl.glPushMatrix();


		gl.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());

		gl.glLoadIdentity();

		gl.glFrustum(-1, 1, -1, 1, 1, 100000);

		gl.glRotated(pitchAngle, 1, 0, 0);
		gl.glRotated(rollAngle, 0, 1, 0);

		gl.glTranslated(-cameraPos.x, -cameraPos.y, -cameraPos.z);

		displayWholeScene(drawable, false);

		gl.glPopMatrix();
	}


	public void material(float r, float g, float b){

		float[] m = {r, g, b, 1};

		gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, m,0);
		//   gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 100.0f);
		gl.glMaterialfv(GL.GL_FRONT, GL2.GL_DIFFUSE, m, 0);
		//gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, m, 0);
		//gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, m, 0);
	}

	public void displayWholeScene(GLAutoDrawable drawable, boolean drawSnake){
		
		
		
		material(1, 1, 1);
        gl.glPointSize(1000/(cameraPos.distance(lightPos)+1));
        gl.glBegin(GL.GL_POINTS);
        gl.glVertex3d(lightPos.x, lightPos.y, lightPos.z);
        gl.glEnd();

		double w = (worldWidth)/10;
		double h = (worldHeight)/10;
		double d = worldDepth/10;

		for(double x = worldX; x < worldX+worldWidth; x+=w){
			for(double y = worldY; y < worldY+worldHeight; y+=h){

				gl.glBegin(GL2.GL_POLYGON);

				gl.glColor3f(0, 1, 0);
				material(0, .5f, 0);
				gl.glNormal3d(0, 0, -1);
				
				gl.glVertex3d(x, y+h, (worldZ+worldDepth));
				gl.glVertex3d(x+w, y+h, (worldZ+worldDepth));
				gl.glVertex3d(x+w, y, (worldZ+worldDepth));
				
				gl.glVertex3d(x, y, (worldZ+worldDepth));
				
				
				
				gl.glEnd();
			}
		}

		for(double z = worldZ; z < worldZ + worldDepth; z+=d){
			for(double y = worldY; y < worldY+worldHeight; y+=h){
				gl.glBegin(GL2.GL_POLYGON);
				gl.glColor3f(0, 0, 1);
				material(0, 0, .5f);
				gl.glNormal3d(1, 0, 0);
				
				
				
				gl.glVertex3d(worldX, y, (z+d));
				gl.glVertex3d(worldX, y, (z));
				gl.glVertex3d(worldX, y+h, (z));
				gl.glVertex3d(worldX, y+h, (z+d));

				gl.glEnd();
			}
		}


		//		gl.glBegin(GL2.GL_POLYGON);
		//		gl.glColor3f(0, 0, 1);
		//		material(0, 0, 1);
		//		gl.glNormal3d(-1, 0, 0);
		//		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ+worldDepth));
		//		gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ));
		//		gl.glVertex3d(worldX, worldY, -(worldZ));
		//		gl.glVertex3d(worldX, worldY, -(worldZ+worldDepth));
		//		gl.glEnd();

	}

	public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
	}


	private static class Vector3D{
		private final double x;
		private final double y;
		private final double z;

		public Vector3D(double x, double y, double z){
			this.x = x;
			this.y = y;
			this.z = z;
		}

		public float distance(Vector3D other) {
			return (float) Math.sqrt((x-other.x)*(x-other.x) + (y-other.y)*(y-other.y) + (z-other.z)*(z-other.z));
		}

		public Vector3D add(Vector3D delta) {
			return new Vector3D(x+delta.x, y+delta.y, z+delta.z);
		}

		public String toString(){
			return x + ", " + y + ", " + z;
		}

	}

	public static void main(String[] args) {
		new CameraTest();
	}


	@Override
	public void dispose(GLAutoDrawable arg0)
	{
		// TODO Auto-generated method stub

	}
}

[quote=“thedanisaur,post:14,topic:51805”]
I’m not asking anybody to do my project for me (nor would I!), I’m just trying to clear up my confusion on how my lighting is behaving, so I don’t think naming the course is a problem. It’s CS 551 at George Mason University.

Odd, I’ll take a look when I’m done with work.

Oh, no I guess I didn’t phrase my question well, not accusing you of cheating or anything. I was curious what the OBJECTIVE of the course was (not what course number and where), as that might help me understand why you’re being forced to use outdated techniques that’s all :point:.

I definitely appreciate it!

Oh yeah I didn’t think you were saying I was cheating, that was more for anybody else at my school who might come across this post. Anyway, if you’re curious, it’s a graduate-level intro to 3D graphics class that was previously taught in C++. The class was then converted to Java (presumably back when JOGL 1 was still the thing), and the professor wrote a JOGL book (http://www.amazon.com/Foundations-3D-Graphics-Programming-Java3D/dp/1848002831). That book (and the professor’s codebase) is still used for the class, which is probably why we still use JOGL 1 instead of updating to JOGL 2.

OK, so I’ve made some changes to your code, but not much. Basically, you have a spot light that is facing the wrong way. I thought openGL had a point light unless otherwise specified, but whatever. Anyway, when you are facing down the initial axis this isn’t a problem, but as soon as you rotate your light turns in an odd direction.

Here’s the code, at this point it feels super hacky so you’ll need to fix your normals and camera rotations and such:

package CameraTest;

import java.awt.BorderLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;

import com.jogamp.opengl.util.FPSAnimator;

public class CameraTest implements GLEventListener {


   private final GLCanvas canvas = new GLCanvas();

   private final int worldX = -400;
   private final int worldY = -400;
   private final int worldWidth = 800;
   private final int worldHeight = 800;
   private final int worldZ = 100;
   private final int worldDepth = 800;

   public GL2 gl;

   private boolean upPressed = false;
   private boolean downPressed = false;
   private boolean leftPressed = false;
   private boolean rightPressed = false;
   private boolean pPressed = false;
   private boolean oPressed = false;

   double speed = 5;

   private double pitchAngle = 0;
   private double rollAngle = 0;

   Vector3D cameraPos = new Vector3D(0, 0, 400);
   Vector3D cameraDirection = new Vector3D(0, 0, -1);

   public CameraTest(){



      canvas.addGLEventListener(this);
      gl = (GL2) canvas.getGL();



      FPSAnimator animator = new FPSAnimator(canvas, 60);
      animator.start();

      canvas.addKeyListener(new KeyAdapter(){

         @Override
         public void keyReleased(KeyEvent e) {

            if(e.getKeyCode() == KeyEvent.VK_UP){
               upPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_DOWN){
               downPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_LEFT){
               leftPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
               rightPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_P){
               pPressed = false;
            }
            else if(e.getKeyCode() == KeyEvent.VK_O){
               oPressed = false;
            }
         }

         @Override
         public void keyPressed(KeyEvent e) {


            if(e.getKeyCode() == KeyEvent.VK_UP){
               upPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_DOWN){
               downPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_LEFT){
               leftPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
               rightPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_P){
               pPressed = true;
            }
            else if(e.getKeyCode() == KeyEvent.VK_O){
               oPressed = true;
            }

            System.out.println();
            System.out.println("Pos: " + cameraPos.toString());
            System.out.println("Dir: " + cameraDirection.toString());
         }
      });

      JFrame frame = new JFrame("Camera Test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(canvas, BorderLayout.CENTER);

      frame.setSize(500, 500);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);

      canvas.requestFocusInWindow();
   }


   public void init(GLAutoDrawable drawable) {

   }

   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
      gl = (GL2) canvas.getGL();

      gl.glEnable(GL.GL_DEPTH_TEST);
      gl.glMatrixMode(GL2.GL_MODELVIEW);
      gl.glEnable(GL.GL_BLEND);

      gl.glEnable(GL2.GL_LIGHTING);
      gl.glEnable(GL2.GL_LIGHT0);

      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, new float[]{1f, 1f, 1f, 1},0);
      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_EMISSION, new float[]{.1f, .1f, .1f, 1},0);
      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, new float[]{0f, 0f, 0f, 1},0);
      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, new float[]{1f, 1f, 1f, 1},0);

      gl.glBlendFunc(GL.GL_SRC_ALPHA,  GL.GL_ONE_MINUS_SRC_ALPHA);

      gl.glLoadIdentity();
      gl.glFrustum(-1, 1, -1, 1, 1, worldZ + worldDepth + 10);
      gl.glViewport(0, 0, width, height);

      gl.glClearColor(.25f, .25f, .25f, 1f);
   }


   public void display(GLAutoDrawable drawable){
      gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
      step();
      displayFromCamera(drawable);
   }

   private void step(){

      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, new float[]{(float)cameraPos.x, (float)cameraPos.y, (float)cameraPos.z}, 0);

      gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPOT_DIRECTION, new float[]{(float) cameraDirection.x, (float) cameraDirection.y, (float) -cameraDirection.z, 1}, 0);

      if(upPressed){
         pitchAngle+=1;
      }
      if(downPressed){
         pitchAngle-=1;
      }

      while(pitchAngle < 0){
         pitchAngle += 360;
      }
      while(pitchAngle > 360){
         pitchAngle -= 360;
      }

      if(leftPressed){
         if(pitchAngle < 270 && pitchAngle > 90){
            rollAngle+=1;
         }
         else{
            rollAngle-=1;
         }

      }
      if(rightPressed){
         if(pitchAngle < 270 && pitchAngle > 90){
            rollAngle-=1;
         }
         else{
            rollAngle+=1;
         }
      }
      float dirX = (float) (Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle )));
      float dirY = (float) (-Math.sin(Math.toRadians(pitchAngle) ));
      float dirZ = (float) (Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle)));

      cameraDirection = new Vector3D(dirX, dirY, dirZ);

      if(pPressed){
         double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
         double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
         double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

         cameraPos = cameraPos.add(new Vector3D(newPosX, newPosY, -newPosZ));
      }
      
      if(oPressed){
         double newPosX = speed *  Math.sin(Math.toRadians(rollAngle)) * Math.cos(Math.toRadians(pitchAngle ));
         double newPosY = speed * -Math.sin(Math.toRadians(pitchAngle) );
         double newPosZ = speed *  Math.cos(Math.toRadians(rollAngle) ) * Math.cos(Math.toRadians(pitchAngle));

         cameraPos = cameraPos.add(new Vector3D(-newPosX, -newPosY, newPosZ));
      }
   }

   public void displayFromCamera(GLAutoDrawable drawable){
      gl.glPushMatrix();


      gl.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());

      gl.glLoadIdentity();

      gl.glFrustum(-1, 1, -1, 1, 1, worldZ + worldDepth * 10);

      gl.glRotated(pitchAngle, 1, 0, 0);
      gl.glRotated(rollAngle, 0, 1, 0);
      gl.glTranslated(-cameraPos.x, -cameraPos.y, -cameraPos.z);

      displayWholeScene(drawable, false);

      gl.glPopMatrix();
   }


   public void material(float r, float g, float b){

      float[] m = {r, g, b, 1};

      gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, m,0);
      //   gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 100.0f);
      gl.glMaterialfv(GL.GL_FRONT, GL2.GL_DIFFUSE, m, 0);
      //gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, m, 0);
      //gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, m, 0);
   }

   public void displayWholeScene(GLAutoDrawable drawable, boolean drawSnake){

      double w = (worldWidth)/10;
      double h = (worldHeight)/10;
         double d = worldDepth/10;

      for(double x = worldX; x < worldX+worldWidth; x+=w){
         for(double y = worldY; y < worldY+worldHeight; y+=h){

            gl.glBegin(GL2.GL_POLYGON);

            gl.glColor3f(0, 1, 0);
            material(0, .5f, 0);
            gl.glNormal3d(0, 0, 1);
            gl.glVertex3d(x, y, -(worldZ+worldDepth));
            gl.glVertex3d(x+w, y, -(worldZ+worldDepth));
            gl.glVertex3d(x+w, y+h, -(worldZ+worldDepth));
            gl.glVertex3d(x, y+h, -(worldZ+worldDepth));
            gl.glEnd();
         }
      }
      
         for(double z = worldZ; z < worldZ + worldDepth; z+=d){
            for(double y = worldY; y < worldY+worldHeight; y+=h){
                   gl.glBegin(GL2.GL_POLYGON);
                   gl.glColor3f(0, 0, 1);
                   material(0, 0, .5f);
                   gl.glNormal3d(-1, 0, 0);
                   gl.glVertex3d(worldX, y, -(z+d));
                   gl.glNormal3d(-1, 0, 0);
                   gl.glVertex3d(worldX, y, -(z));
                   gl.glNormal3d(-1, 0, 0);
                   gl.glVertex3d(worldX, y+h, -(z));
                   gl.glNormal3d(-1, 0, 0);
                   gl.glVertex3d(worldX, y+h, -(z+d));
     
                   gl.glEnd();
            }
         }


//      gl.glBegin(GL2.GL_POLYGON);
//      gl.glColor3f(0, 0, 1);
//      material(0, 0, 1);
//      gl.glNormal3d(-1, 0, 0);
//      gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ+worldDepth));
//      gl.glVertex3d(worldX, worldY+worldHeight, -(worldZ));
//      gl.glVertex3d(worldX, worldY, -(worldZ));
//      gl.glVertex3d(worldX, worldY, -(worldZ+worldDepth));
//      gl.glEnd();

   }

   public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
   }


   private static class Vector3D{
      private final double x;
      private final double y;
      private final double z;

      public Vector3D(double x, double y, double z){
         this.x = x;
         this.y = y;
         this.z = z;
      }

      public Vector3D add(Vector3D delta) {
         return new Vector3D(x+delta.x, y+delta.y, z+delta.z);
      }

      public String toString(){
         return x + ", " + y + ", " + z;
      }

   }

   public static void main(String[] args) {
      new CameraTest();
   }


   @Override
   public void dispose(GLAutoDrawable arg0)
   {
      // TODO Auto-generated method stub

   }
}

i’m almost sure the space is not right.

where does the projection/frustum matrix land ? GL_PROJECTION or GL_MODELVIEW ? should be gl_projection.

is the last active matrix gl_modelview ? (glMatrixMode) it should. glLight GL_POSITION is multiplied by the current matrix, which is assumed to be modelview. transformed into eye-space etc etc.

what is the light-position w-coordinate set to ? if it’s set to zero, light is treated as directional-light. not sure if that’s what you want.

o/

basil_ is right… I’m so silly, you should call glFrustum when the projection matrix is active and you should call glRotate when the model view matrix is active. reshape() should leave the model view matrix active.