|
This example shows how to create shadows with JOGL.
This is the Java port of the one of the NeHe OpenGL tutorials.
You can get complete IntelliJ IDEA project structure (all source, resources, build script, …) by downloading the source distribution from here.
The original post of the programmer who ported the examples can be found here.
package demos.nehe.lesson27;
/*--. .-"-.
/ o_O / O o \
\_ (__\ \_ v _/
// \\ // \\
(( )) (( ))
¤¤¤¤¤¤¤¤¤¤¤¤¤¤--""---""--¤¤¤¤--""---""--¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
¤ ||| ||| ¤
¤ | | ¤
¤ ¤
¤ Programmer:Abdul Bezrati ¤
¤ Program :Nehe's 27th lesson port to JOGL ¤
¤ Comments :None ¤
¤ _______ ¤
¤ /` _____ `\;,
This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
¤
¤ (__(^===^)__)';, ___ ¤
¤ / ::: \ ,; /^ ^\ ¤
¤ | ::: | ,;' ( Ö Ö ) ¤
¤¤¤'._______.'`¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ --°oOo--(_)--oOo°--¤¤*/
import demos.common.GLDisplay;
/**
* @author Abdul Bezrati
*/
public class Lesson27 {
public static void main(String[] args) {
GLDisplay neheGLDisplay = GLDisplay.createGLDisplay("Lesson 27: Shadows");
Renderer renderer = new Renderer();
InputHandler inputHandler = new InputHandler(renderer, neheGLDisplay);
neheGLDisplay.addGLEventListener(renderer);
neheGLDisplay.addKeyListener(inputHandler);
neheGLDisplay.start();
}
}
package demos.nehe.lesson27;
import demos.common.GLDisplay;
import javax.swing.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
class InputHandler extends KeyAdapter {
private Renderer renderer;
public InputHandler(Renderer renderer, GLDisplay glDisplay) {
this.renderer = renderer;
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
"Decrease X-axis rotation speed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
"Increase X-axis rotation speed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
"Decrease Y-axis rotation speed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
"Increase Y-axis rotation speed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_L, 0),
"Move light right");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_J, 0),
"Move light left");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_I, 0),
"Move light up");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_K, 0),
"Move light down");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_O, 0),
"Move light forward");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_U, 0),
"Move light backward");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_D, 0),
"Move ball right");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "Move ball left");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "Move ball up");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "Move ball down");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_E, 0), "Move ball forward");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), "Move ball backward");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD6, 0), "Move cross right");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD4, 0), "Move cross left");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD8, 0), "Move cross up");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD5, 0), "Move cross down");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD9, 0), "Move cross forward");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD7, 0), "Move cross backward");
}
public void keyPressed(KeyEvent e) {
processKeyEvent(e, true);
}
public void keyReleased(KeyEvent e) {
processKeyEvent(e, false);
}
private void processKeyEvent(KeyEvent e, boolean pressed) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
renderer.decreaseXspeed(pressed);
break;
case KeyEvent.VK_DOWN:
renderer.increaseXspeed(pressed);
break;
case KeyEvent.VK_RIGHT:
renderer.increaseYspeed(pressed);
break;
case KeyEvent.VK_LEFT:
renderer.decreaseYspeed(pressed);
break;
// Adjust Light's Position
case KeyEvent.VK_L:
renderer.translateLightRight(pressed); // 'L' Moves Light Right
break;
case KeyEvent.VK_J:
renderer.translateLightLeft(pressed); // 'J' Moves Light Left
break;
case KeyEvent.VK_I:
renderer.translateLightUp(pressed); // 'I' Moves Light Up
break;
case KeyEvent.VK_K:
renderer.translateLightDown(pressed); // 'K' Moves Light Down
break;
case KeyEvent.VK_O:
// 'O' Moves Light Toward Viewer
renderer.translateLightForward(pressed);
break;
case KeyEvent.VK_U:
// 'U' Moves Light Away From Viewer
renderer.translateLightBackward(pressed);
break;
// Adjust Object's Position
case KeyEvent.VK_NUMPAD6:
// 'Numpad6' Move Object Right
renderer.translateObjectRight(pressed);
break;
case KeyEvent.VK_NUMPAD4:
// 'Numpad4' Move Object Left
renderer.translateObjectLeft(pressed);
break;
case KeyEvent.VK_NUMPAD8:
renderer.translateObjectUp(pressed); // 'Numpad8' Move Object Up
break;
case KeyEvent.VK_NUMPAD5:
// 'Numpad5' Move Object Down
renderer.translateObjectDown(pressed);
break;
case KeyEvent.VK_NUMPAD9:
// 'Numpad9' Move Object Toward Viewer
renderer.translateObjectForward(pressed);
break;
case KeyEvent.VK_NUMPAD7:
// 'Numpad7' Move Object Away From Viewer
renderer.translateObjectBackward(pressed);
break;
// Adjust Ball's Position
case KeyEvent.VK_D:
renderer.translateSphereRight(pressed); // 'D' Move Ball Right
break;
case KeyEvent.VK_A:
renderer.translateSphereLeft(pressed); // 'A' Move Ball Left
break;
case KeyEvent.VK_W:
renderer.translateSphereUp(pressed); // 'W' Move Ball Up
break;
case KeyEvent.VK_S:
renderer.translateSphereDown(pressed); // 'S' Move Ball Down
break;
case KeyEvent.VK_E:
// 'E' Move Ball Toward Viewer
renderer.translateSphereForward(pressed);
break;
case KeyEvent.VK_Q:
// 'Q' Move Ball Away From Viewer
renderer.translateSphereBackward(pressed);
break;
}
}
}
package demos.nehe.lesson27;
import demos.common.ResourceRetriever;
import javax.media.opengl.GL;
import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
class Object3D {
private int nPlanes, nPoints;
private Point points[] = new Point[100];
private Plane planes[] = new Plane[100];
public Object3D() {
for (int i = 0; i < 100; i++) {
points[i] = new Point();
planes[i] = new Plane();
}
}
// load object
public static Object3D readObject(String st) throws IOException {
StringBuffer data = new StringBuffer();
InputStream inputStream = ResourceRetriever.getResourceAsStream(st);
int info;
while ((info = inputStream.read()) != -1)
data.append((char) info);
inputStream.close();
Object3D o = new Object3D();
//points
StringTokenizer tokenizer = new StringTokenizer(data.toString());
o.nPoints = Integer.parseInt(tokenizer.nextToken());
for (int i = 1; i <= o.nPoints; i++) {
o.points[i].x = Float.parseFloat(tokenizer.nextToken());
o.points[i].y = Float.parseFloat(tokenizer.nextToken());
o.points[i].z = Float.parseFloat(tokenizer.nextToken());
}
//planes
o.nPlanes = Integer.parseInt(tokenizer.nextToken());
for (int i = 0; i < o.nPlanes; i++) {
o.planes[i].p[0] = Integer.parseInt(tokenizer.nextToken());
o.planes[i].p[1] = Integer.parseInt(tokenizer.nextToken());
o.planes[i].p[2] = Integer.parseInt(tokenizer.nextToken());
o.planes[i].normals[0].x = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[0].y = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[0].z = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[1].x = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[1].y = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[1].z = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[2].x = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[2].y = Float.parseFloat(tokenizer.nextToken());
o.planes[i].normals[2].z = Float.parseFloat(tokenizer.nextToken());
}
o.setConnectivity(); // Set Face To Face Connectivity
o.calcPlanes();
return o;
}
// connectivity procedure - based on Gamasutra's article
// hard to explain here
public void setConnectivity() {
for (int i = 0; i < nPlanes - 1; i++)
for (int j = i + 1; j < nPlanes; j++)
for (int ki = 0; ki < 3; ki++)
if (planes[i].neigh[ki] == 0) {
for (int kj = 0; kj < 3; kj++) {
int p1i = ki;
int p1j = kj;
int p2i = (ki + 1) % 3;
int p2j = (kj + 1) % 3;
p1i = planes[i].p[p1i];
p2i = planes[i].p[p2i];
p1j = planes[j].p[p1j];
p2j = planes[j].p[p2j];
int P1i = ((p1i + p2i) - Math.abs(p1i - p2i)) / 2;
int P2i = ((p1i + p2i) + Math.abs(p1i - p2i)) / 2;
int P1j = ((p1j + p2j) - Math.abs(p1j - p2j)) / 2;
int P2j = ((p1j + p2j) + Math.abs(p1j - p2j)) / 2;
if ((P1i == P1j) && (P2i == P2j)) { //they are neighbours
planes[i].neigh[ki] = j + 1;
planes[j].neigh[kj] = i + 1;
}
}
}
}
private void calcPlanes() {
for (int i = 0; i < nPlanes; i++) // Loop Through All Object Planes
calcPlane(planes[i]); // Compute Plane Equations For All Faces
}
// function for computing a plane equation given 3 points
private void calcPlane(Plane plane) {
Point v[] = new Point[4];
for (int i = 0; i < 3; i++) {
v[i + 1] = new Point();
v[i + 1].x = points[plane.p[i]].x;
v[i + 1].y = points[plane.p[i]].y;
v[i + 1].z = points[plane.p[i]].z;
}
plane.PlaneEq.a = v[1].y * (v[2].z - v[3].z) + v[2].y * (v[3].z - v[1].z)
+ v[3].y * (v[1].z - v[2].z);
plane.PlaneEq.b = v[1].z * (v[2].x - v[3].x) + v[2].z * (v[3].x - v[1].x)
+ v[3].z * (v[1].x - v[2].x);
plane.PlaneEq.c = v[1].x * (v[2].y - v[3].y) + v[2].x * (v[3].y - v[1].y)
+ v[3].x * (v[1].y - v[2].y);
plane.PlaneEq.d = -(v[1].x * (v[2].y * v[3].z - v[3].y * v[2].z) +
v[2].x * (v[3].y * v[1].z - v[1].y * v[3].z) +
v[3].x * (v[1].y * v[2].z - v[2].y * v[1].z));
}
// procedure for drawing the object - very simple
public void draw(GL gl) {
gl.glBegin(GL.GL_TRIANGLES);
for (int i = 0; i < nPlanes; i++) {
for (int j = 0; j < 3; j++) {
gl.glNormal3f(planes[i].normals[j].x,
planes[i].normals[j].y,
planes[i].normals[j].z);
gl.glVertex3f(points[planes[i].p[j]].x,
points[planes[i].p[j]].y,
points[planes[i].p[j]].z);
}
}
gl.glEnd();
}
public void castShadow(GL gl, float[] lp) {
Point v1 = new Point();
Point v2 = new Point();
//set visual parameter
for (int i = 0; i < nPlanes; i++) {
// chech to see if light is in front or behind the plane (face plane)
float side = planes[i].PlaneEq.a * lp[0] +
planes[i].PlaneEq.b * lp[1] +
planes[i].PlaneEq.c * lp[2] +
planes[i].PlaneEq.d * lp[3];
if (side > 0)
planes[i].visible = true;
else
planes[i].visible = false;
}
gl.glDisable(GL.GL_LIGHTING);
gl.glDepthMask(false);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glEnable(GL.GL_STENCIL_TEST);
gl.glColorMask(false, false, false, false);
gl.glStencilFunc(GL.GL_ALWAYS, 1, 0xffffffff);
// first pass, stencil operation increases stencil value
gl.glFrontFace(GL.GL_CCW);
gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_INCR);
for (int i = 0; i < nPlanes; i++) {
if (planes[i].visible)
for (int j = 0; j < 3; j++) {
int k = planes[i].neigh[j];
if ((k == 0) || (!planes[k - 1].visible)) {
// here we have an edge, we must draw a polygon
int p1 = planes[i].p[j];
int jj = (j + 1) % 3;
int p2 = planes[i].p[jj];
//calculate the length of the vector
v1.x = (points[p1].x - lp[0]) * 100;
v1.y = (points[p1].y - lp[1]) * 100;
v1.z = (points[p1].z - lp[2]) * 100;
v2.x = (points[p2].x - lp[0]) * 100;
v2.y = (points[p2].y - lp[1]) * 100;
v2.z = (points[p2].z - lp[2]) * 100;
//draw the polygon
gl.glBegin(GL.GL_TRIANGLE_STRIP);
gl.glVertex3f(points[p1].x,
points[p1].y,
points[p1].z);
gl.glVertex3f(points[p1].x + v1.x,
points[p1].y + v1.y,
points[p1].z + v1.z);
gl.glVertex3f(points[p2].x,
points[p2].y,
points[p2].z);
gl.glVertex3f(points[p2].x + v2.x,
points[p2].y + v2.y,
points[p2].z + v2.z);
gl.glEnd();
}
}
}
// second pass, stencil operation decreases stencil value
gl.glFrontFace(GL.GL_CW);
gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_DECR);
for (int i = 0; i < nPlanes; i++) {
if (planes[i].visible)
for (int j = 0; j < 3; j++) {
int k = planes[i].neigh[j];
if ((k == 0) || (!planes[k - 1].visible)) {
// here we have an edge, we must draw a polygon
int p1 = planes[i].p[j];
int jj = (j + 1) % 3;
int p2 = planes[i].p[jj];
//calculate the length of the vector
v1.x = (points[p1].x - lp[0]) * 100;
v1.y = (points[p1].y - lp[1]) * 100;
v1.z = (points[p1].z - lp[2]) * 100;
v2.x = (points[p2].x - lp[0]) * 100;
v2.y = (points[p2].y - lp[1]) * 100;
v2.z = (points[p2].z - lp[2]) * 100;
//draw the polygon
gl.glBegin(GL.GL_TRIANGLE_STRIP);
gl.glVertex3f(points[p1].x,
points[p1].y,
points[p1].z);
gl.glVertex3f(points[p1].x + v1.x,
points[p1].y + v1.y,
points[p1].z + v1.z);
gl.glVertex3f(points[p2].x,
points[p2].y,
points[p2].z);
gl.glVertex3f(points[p2].x + v2.x,
points[p2].y + v2.y,
points[p2].z + v2.z);
gl.glEnd();
}
}
}
gl.glFrontFace(GL.GL_CCW);
gl.glColorMask(true, true, true, true);
//draw a shadowing rectangle covering the entire screen
gl.glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
gl.glStencilFunc(GL.GL_NOTEQUAL, 0, 0xffffffff);
gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_KEEP);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glBegin(GL.GL_TRIANGLE_STRIP);
gl.glVertex3f(-1f, 1f, -1f);
gl.glVertex3f(-1f, -1f, -1f);
gl.glVertex3f(1f, 1f, -1f);
gl.glVertex3f(1f, -1f, -1f);
gl.glEnd();
gl.glPopMatrix();
gl.glDisable(GL.GL_BLEND);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glDepthMask(true);
gl.glEnable(GL.GL_LIGHTING);
gl.glDisable(GL.GL_STENCIL_TEST);
gl.glShadeModel(GL.GL_SMOOTH);
}
// vertex in 3d-coordinate system
private static class Point {
float x, y, z;
}
// plane equation
private static class PlaneEq {
float a, b, c, d;
}
// structure describing an object's face
private static class Plane {
int p[] = new int[3],
neigh[] = new int[3];
Point normals[] = new Point[3];
boolean visible;
PlaneEq PlaneEq;
Plane() {
PlaneEq = new PlaneEq();
for (int i = 0; i < 3; i++)
normals[i] = new Point();
}
}
}
package demos.nehe.lesson27;
import javax.media.opengl.*;
import javax.media.opengl.glu.GLUquadric;
import javax.media.opengl.glu.GLU;
import java.io.IOException;
class Renderer implements GLEventListener {
private GLUquadric quadric;
private Object3D object3D;
private float[] LightPos = {0.0f, 5.0f, -4.0f, 1.0f}; // Light Position
private boolean LightUp, LightDown, LightLeft, LightRight,
LightForward, LightBackward;
private float[] LightAmb = {0.2f, 0.2f, 0.2f, 1.0f}; // Ambient Light Values
private float[] LightDif = {0.6f, 0.6f, 0.6f, 1.0f}; // Diffuse Light Values
private float[] LightSpc = {-0.2f, -0.2f, -0.2f, 1.0f}; // Specular Light Values
private float[] MatAmb = {0.4f, 0.4f, 0.4f, 1.0f}; // Material - Ambient Values
private float[] MatDif = {0.2f, 0.6f, 0.9f, 1.0f}; // Material - Diffuse Values
private float[] MatSpc = {0.0f, 0.0f, 0.0f, 1.0f}; // Material - Specular Values
private float[] MatShn = {0.0f}; // Material - Shininess
private float[] SpherePos = {-4.0f, -5.0f, -6.0f};
private boolean SphereUp, SphereDown, SphereLeft, SphereRight,
SphereForward, SphereBackward;
private float[] ObjPos = {-2.0f, -2.0f, -5.0f}; // Object Position
private boolean ObjUp, ObjDown, ObjLeft, ObjRight, ObjForward, ObjBackward;
private float xspeed; // X Rotation Speed
private boolean increaseXspeed;
private boolean decreaseXspeed;
private float yspeed; // Y Rotation Speed
private boolean increaseYspeed;
private boolean decreaseYspeed;
private float xrot; // X Rotation
private float yrot; // Y Rotation
private GLU glu = new GLU();
private boolean initGLObjects() throws IOException { // Initialize Objects
object3D = Object3D.readObject("demos/data/models/Object2.txt");
return object3D != null; // If Failed Return False
}
public void translateSphereUp(boolean state) {
SphereUp = state;
}
public void translateSphereDown(boolean state) {
SphereDown = state;
}
public void translateSphereLeft(boolean state) {
SphereLeft = state;
}
public void translateSphereRight(boolean state) {
SphereRight = state;
}
public void translateSphereForward(boolean state) {
SphereForward = state;
}
public void translateSphereBackward(boolean state) {
SphereBackward = state;
}
public void translateLightUp(boolean state) {
LightUp = state;
}
public void translateLightDown(boolean state) {
LightDown = state;
}
public void translateLightLeft(boolean state) {
LightLeft = state;
}
public void translateLightRight(boolean state) {
LightRight = state;
}
public void translateLightForward(boolean state) {
LightForward = state;
}
public void translateLightBackward(boolean state) {
LightBackward = state;
}
public void translateObjectUp(boolean state) {
ObjUp = state;
}
public void translateObjectDown(boolean state) {
ObjDown = state;
}
public void translateObjectLeft(boolean state) {
ObjLeft = state;
}
public void translateObjectRight(boolean state) {
ObjRight = state;
}
public void translateObjectForward(boolean state) {
ObjForward = state;
}
public void translateObjectBackward(boolean state) {
ObjBackward = state;
}
public void increaseXspeed(boolean increase) {
increaseXspeed = increase;
}
public void decreaseXspeed(boolean decrease) {
decreaseXspeed = decrease;
}
public void increaseYspeed(boolean increase) {
increaseYspeed = increase;
}
public void decreaseYspeed(boolean decrease) {
decreaseYspeed = decrease;
}
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
try {
initGLObjects();
} catch (IOException e) {
System.out.println("Couldn't load model");
throw new RuntimeException(e);
}
gl.glShadeModel(GL.GL_SMOOTH); // Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
gl.glClearDepth(1.0f); // Depth Buffer Setup
gl.glClearStencil(0); // Stencil Buffer Setup
gl.glEnable(GL.GL_DEPTH_TEST); // Enables Depth Testing
gl.glDepthFunc(GL.GL_LEQUAL); // The Type Of Depth Testing To Do
// Really Nice Perspective Calculations
gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, LightPos, 0); // Set Light1 Position
gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, LightAmb, 0); // Set Light1 Ambience
gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, LightDif, 0); // Set Light1 Diffuse
gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, LightSpc, 0); // Set Light1 Specular
gl.glEnable(GL.GL_LIGHT1); // Enable Light1
gl.glEnable(GL.GL_LIGHTING); // Enable Lighting
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, MatAmb, 0); // Set Material Ambience
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, MatDif, 0); // Set Material Diffuse
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, MatSpc, 0); // Set Material Specular
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, MatShn, 0);// Set Material Shininess
gl.glCullFace(GL.GL_BACK); // Set Culling Face To Back Face
gl.glEnable(GL.GL_CULL_FACE); // Enable Culling
gl.glClearColor(0.1f, 1.0f, 0.5f, 1.0f); // Set Clear Color (Greenish Color)
quadric = glu.gluNewQuadric(); // Initialize Quadratic
glu.gluQuadricNormals(quadric, GL.GL_SMOOTH); // Enable Smooth Normal Generation
glu.gluQuadricTexture(quadric, false); // Disable Auto Texture Coords
}
private void drawRoom(GL gl) { // Draw The Room (Box)
gl.glBegin(GL.GL_QUADS); // Begin Drawing Quads
// Floor
gl.glNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up
gl.glVertex3f(-10.0f, -10.0f, -20.0f); // Back Left
gl.glVertex3f(-10.0f, -10.0f, 20.0f); // Front Left
gl.glVertex3f(10.0f, -10.0f, 20.0f); // Front Right
gl.glVertex3f(10.0f, -10.0f, -20.0f); // Back Right
// Ceiling
gl.glNormal3f(0.0f, -1.0f, 0.0f); // Normal Point Down
gl.glVertex3f(-10.0f, 10.0f, 20.0f); // Front Left
gl.glVertex3f(-10.0f, 10.0f, -20.0f); // Back Left
gl.glVertex3f(10.0f, 10.0f, -20.0f); // Back Right
gl.glVertex3f(10.0f, 10.0f, 20.0f); // Front Right
// Front Wall
gl.glNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Away From Viewer
gl.glVertex3f(-10.0f, 10.0f, -20.0f); // Top Left
gl.glVertex3f(-10.0f, -10.0f, -20.0f); // Bottom Left
gl.glVertex3f(10.0f, -10.0f, -20.0f); // Bottom Right
gl.glVertex3f(10.0f, 10.0f, -20.0f); // Top Right
// Back Wall
gl.glNormal3f(0.0f, 0.0f, -1.0f); // Normal Pointing Towards Viewer
gl.glVertex3f(10.0f, 10.0f, 20.0f); // Top Right
gl.glVertex3f(10.0f, -10.0f, 20.0f); // Bottom Right
gl.glVertex3f(-10.0f, -10.0f, 20.0f); // Bottom Left
gl.glVertex3f(-10.0f, 10.0f, 20.0f); // Top Left
// Left Wall
gl.glNormal3f(1.0f, 0.0f, 0.0f); // Normal Pointing Right
gl.glVertex3f(-10.0f, 10.0f, 20.0f); // Top Front
gl.glVertex3f(-10.0f, -10.0f, 20.0f); // Bottom Front
gl.glVertex3f(-10.0f, -10.0f, -20.0f); // Bottom Back
gl.glVertex3f(-10.0f, 10.0f, -20.0f); // Top Back
// Right Wall
gl.glNormal3f(-1.0f, 0.0f, 0.0f); // Normal Pointing Left
gl.glVertex3f(10.0f, 10.0f, -20.0f); // Top Back
gl.glVertex3f(10.0f, -10.0f, -20.0f); // Bottom Back
gl.glVertex3f(10.0f, -10.0f, 20.0f); // Bottom Front
gl.glVertex3f(10.0f, 10.0f, 20.0f); // Top Front
gl.glEnd(); // Done Drawing Quads
}
private void update() {
if (increaseXspeed)
xspeed += 0.08f;
if (decreaseXspeed)
xspeed -= 0.08f;
if (increaseYspeed)
yspeed += 0.08f;
if (decreaseYspeed)
yspeed -= 0.08f;
translate(LightPos, LightUp, LightDown, LightLeft, LightRight,
LightForward, LightBackward);
translate(ObjPos, ObjUp, ObjDown, ObjLeft, ObjRight, ObjForward, ObjBackward);
translate(SpherePos, SphereUp, SphereDown, SphereLeft, SphereRight,
SphereForward, SphereBackward);
}
private void translate(float[] position, boolean up, boolean down, boolean left,
boolean right, boolean forward, boolean backward) {
float x = 0;
float y = 0;
float z = 0;
if (left)
x -= 0.05f;
if (right)
x += 0.05f;
if (up)
y += 0.05f;
if (down)
y -= 0.05f;
if (forward)
z += 0.05f;
if (backward)
z -= 0.05f;
position[0] += x;
position[1] += y;
position[2] += z;
}
public void display(GLAutoDrawable drawable) {
update();
GL gl = drawable.getGL();
// Clear Color Buffer, Depth Buffer, Stencil Buffer
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT |
GL.GL_STENCIL_BUFFER_BIT);
GLmatrix16f Minv = new GLmatrix16f();
GLvector4f wlp = new GLvector4f();
GLvector4f lp = new GLvector4f();
gl.glLoadIdentity(); // Reset Modelview Matrix
gl.glTranslatef(0.0f, 0.0f, -20.0f); // Zoom Into Screen 20 Units
gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, LightPos, 0); // Position Light1
gl.glTranslatef(SpherePos[0], SpherePos[1], SpherePos[2]); // Position The Sphere
glu.gluSphere(quadric, 1.5f, 32, 16); // Draw A Sphere
// calculate light's position relative to local coordinate system
// dunno if this is the best way to do it, but it actually works
// if u find another aproach, let me know ;)
// we build the inversed matrix by doing all the actions in reverse order
// and with reverse parameters (notice -xrot, -yrot, -ObjPos[], etc.)
gl.glLoadIdentity(); // Reset Matrix
gl.glRotatef(-yrot, 0.0f, 1.0f, 0.0f); // Rotate By -yrot On Y Axis
gl.glRotatef(-xrot, 1.0f, 0.0f, 0.0f); // Rotate By -xrot On X Axis
// Retrieve ModelView Matrix (Stores In Minv)
gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, Minv.e, 0);
lp.e[0] = LightPos[0]; // Store Light Position X In lp[0]
lp.e[1] = LightPos[1]; // Store Light Position Y In lp[1]
lp.e[2] = LightPos[2]; // Store Light Position Z In lp[2]
lp.e[3] = LightPos[3]; // Store Light Direction In lp[3]
VMatMult(Minv, lp); // We Store Rotated Light Vector In 'lp' Array
// Move Negative On All Axis Based On ObjPos[] Values (X, Y, Z)
gl.glTranslatef(-ObjPos[0], -ObjPos[1], -ObjPos[2]);
// Retrieve ModelView Matrix From Minv
gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, Minv.e, 0);
wlp.e[0] = 0.0f; // World Local Coord X To 0
wlp.e[1] = 0.0f; // World Local Coord Y To 0
wlp.e[2] = 0.0f; // World Local Coord Z To 0
wlp.e[3] = 1.0f;
// We Store The Position Of The World Origin Relative To The
VMatMult(Minv, wlp);
// Local Coord. System In 'wlp' Array
lp.e[0] += wlp.e[0]; // Adding These Two Gives Us The
lp.e[1] += wlp.e[1]; // Position Of The Light Relative To
lp.e[2] += wlp.e[2]; // The Local Coordinate System
gl.glColor4f(0.7f, 0.4f, 0.0f, 1.0f); // Set Color To An Orange
gl.glLoadIdentity(); // Reset Modelview Matrix
gl.glTranslatef(0.0f, 0.0f, -20.0f); // Zoom Into The Screen 20 Units
drawRoom(gl); // Draw The Room
gl.glTranslatef(ObjPos[0], ObjPos[1], ObjPos[2]); // Position The Object
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); // Spin It On The X Axis By xrot
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); // Spin It On The Y Axis By yrot
object3D.draw(gl); // Procedure For Drawing The Loaded Object
// Procedure For Casting The Shadow Based On The Silhouette
object3D.castShadow(gl, lp.e);
gl.glColor4f(0.7f, 0.4f, 0.0f, 1.0f); // Set Color To Purplish Blue
gl.glDisable(GL.GL_LIGHTING); // Disable Lighting
gl.glDepthMask(false); // Disable Depth Mask
gl.glTranslatef(lp.e[0], lp.e[1], lp.e[2]); // Translate To Light's Position
// Notice We're Still In Local Coordinate System
// Draw A Little Yellow Sphere (Represents Light)
glu.gluSphere(quadric, 0.2f, 16, 8);
gl.glEnable(GL.GL_LIGHTING); // Enable Lighting
gl.glDepthMask(true); // Enable Depth Mask
xrot += xspeed; // Increase xrot By xspeed
yrot += yspeed; // Increase yrot By yspeed
gl.glFlush(); // Flush The OpenGL Pipeline
}
public void reshape(GLAutoDrawable drawable,
int xstart,
int ystart,
int width,
int height) {
GL gl = drawable.getGL();
height = (height == 0) ? 1 : height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45, (float) width / height, 1, 1000);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged,
boolean deviceChanged) {
}
private static class GLvector4f {
float[] e = new float[4];
}; // Typedef's For VMatMult Procedure
private static class GLmatrix16f {
float[] e = new float[16];
}; // Typedef's For VMatMult Procedure
private static void VMatMult(GLmatrix16f M, GLvector4f v) {
float res[] = new float[4]; // Hold Calculated Results
res[0] = M.e[0] * v.e[0] + M.e[4] * v.e[1] + M.e[8] * v.e[2] + M.e[12] * v.e[3];
res[1] = M.e[1] * v.e[0] + M.e[5] * v.e[1] + M.e[9] * v.e[2] + M.e[13] * v.e[3];
res[2] = M.e[2] * v.e[0] + M.e[6] * v.e[1] + M.e[10] * v.e[2] + M.e[14] * v.e[3];
res[3] = M.e[3] * v.e[0] + M.e[7] * v.e[1] + M.e[11] * v.e[2] + M.e[15] * v.e[3];
v.e[0] = res[0]; // Results Are Stored Back In v[]
v.e[1] = res[1];
v.e[2] = res[2];
v.e[3] = res[3]; // Homogenous Coordinate
}
}
|
Related Tips
|
You can share your information about this topic using the form below!
Please do not post your questions with this form! Thanks.