/**
* @(#) simpleshadow.java
* @(#) author: Øyvind Liland (HIØ 2002)
*/
/**
* How to control triangle and light:
*
* Arrow up: Rotate triangle around x-axis in negative z-direction
* Arrow down: Rotate triangle around x-axis in positive z-direction
* Arrow left: Rotate triangle around z-axis in negative x-direction
* Arrow right: Rotate triangle around z-axis in positive x-direction
* D or d key: Move triangle down
* U or u key: Move triangle up
* L or l key: Move triangle left
* R or r key: Move triangle right
* A or a key: Move triangle away (negative z-axis)
* T or t key: Move triangle towards (positive z-axis)
* F1: Move light left (negative x-axis)
* F2: Move light right (positive x-axis)
* F3: Move light away (negative z-axis)
* F4: Move light towards (positive z-axis)
*/
/**
*This code is mostly commented in norwegian
*/
//Imports
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.lang.*;
import java.util.*;
import java.io.*;
import gl4java.GLContext;
import gl4java.awt.GLCanvas;
import gl4java.utils.glut.*;
import gl4java.utils.textures.*;
public class simpleshadow extends JFrame {
JPanel panel;
JLabel light;
myGLCanvas canvas = null;
//Windows events
WindowHandler wHandler;
KeyHandler kHandler;
//Degrees the triangle should rotate for each key-press
private double step_rot = 0.0;
//Boolean variables to determine whether to rotate round x-axis or z-axis
private boolean rotate_x = false;
private boolean rotate_z = false;
//final int som brukes for å avgjøre hvilken akse det skal transeleres på
//i canvas.translate(int axis,double step)
private final int axis_x = 0;
private final int axis_y = 1;
private final int axis_z = 2;
//Step on y-axis, x-axis or z-axis
private double step_trans = 0.0;
//Lightposition on x-axis and y-axis
private float light_x = 1.0f;
private float light_y = 2.0f;
//Sjekker om trekanten befinner seg i "lovlig" område
private boolean triangleIsInside = true;
//Constructor
public simpleshadow () {
panel = (JPanel) this.getContentPane();
panel.setLayout(new BorderLayout());
this.setSize(new Dimension(600,600));
this.setTitle("Simple Shadow");
light = new JLabel("Positional light at: ");
panel.add("North",light);
//gl4java initiering
Dimension d = getSize();
canvas = new myGLCanvas(d.width, d.height);
panel.add("Center", canvas);
wHandler = new WindowHandler();
kHandler = new KeyHandler();
this.addWindowListener(wHandler);
this.addKeyListener(kHandler);
pack();
show();
}
//Main method
public static void main(String[]args){
new simpleshadow();
}
//---------------------------------------------------------
//Inner class for window events, interface WindowListener
class WindowHandler implements WindowListener {
public void windowOpened(WindowEvent e){}
public void windowClosing(WindowEvent e){
System.exit(0);
}
public void windowClosed(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
}
//-------------------------------------------------------------------
//Inner class for key events, interface KeyListener
class KeyHandler implements KeyListener {
public void keyPressed(KeyEvent e){
switch (e.getKeyCode())
{
//Roterer trekant mot venstre
case KeyEvent.VK_LEFT:
rotate_x = false;
rotate_z = true;
step_rot = -2.0;
canvas.rotate(step_rot);
//Metode som sjekker at alle punktene i trekanten befinner
//seg innenfor "lovlig" område. Trekanten kan ikke gå gjennom
//gulv eller vegger.
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.rotate(-step_rot);
break;
//Roterer trekant mot høyre
case KeyEvent.VK_RIGHT:
rotate_x = false;
rotate_z = true;
step_rot = 2.0;
canvas.rotate(step_rot);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.rotate(-step_rot);
break;
//Roterer trekant "inn i skjerm"
case KeyEvent.VK_UP:
rotate_x = true;
rotate_z = false;
step_rot = -2.0;
canvas.rotate(step_rot);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.rotate(-step_rot);
break;
//Roterer trekant "ut av skjerm"
case KeyEvent.VK_DOWN:
rotate_x = true;
rotate_z = false;
step_rot = 2.0;
canvas.rotate(step_rot);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.rotate(-step_rot);
break;
//Flytter lyskilden mot høyre (positiv x)
case KeyEvent.VK_F1:
light_x += 0.25;
canvas.light_position[0] = light_x;
canvas.repaint();
break;
//Flytter lyskilden mot venstre (negativ x)
case KeyEvent.VK_F2:
light_x -= 0.25;
canvas.light_position[0] = light_x;
canvas.repaint();
break;
//Flytter lyskilden ned (negativ y)
case KeyEvent.VK_F3:
light_y -= 0.25;
canvas.light_position[1] = light_y;
canvas.repaint();
break;
//Flytter lyskilden opp (positiv y)
case KeyEvent.VK_F4:
light_y += 0.25;
canvas.light_position[1] = light_y;
canvas.repaint();
break;
}
switch ((char)e.getKeyChar())
{
//Beveger trekanten nedover (negativ y)
case 'D':
case 'd':
step_trans = -0.025;
canvas.translate(axis_y,step_trans);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.translate(axis_y,-step_trans);
break;
//Beveger trekanten oppover (positiv y)
case 'U':
case 'u':
step_trans = 0.025;
canvas.translate(axis_y,step_trans);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.translate(axis_y,-step_trans);
break;
//Beveger trekanten mot skjerm (positiv z)
case 'T':
case 't':
step_trans = 0.025;
canvas.translate(axis_z,step_trans);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.translate(axis_z,-step_trans);
break;
//Beveger trekanten "inn i" skjerm (negativ z)
case 'A':
case 'a':
step_trans = -0.025;
canvas.translate(axis_z,step_trans);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.translate(axis_z,-step_trans);
break;
//Beveger trekant mot venstre (negativ x)
case 'L':
case 'l':
step_trans = -0.025;
canvas.translate(axis_x,step_trans);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.translate(axis_x,-step_trans);
break;
//Beveger trekant mot høyre (positiv x)
case 'R':
case 'r':
step_trans = 0.025;
canvas.translate(axis_x,step_trans);
if (canvas.isInside(canvas.triangle))
canvas.repaint();
else
canvas.translate(axis_x,-step_trans);
break;
}
}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){}
}
//-----------------------------------------------------------------------
//Inner class myGLCanvas
private class myGLCanvas extends GLCanvas {
GLUTFunc glut = null;
//Global variabel for bruk i posisjonering av lys og utregning av projeksjon
//for skyggekasting
float light_position[] = { light_x, light_y, 2.0f, 0.0f };
//Setter koordinatene for gulv og vegger.
float floor[][] =
{
{-2.0f,-0.5f,-3.0f},
{-2.0f,-0.5f,4.0f},
{2.0f,-0.5f,4.0f},
{2.0f,-0.5f,-3.0f}
};
float back_wall[][] =
{
{-2.0f, -0.5f, -3.0f},
{-2.0f, 2.5f, -3.0f},
{2.0f, 2.5f, -3.0f},
{2.0f, -0.5f,-3.0f}
};
float left_wall[][] =
{
{-2.0f,-0.5f,4.0f},
{-2.0f,2.5f,4.0f},
{-2.0f,2.5f,-3.0f},
{-2.0f,-0.5f,-3.0f}
};
float right_wall[][] =
{
{2.0f,-0.5f,4.0f},
{2.0f,2.5f,4.0f},
{2.0f,2.5f,-3.0f},
{2.0f,-0.5f,-3.0f}
};
//Normalene til gulv og vegger
float normals[][] =
{
{1.0f,0.0f,0.0f}, //Left wall
{-1.0f,0.0f,0.0f}, //Right wall
{0.0f,0.0f,1.0f}, //Back wall
{0.0f,1.0f,0.0f} //Floor
};
//Koordinater for trekanten som skal projisere skygge
float triangle[][] =
{
{-1.0f,0.0f,1.0f},
{1.0f,0.0f,1.0f},
{0.0f,0.0f,-1.0f}
};
//Storage for one texture
int texture[] = new int[1];
//Name on the file to be loaded as a texture
String fileName = "data/marblefloor.png";
//Constructor
public myGLCanvas(int w, int h) {
super(w, h);
}
//Kalles før myGLCanvas blir skapt
public void preInit() {
doubleBuffer = true;
stereoView = false;
accumSize = 8;
}
//Kalles når programmet starter og tar seg av engans initiering.
//Typisk lyssetting, glattemodus, bakgrunnsfarge
public void init() {
reshape (getSize().width, getSize().height);
glut = new GLUTFuncLightImpl(gl,glu);
//Turns on light in the scene
setLigth();
//Laster tekstur for bruk på gulv
loadTexture();
// Enables Clearing Of The Depth Buffer
gl.glClearDepth(1.0);
// Enables Depth Testing
gl.glEnable(GL_DEPTH_TEST);
// Normalize
gl.glEnable(GL_NORMALIZE);
//Clear the background color to black
gl.glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
//Smooth
gl.glShadeModel (GL_SMOOTH);
}
//Textureloader. Legger teksturer inn i array texture for senere bruk
public void loadTexture(){
TextureLoader texLoader = new PngTextureLoader(gl,glu);
texLoader.readTexture(fileName);
if (texLoader.isOk()) {
gl.glGenTextures(1,texture);
gl.glBindTexture(GL_TEXTURE_2D,texture[0]);
gl.glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl.glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl.glTexImage2D(GL_TEXTURE_2D, 0, 3, texLoader.getImageWidth(),
texLoader.getImageHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, texLoader.getTexture());
}
}
//Metode for å sette lyset i scenen
public void setLigth() {
float light_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
float light_diffuse[] = { 0.2f, 0.2f, 0.2f, 1.0f };
gl.glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
gl.glLightfv(GL_LIGHT0, GL_POSITION, light_position);
gl.glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
gl.glEnable(GL_LIGHTING);
gl.glEnable(GL_LIGHT0);
}
//Metode for å sette materialegenskaper til de forskjellige objektene i scenen
public void setMaterial(int choice) {
if (choice == 1) {
//Blå (Vegger)
float mat_ambient[] = { 0.1f, 0.1f, 0.6f, 1.0f };
float mat_diffuse[] = { 0.2f, 0.2f, 1.0f, 1.0f };
float shininess[] = {0.0f};
//Setter material properties
gl.glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
gl.glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
}else if (choice == 2) {
//Rød (Trekant)
float mat_ambient[] = { 0.5f, 0.0f, 0.0f, 1.0f };
float mat_diffuse[] = { 0.8f, 0.0f, 0.0f, 1.0f };
float shininess[] = {100.0f};
//Setter material properties
gl.glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
gl.glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
}else if (choice == 3) {
//Sort/grå (Skygge)
float mat_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
float mat_diffuse[] = { 0.0f, 0.0f, 0.0f, 1.0f };
float shininess[] = {0.0f};
//Setter material properties
gl.glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
gl.glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
}else{
//Hvit (Default)
float mat_ambient[] = { 1.0f, 1.0f, 1.0f, 1.0f };
float mat_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
float shininess[] = {0.0f};
//Setter material properties
gl.glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
gl.glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
}
}
//Kalles før myGLCanvas blir skapt
public void display() {
if (glj.gljMakeCurrent() == false)
return;
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.glClear(GL_ACCUM_BUFFER_BIT);
gl.glLoadIdentity();
glu.gluLookAt(0.0f,2.0f,7.0f,// eye
0.0f,0.0f,0.0f, // looking at
0.0f,1.0f,0.0f);// is up
//Gir informasjon om hvor lyset befinner seg og vises i label øverst i JFrame.
light.setText("Positional light at: (" + light_position[0] + ", " +
light_position[1] + ", " + light_position[2] + ")");
//Moves the light
gl.glPushMatrix();
gl.glLightfv(GL_LIGHT0,GL_POSITION,light_position);
gl.glPushMatrix();
gl.glPushMatrix();
//Må tegne gulv og vegger med polygon offset for å forhindre "stiching" når
//skyggene tegnes på planene
gl.glEnable(GL_POLYGON_OFFSET_FILL);
gl.glPolygonOffset(1.0f,1.0f);
drawWall(right_wall, normals[1]);
drawWall(left_wall, normals[0]);
drawWall(back_wall, normals[2]);
drawFloor(floor, normals[3]);
gl.glDisable(GL_POLYGON_OFFSET_FILL);
gl.glPopMatrix();
//Vil "blande" skygge med bakgrunn. Dette gjelder bare for skyggen
gl.glEnable(GL_BLEND);
gl.glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
//Tegner skyggen på gulvet med PolygonOffset disablet
gl.glPushMatrix();
drawShadow(triangle,right_wall);
drawShadow(triangle,left_wall);
drawShadow(triangle,back_wall);
drawShadow(triangle,floor);
gl.glPopMatrix();
//Skur av blending
gl.glDisable(GL_BLEND);
//Tegner så triangelet
gl.glPushMatrix();
drawTriangle();
gl.glPopMatrix();
glj.gljSwap();
glj.gljFree();
}
//Metoden tegner ut skyggen. Tar et object (trekanten) og et plan (gulv og vegger) som argument
public void drawShadow(float object[][],float plane[][]) {
//Regner ut gulvets normal ved hjelp av tre kjente punkter i planet
float normal[] = calculateNormal(plane[0],plane[1],plane[3]);
//Finner koordinatene til projeksjonene
float p1[] = calculateProjection(plane[0], object[0], normal, light_position);
float p2[] = calculateProjection(plane[0], object[1], normal, light_position);
float p3[] = calculateProjection(plane[0], object[2], normal, light_position);
//Sort
setMaterial(3);
//Tegner skyggen (projeksjonen)
gl.glBegin(GL_POLYGON);
gl.glNormal3f(normal[0],normal[1],normal[2]);
gl.glVertex3f(p1[0],p1[1],p1[2]);
gl.glVertex3f(p2[0],p2[1],p2[2]);
gl.glVertex3f(p3[0],p3[1],p3[2]);
gl.glEnd();
}
//Metode for å tegne gulvet
public void drawFloor(float coo[][],float normal[]){
//Array som inneholder hjørnene til texturen. Hjørnene skal mappes slik at
//de ligger på korensponderende hjørner på gulvet
float corner[][] =
{
{0.0f,1.0f},//Top-left corner
{0.0f,0.0f},//Bottom-left corner
{1.0f,0.0f},//Bottom-right corner
{1.0f,1.0f}//Top-right corner
};
//Aktiviserer tekstur og henter denne fra texture-array.
gl.glEnable(GL_TEXTURE_2D);
gl.glBindTexture(GL_TEXTURE_2D, texture[0]);
//Tekstur skal overskygge alle materialegenskaper som gulvet eventuelt må ha
gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
gl.glBegin(GL_QUADS);
//Setter normalen (Peker opp langs positiv y)
gl.glNormal3f(normal[0],normal[1],normal[2]);
for (int i = 0; i < coo.length; i++) {
//Binder tekstur til gulvet og tegner
gl.glTexCoord2f(corner[i][0],corner[i][1]);
gl.glVertex3f(coo[i][0],coo[i][1],coo[i][2]);
}
gl.glEnd();
//Skrur av teksture slik at ingen andre objekter i scenen skal bli tegnet med tekstur
gl.glDisable(GL_TEXTURE_2D);
}
//Metode for å tegne vegger. Tar en array av hjørnekoordinater og planets normal som argument
public void drawWall(float coo[][], float normal[]){
//Blå
setMaterial(1);
gl.glBegin(GL_QUADS);
//Setter normal
gl.glNormal3f(normal[0],normal[1],normal[2]);
for (int i = 0; i < coo.length; i++) {
//Tegner vegg
gl.glVertex3f(coo[i][0],coo[i][1],coo[i][2]);
}
gl.glEnd();
}
//Metode for å tegne trekant
public void drawTriangle() {
//Rød
setMaterial(2);
gl.glBegin(GL_POLYGON);
//Tegner trekant
for (int i = 0; i < triangle.length; i++)
gl.glVertex3f(triangle[i][0],triangle[i][1],triangle[i][2]);
gl.glEnd();
}
//Metode for å sjekke om et objekt (trekanten) ligger innenfor begrenset område
public boolean isInside(float object[][]){
//Offset slik at ikke trekanten skal gå helt inn i planet, denne er den samme som
//step_trans, men setter den også her.
float off = 0.025f;
float x_min = -2.0f + off;
float x_max = 2.0f - off;
float y_min = -0.5f + off;
float y_max = 3.0f - off;
float z_min = -3.0f + off;
float z_max = 4.0f - off;
//Bruker en variabel check for å avgjøre om alle koordinatene i alle punktene
//(3 punkter for triangel) ligger innenfor det "lovlige" definerte området.
//Hvis ALLE koordinatene for hvert punkt i object-arrayen oppfyller kravet
//vil check økes med èn.
int check = 0;
for (int i = 0; i < object.length; i ++) {
if ((x_min <= object[i][0]) && (object[i][0] <= x_max) &&
(y_min <= object[i][1]) && (object[i][1] <= y_max) &&
(z_min <= object[i][2]) && (object[i][2] <= z_max))
check++;
}
//Hvis alle koordinatene i object-arrayen ligger innefor "lovlig" område vil
//check = 3 (altså antall punkter som oppfyller kravene) og metoden kan returnere true
if (check == 3)
return true;
return false;
}
//Metode for å rotere
public void rotate(double rot){
//Må translere alle punktene i trekanten tilbake til utgangspunkt for å få ønsket rotasjon.
//Det vil si at trekanten IKKE skal rotere om origo den "globale" origo, men den "lokale". Dette
//gjør at vi får en lik rotasjon uansett hvor i det "globale" koordinatsystemet trekanten befinner
//seg.
//Tar vare på alle y-koordinatene i temporær array
float tmp_y[] = new float[3];
float tmp_x[] = new float[3];
float tmp_z[] = new float[3];
for (int k = 0; k < 3; k++){
tmp_y[k] = triangle[k][1];
tmp_x[k] = triangle[k][0];
tmp_z[k] = triangle[k][2];
//Uansett hvor trekanten befinner seg skal den flyttes tilbake til utgangspunkt
translate(axis_y, -(double)tmp_y[k]);
translate(axis_x, -(double)tmp_x[k]);
translate(axis_z, -(double)tmp_z[k]);
}
//Vi kan nå rotere trekanten
if (rotate_x) {
//Trekantens koordinater multiplisert med rotasjonsmatrisen for rotasjon om x-aksen
for (int j = 0; j < 3; j++){
float x = triangle[j][0];
float y = (triangle[j][1] * (float)Math.cos(Math.toRadians(rot))) - (triangle[j][2] *
(float)Math.sin(Math.toRadians(rot)));
float z = ((float)Math.sin(Math.toRadians(rot) * triangle[j][1])) + (triangle[j][2] *
(float)Math.cos(Math.toRadians(rot)));
triangle[j][0] = x;
triangle[j][1] = y;
triangle[j][2] = z;
}
}else if (rotate_z) {
//Trekantens koordinater multiplisert med rotasjonsmatrisen for rotasjon om z-aksen
for (int j = 0; j < 3; j++){
float x = (triangle[j][0] * (float)Math.cos(Math.toRadians(rot))) + (triangle[j][1] *
(float)Math.sin(Math.toRadians(rot)));
float y = -((float)Math.sin(Math.toRadians(rot) * triangle[j][0])) + (triangle[j][1] *
(float)Math.cos(Math.toRadians(rot)));
float z = triangle[j][2];
triangle[j][0] = x;
triangle[j][1] = y;
triangle[j][2] = z;
}
}else{
System.err.println("Error in method: void rotate()");
System.exit(-1);
}
//Når rotasjonen er utført kan vi translere trekanten tilbake igjen hvor den befant seg før
//rotasjon.
for (int k = 0; k < 3; k++){
translate(axis_y, (double)tmp_y[k]);
translate(axis_x, (double)tmp_x[k]);
translate(axis_z, (double)tmp_z[k]);
}
}
//Metode for å transelere et objekt (trekanten)
public void translate(int axis, double step) {
for (int i = 0; i < 3; i++){
float tmp = triangle[i][axis] + (float)step;
triangle[i][axis] = tmp;
}
}
//Finner normalen til et plan basert på tre kjente punkter i planet
public float [] calculateNormal(float p1[], float p2[], float p3[]) {
float normal[] = new float[3];
//Calculate the normal vector for the plane
//Gitt to vektorer (tre punkter) i planet kan normalen regnes ut
normal[0] = (((p2[1]-p1[1])*(p3[2]-p1[2]))-((p2[2]-p1[2])*(p3[1]-p1[1])));
normal[1] = (((p2[2]-p1[2])*(p3[0]-p1[0]))-((p2[0]-p1[0])*(p3[2]-p1[2])));
normal[2] = (((p2[0]-p1[0])*(p3[1]-p1[1]))-((p2[1]-p1[1])*(p3[0]-p1[0])));
return normal;
}
//Metode som regner ut parameter t ut fra et gitt punkt på en gitt flate og med retningsvektor
//lik lysets retning. r er et gitt punkt i planet, p er punktet som skal projiseres, n er planets
//normal og a er lysets retningsvektor.
public float[] calculateProjection(float r[], float p[], float n[], float a[]){
float projection [] = new float[3];
/*TEORI:
En linje L gjennom et punkt p = (p1,p2,p3) og med samme retning som a = [a1,a2,a3] er samlingen
av alle punkter x på formen: x = p + t*a. Dette gir oss for x1,x2 og x3:
(1)
x1 = p1 + t*a1
x2 = p2 + t*a2
x3 = p3 + t*a3
Likning for et plan er gitt ved:
(2)
n1*r1 + n2*r2 + n3*r3 + d = 0
hvor planets normal n = [n1,n2,n3] og et vilkårlig punkt i planet r = (r1,r2,r3).
For å finne punktet på linje L som ligger i planet har vi sammenhengen:
(3)
n1(p1 + t*a1) + n2(p2 + t*a2) + n3(p3 + t*a3) = n1*r1 + n2*r2 + n3*r3
Vi finner t:
(4)
n1*p1 + n1*t*a1 + n2*p2 + n2*t*a2 + n3*p3 + n3*t*a3 = n1*r1 + n2*r2 + n3*r3
n1*t*a1 + n2*t*a2 + n3*t*a3 = n1*r1 + n2*r2 + n3*r3 - n1*p1 - n2*p2 - n3*p3
t(n1*a1 + n2*a2 + n3*a3) = n1(r1 - p1) + n2(r2 - p2) + n3(r3 - p3)
t = (n1(r1 - p1) + n2(r2 - p2) + n3(r3 - p3))/(n1*a1 + n2*a2 + n3*a3)
Vi kan nå sette inn t i likningsettet (1) for å finne x1,x2 og x3. Dette er altså koordinatene
for et punkt i planet på rett linje L som gjennomløper punktet p (objektet som skal kaste skygge)
og som har en retningsvektor a (lysets retning)
*/
//Regner ut t
float t =
(n[0]*(r[0] - p[0]) + n[1]*(r[1] - p[1]) + n[2]*(r[2] - p[2]))/
(n[0]*a[0] + n[1]*a[1] + n[2]*a[2]);
//Setter t inn i likningsettet (1)
float x1 = p[0] + (t * a[0]);
float x2 = p[1] + (t * a[1]);
float x3 = p[2] + (t * a[2]);
projection[0] = x1;
projection[1] = x2;
projection[2] = x3;
return projection;
}
//Kalles når vindu reskaleres
public void reshape(int w, int h){
gl.glViewport(0,0,w,h);
gl.glMatrixMode(GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(35.0, (float) w/h, 1.0, 500.0);
gl.glMatrixMode(GL_MODELVIEW);
}
}
}