Riven:
You often don’t want each vertex of a triangle to have to same normal.
Imagine rendering a sphere, or other curved shapes, it would look rather bad as the shade wouldn’t be smooth across the surface.
Aaah, of course. OK, I’m afraid I have another question. (And BTW, thank you so much for your help so far.) So I’m now trying to render a cube, and I’m setting the normals to point straight out of the faces. However, I’m now seeing that the top face of the cube, with a normal call of
glNormal3f(0.0f, 0.0f, 1.0f);
gets the most illumination, independent of what light position I supply using
glLight(GL_LIGHT1, GL_POSITION,(FloatBuffer)temp.asFloatBuffer().put(lightPosition).flip());
Complete code:
package com.zarkonnen.lwjgltest;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.*;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
public class Main {
public static final int DISPLAY_HEIGHT = 480;
public static final int DISPLAY_WIDTH = 640;
public static final Logger LOGGER = Logger.getLogger(Main.class.getName());
private float lightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; // Ambient Light Values ( NEW )
private float lightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Light Values ( NEW )
private float lightPosition[] = { 0.0f, 1.0f, 0.0f, 1.0f }; // Light Position ( NEW )
static {
try {
LOGGER.addHandler(new FileHandler("errors.log", true));
} catch (IOException ex) {
LOGGER.log(Level.WARNING, ex.toString(), ex);
}
}
public static void main(String[] args) {
Main main = null;
try {
main = new Main();
main.create();
main.run();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, ex.toString(), ex);
} finally {
if (main != null) {
main.destroy();
}
}
}
ArrayList<Box> boxes = new ArrayList<Box>();
public void create() throws LWJGLException, IOException {
//Display
Display.setDisplayMode(new DisplayMode(DISPLAY_WIDTH, DISPLAY_HEIGHT));
Display.setFullscreen(false);
Display.setTitle("Hello LWJGL World!");
Display.create();
//Keyboard
Keyboard.create();
//Mouse
Mouse.setGrabbed(false);
Mouse.create();
//OpenGL
initGL();
Texture tex = TextureLoader.getTexture("png", Main.class.getResourceAsStream("tex.png"));
boxes.add(new Box(0, 0, 0, 1, 1, 1, tex));
}
public void destroy() {
//Methods already check if created before destroying.
Mouse.destroy();
Keyboard.destroy();
Display.destroy();
}
public void initGL() {
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(
45.0f,
DISPLAY_WIDTH * 1.0f / DISPLAY_HEIGHT,
0.1f,
100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
// Really Nice Perspective Calculations
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
ByteBuffer temp = ByteBuffer.allocateDirect(16);
temp.order(ByteOrder.nativeOrder());
glLight(GL_LIGHT1, GL_AMBIENT, (FloatBuffer)temp.asFloatBuffer().put(lightAmbient).flip()); // Setup The Ambient Light
glLight(GL_LIGHT1, GL_DIFFUSE, (FloatBuffer)temp.asFloatBuffer().put(lightDiffuse).flip()); // Setup The Diffuse Light
glLight(GL_LIGHT1, GL_POSITION,(FloatBuffer)temp.asFloatBuffer().put(lightPosition).flip()); // Position The Light
glEnable(GL_LIGHT1); // Enable Light One
}
public void processKeyboard() {
if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) { cx += 0.03f; }
if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) { cx -= 0.03f; }
if (Keyboard.isKeyDown(Keyboard.KEY_UP)) { cy -= 0.03f; }
if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) { cy += 0.03f; }
}
public void processMouse() {
}
float cx, cy;
public Main() throws IOException {
}
static class Box {
float x, y, z, w, d, h;
Texture tex;
public Box(float x, float y, float z, float w, float d, float h, Texture tex) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
this.d = d;
this.h = h;
this.tex = tex;
}
}
public void render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
for (Box b : boxes) {
glLoadIdentity();
// Camera
glTranslatef(cx, cy, -8);
glTranslatef(b.x, b.y, b.z);
b.tex.bind();
glBegin(GL_QUADS);
// North face
glNormal3f(0.0f, -1.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(b.x, b.y + b.h, b.z); glTexCoord2f(b.tex.getWidth(), 0.0f); glVertex3f(b.x + b.w, b.y + b.h, b.z);
glTexCoord2f(b.tex.getWidth(), b.tex.getHeight()); glVertex3f(b.x + b.w, b.y + b.h, b.z + b.d);
glTexCoord2f(0.0f, b.tex.getHeight()); glVertex3f(b.x, b.y + b.h, b.z + b.d);
// East face
glNormal3f(1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(b.x + b.w, b.y, b.z); glTexCoord2f(b.tex.getWidth(), 0.0f); glVertex3f(b.x + b.w, b.y, b.z + b.d);
glTexCoord2f(b.tex.getWidth(), b.tex.getHeight()); glVertex3f(b.x + b.w, b.y + b.h, b.z + b.d);
glTexCoord2f(0.0f, b.tex.getHeight()); glVertex3f(b.x + b.w, b.y + b.h, b.z);
// West face
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(b.x, b.y, b.z); glTexCoord2f(b.tex.getWidth(), 0.0f); glVertex3f(b.x, b.y + b.h, b.z);
glTexCoord2f(b.tex.getWidth(), b.tex.getHeight()); glVertex3f(b.x, b.y + b.h, b.z + b.d);
glTexCoord2f(0.0f, b.tex.getHeight()); glVertex3f(b.x, b.y, b.z + b.d);
// South face
glNormal3f(0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(b.x, b.y, b.z); glTexCoord2f(b.tex.getWidth(), 0.0f); glVertex3f(b.x, b.y, b.z + b.d);
glTexCoord2f(b.tex.getWidth(), b.tex.getHeight()); glVertex3f(b.x + b.w, b.y, b.z + b.d);
glTexCoord2f(0.0f, b.tex.getHeight()); glVertex3f(b.x + b.w, b.y, b.z);
// Top face
glNormal3f(0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(b.x, b.y, b.z + b.d); glTexCoord2f(b.tex.getWidth(), 0.0f); glVertex3f(b.x, b.y + b.h, b.z + b.d);
glTexCoord2f(b.tex.getWidth(), b.tex.getHeight()); glVertex3f(b.x + b.w, b.y + b.h, b.z + b.d);
glTexCoord2f(0.0f, b.tex.getHeight()); glVertex3f(b.x + b.w, b.y, b.z + b.d);
glEnd();
}
}
public void run() {
while (!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
if (Display.isVisible()) {
processKeyboard();
processMouse();
update();
render();
} else {
if (Display.isDirty()) {
render();
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
Display.update();
Display.sync(60);
}
}
public void update() {
}
}