Scene Node Example , a walk through example
Main class WalkThrough
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLJPanel;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;
import jscene3D.Camera3D;
import jscene3D.CubeGeo;
import jscene3D.ObjectContainer3D;
import jscene3D.Primitive;
import jscene3D.UVConeGeo;
import jscene3D.UVCylinderGeo;
import jscene3D.UVSphereGeo;
public class WalkThroughPanel extends JPanel {
private GLJPanel drawable;
private JLabel msg;
private ObjectContainer3D theWorld;
private Camera3D viewer;
private ObjectContainer3D cameraBox;
public WalkThroughPanel(){
GLEventListener glListener=new GLEventListener(){
public void init(GLAutoDrawable drawable){
GL2 gl=drawable.getGL().getGL2();
gl.glClearColor(0,0,0.3f,1);
gl.glEnable(GL2.GL_LIGHTING);
gl.glEnable(GL2.GL_LIGHT0);
gl.glEnable(GL2.GL_DEPTH_TEST);
gl.glEnable(GL2.GL_COLOR_MATERIAL);
gl.glEnable(GL2.GL_NORMALIZE);
gl.glShadeModel(GL2.GL_SMOOTH);
}
public void display(GLAutoDrawable drawable){
GL2 gl=drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT|GL2.GL_DEPTH_BUFFER_BIT);
viewer.apply(gl);
theWorld.draw(gl);
}
public void reshape(GLAutoDrawable drawable,int x,int y,int width,int height){
}
public void dispose(GLAutoDrawable drawable){
}
};
MouseInputAdapter ma=new MouseInputAdapter(){
public void mousePressed(MouseEvent e){
requestFocus();
}
};
FocusListener fl=new FocusListener(){
public void focusLost(FocusEvent e){
setBorder(BorderFactory.createLineBorder(Color.GRAY, 4));
msg.setText("click to get focus");
}
public void focusGained(FocusEvent e){
setBorder(BorderFactory.createLineBorder(Color.CYAN, 4));
msg.setText("arrow keys=move; r=reset world; home=reset view");
}
};
KeyAdapter ka=new KeyAdapter(){
// public void keyPressed(KeyEvent e){
//
// int code=e.getKeyCode();
// float angle=viewer.getRotation()[0];
// float x;
// float z;
// float dx;
// float dz;
//
// switch(code){
// case KeyEvent.VK_UP:
// dx=viewer.getPosition()[0];
// dz=viewer.getPosition()[2];
// x=(float)(0.2*Math.sin(angle*Math.PI/180));
// z=(float)(0.2*Math.cos(angle*Math.PI/180));
// viewer.setPosition((float)(dx-x), 0, (float)(dz-z));
// break;
//
// case KeyEvent.VK_DOWN:
// dx=viewer.getPosition()[0];
// dz=viewer.getPosition()[2];
// x=(float)(0.2*Math.sin(angle*Math.PI/180));
// z=(float)(0.2*Math.cos(angle*Math.PI/180));
// viewer.setPosition((float)(dx+x), 0, (float)(dz+z));
// break;
//
// case KeyEvent.VK_LEFT:
// angle=viewer.getRotation()[0];
// viewer.setRotation(angle+1, 0, 1, 0);
// break;
//
// case KeyEvent.VK_RIGHT:
// angle=viewer.getRotation()[0];
// viewer.setRotation(angle-1, 0, 1, 0);
// break;
//
// case KeyEvent.VK_HOME:
// viewer.setPosition(0, 0, 0);
// break;
//
// case KeyEvent.VK_R:
// buildWorld();
// viewer.setPosition(0, 0, 0);
// }
//
// drawable.repaint();
//
//
//
// }
public void keyPressed(KeyEvent e){
int code=e.getKeyCode();
float angle=cameraBox.getRotation()[0];
float x;
float z;
float dx;
float dz;
switch(code){
case KeyEvent.VK_UP:
dx=cameraBox.getPosition()[0];
dz=cameraBox.getPosition()[2];
x=(float)(0.2*Math.sin(angle*Math.PI/180));
z=(float)(0.2*Math.cos(angle*Math.PI/180));
cameraBox.setPosition((float)(dx-x), 0, (float)(dz-z));
break;
case KeyEvent.VK_DOWN:
dx=cameraBox.getPosition()[0];
dz=cameraBox.getPosition()[2];
x=(float)(0.2*Math.sin(angle*Math.PI/180));
z=(float)(0.2*Math.cos(angle*Math.PI/180));
cameraBox.setPosition((float)(dx+x), 0, (float)(dz+z));
break;
case KeyEvent.VK_LEFT:
angle=cameraBox.getRotation()[0];
cameraBox.setRotation(angle+1, 0, 1, 0);
break;
case KeyEvent.VK_RIGHT:
angle=cameraBox.getRotation()[0];
cameraBox.setRotation(angle-1, 0, 1, 0);
break;
case KeyEvent.VK_HOME:
cameraBox.setPosition(0, 0, 0);
break;
case KeyEvent.VK_R:
buildWorld();
cameraBox.setPosition(0, 0, 0);
}
drawable.repaint();
}
};
drawable=new GLJPanel();
drawable.setPreferredSize(new Dimension(600,350));
drawable.addGLEventListener(glListener);
this.setLayout(new BorderLayout());
this.add(drawable,BorderLayout.CENTER);
msg=new JLabel("Click to focus",JLabel.CENTER);
msg.setOpaque(true);
msg.setBackground(Color.LIGHT_GRAY);
msg.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
this.add(msg,BorderLayout.SOUTH);
//hierarchical test
viewer=new Camera3D();
viewer.setPerspectiveParameters(60,0.1f, 100);
cameraBox=new ObjectContainer3D();
cameraBox.addChild(viewer);
Primitive sphere=new Primitive(new UVSphereGeo(0.05));
sphere.setPosition(0, 0, -1);
viewer.addChild(sphere);
// viewer.removeChild(sphere);
buildWorld();
this.setBorder(BorderFactory.createLineBorder(Color.GRAY,4));
this.addMouseListener(ma);
this.addFocusListener(fl);
this.addKeyListener(ka);
}
private void buildWorld(){
ObjectContainer3D world=new ObjectContainer3D();
world.addChild(new Primitive(new CubeGeo()).setScale(21, 1, 21).setColor(Color.WHITE).setPosition(0, -2, 0));
for(int i=-20;i<=20;i++){
for(int j=-20;j<=20;j++){
if(Math.random()<0.02 && (Math.abs(i)>2|| Math.abs(j)>2)){
ObjectContainer3D r;
switch((int)(4*Math.random())){
case 0:
r=new Primitive(new CubeGeo()).setScale(0.5f,1.0f,0.5f);
break;
case 1:
r=new Primitive(new UVSphereGeo()).setScale(0.5f);
break;
case 3:
r=new Primitive(new UVConeGeo()).setRotation(90, -1, 0, 0).setPosition(0, -1, 0);
break;
default:
r=new Primitive(new UVCylinderGeo()).setRotation(90,-1, 0, 0).setPosition(0, -1, 0);
}
Color c=Color.getHSBColor((float)Math.random(), (float)(0.5+0.5*Math.random()), 0.8f);
world.addChild(r.setColor(c).setPosition(i, 0, j));
//hierarchical test
world.addChild(cameraBox);
}
}
theWorld=world;
}
}
}
package jscene3D;
Camera3D.java
package jscene3D;
import javax.media.opengl.GL2;
import javax.media.opengl.glu.GLU;
public class Camera3D extends ObjectContainer3D{
private float fov=45;
private float near=0.1f;
private float far=100;
private double eyex, eyey, eyez = 30;
private double refx, refy, refz;
private double upx, upy = 1, upz;
private GLU glu=new GLU();
private ObjectContainer3D node=new ObjectContainer3D();
public Camera3D(){
}
public void setView(double eyeX, double eyeY, double eyeZ,
double viewCenterX, double viewCenterY, double viewCenterZ,
double viewUpX, double viewUpY, double viewUpZ) {
eyex = eyeX;
eyey = eyeY;
eyez = eyeZ;
refx = viewCenterX;
refy = viewCenterY;
refz = viewCenterZ;
upx = viewUpX;
upy = viewUpY;
upz = viewUpZ;
}
public double[] getView() {
return new double[] { eyex, eyey, eyez, refx, refy, refz, upx, upy, upz };
}
public void apply(GL2 gl){
int[] viewport=new int[4];
gl.glGetIntegerv(GL2.GL_VIEWPORT,viewport,0);
float aspect=(float)viewport[2]/viewport[3];
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(fov, aspect, near, far);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
node=this;
while(node!=null){
node.applyInverseTransform(gl);
node=node.getParent();
}
}
public void setPerspectiveParameters(float fovIn,float nearIn,float farIn){
if(fovIn<=0 || fov>=180){
throw new IllegalArgumentException("field of view out of range.");
}
if(near<0){
throw new IllegalArgumentException("near must >0");
}
if(far<near){
throw new IllegalArgumentException("far must > near");
}
fov=fovIn;
near=nearIn;
far=farIn;
}
public float getFov(){
return fov;
}
public float getNear(){
return near;
}
public float getFar(){
return far;
}
}
package jscene3D;
ObjectContainer3D.java
package jscene3D;
import java.awt.Color;
import java.util.ArrayList;
import javax.media.opengl.GL2;
public class ObjectContainer3D {
private float scaleX=1, scaleY=1, scaleZ=1;
private float rotation=0;
private float rotationAxisX=0,rotationAxisY=0,rotationAxisZ=0;
private float translateX=0,translateY=0,translateZ=0;
private Color color;
private ArrayList<ObjectContainer3D> childrenList=new ArrayList<ObjectContainer3D>();
private ObjectContainer3D parent;
public void ObjectContainer3D(){
}
public void draw(GL2 gl){
float[] currentColor=new float[4];
if(color!=null){
//save the outside defined color first
gl.glGetFloatv(GL2.GL_CURRENT_COLOR, currentColor, 0);
}
//save matrix
gl.glPushMatrix();
//affine transform first than linear transform
gl.glTranslated(translateX,translateY,translateZ);
gl.glRotatef(rotation, rotationAxisX, rotationAxisY, rotationAxisZ);
gl.glScalef(scaleX, scaleY, scaleZ);
if(color!=null){
float[] hsb=color.getColorComponents(null);
gl.glColor3f(hsb[0], hsb[1], hsb[2]);
}
drawBasic(gl);
gl.glPopMatrix();
if(color!=null){
gl.glColor3f(currentColor[0], currentColor[1], currentColor[2]);
}
}
protected void drawBasic(GL2 gl){
if(childrenList.size()!=0){
for(ObjectContainer3D child : childrenList){
child.draw(gl);
}
}
else return;
}
public int turnOnLights(GL2 gl,int nextLightNumber){
gl.glPushMatrix();
gl.glTranslatef(translateX,translateY,translateZ);
gl.glRotatef(rotation, rotationAxisX, rotationAxisY, rotationAxisZ);
gl.glScaled(scaleX, scaleY, scaleZ);
nextLightNumber=turnOnLightsBasic(gl,nextLightNumber);
gl.glPopMatrix();
return nextLightNumber;
}
protected int turnOnLightsBasic(GL2 gl,int nextLightNumber){
return nextLightNumber;
}
public void applyInverseTransform(GL2 gl){
float sx=(scaleX==0? 1:1/scaleX);
float sy=(scaleY==0? 1:1/scaleY);
float sz=(scaleZ==0? 1:1/scaleZ);
//linear transform first than
gl.glScalef(sx,sy,sz);
gl.glRotatef(-rotation, rotationAxisX, rotationAxisY, rotationAxisZ);
//than the affine transform
gl.glTranslatef(-translateX, -translateY, -translateZ);
}
public void addChild(ObjectContainer3D child){
if(child==null) {
throw new IllegalArgumentException("Can't add a null object");
}
childrenList.add(child);
child.setParent(this);
}
public void removeChild(ObjectContainer3D child){
if(child==null) {
throw new IllegalArgumentException("Can't add a null object");
}
childrenList.remove(child);
child.setParent(null);
}
public boolean contains(ObjectContainer3D child){
if(childrenList.contains(child)){
return true;
}
return false;
}
public int numChildren(){
return childrenList.size();
}
public ObjectContainer3D setScale(float uniformScaleFactor){
scaleX=scaleY=scaleZ=uniformScaleFactor;
return this;
}
public ObjectContainer3D setScale(float scaleXIn,float scaleYIn,float scaleZIn){
scaleX=scaleXIn;
scaleY=scaleYIn;
scaleZ=scaleZIn;
return this;
}
public ObjectContainer3D setPosition(float x,float y,float z){
translateX=x;
translateY=y;
translateZ=z;
return this;
}
public ObjectContainer3D setRotation(float angle,float xAxis,float yAxis,float zAxis){
rotation=angle;
rotationAxisX=xAxis;
rotationAxisY=yAxis;
rotationAxisZ=zAxis;
return this;
}
public float[] getPosition(){
return new float[]{translateX,translateY,translateZ};
}
public float[] getRotation(){
return new float[]{rotation,rotationAxisX,rotationAxisY,rotationAxisZ};
}
public float[] getScale(){
return new float[]{scaleX,scaleY,scaleZ};
}
public ObjectContainer3D setColor(Color color){
this.color=color;
return this;
}
public Color getColor(){
return color;
}
public ObjectContainer3D getParent() {
return parent;
}
public void setParent(ObjectContainer3D parent) {
this.parent = parent;
}
}
package jscene3D;
Entity.java
extends ObjectContainer3D and can be set shading
package jscene3D;
import java.awt.Color;
import java.util.ArrayList;
import javax.media.opengl.GL2;
public class Entity extends ObjectContainer3D{
private float scaleX=1, scaleY=1, scaleZ=1;
private float rotation=0;
private float rotationAxisX=0,rotationAxisY=0,rotationAxisZ=0;
private float translateX=0,translateY=0,translateZ=0;
private ArrayList<ObjectContainer3D> childrenList=new ArrayList<ObjectContainer3D>();
private ObjectContainer3D parent;
private float[] color;
private float[] specularColor, diffuseColor, ambientColor, emissionColor;
private int shininess = -1;
public Entity(){
}
public void draw(GL2 gl){
boolean hasColor=(color!=null || specularColor!=null || ambientColor!=null || diffuseColor!=null ||
emissionColor!=null || shininess>=0);
if(hasColor){
gl.glPushAttrib(GL2.GL_LIGHTING_BIT|GL2.GL_CURRENT_BIT);
if(color!=null){
gl.glGetFloatv(GL2.GL_CURRENT_COLOR, color,0);
}
if(ambientColor!=null){
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, ambientColor,0);
}
if(diffuseColor!=null){
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK,GL2.GL_DIFFUSE,diffuseColor,0);
}
if(specularColor!=null){
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, specularColor,0);
}
if(emissionColor!=null){
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_EMISSION, emissionColor, 0);
}
if(shininess>=0){
gl.glMateriali(GL2.GL_FRONT_AND_BACK,GL2.GL_SHININESS,shininess);
}
gl.glPushMatrix();
gl.glTranslatef(translateX, translateY, translateZ);
gl.glRotated(rotation, rotationAxisX, rotationAxisY, rotationAxisZ);
gl.glScalef(scaleX, scaleY, scaleZ);
drawBasic(gl);
gl.glPopMatrix();
if(hasColor){
gl.glPopAttrib();
}
}
}
public Entity setColor(Color color) {
this.color = color == null? null : color.getRGBColorComponents(null);
return this;
}
public Entity setColor(float r, float g, float b) {
this.color = new float[] { r, g, b, 1 };
return this;
}
public Entity setColor(float r, float g, float b, float alpha) {
this.color = new float[] { r, g, b, alpha };
return this;
}
public float[] getColorf() {
return color;
}
public Entity setAmbientAndDiffuseColor(Color c) {
this.ambientColor = c == null? null : c.getRGBColorComponents(null);
this.diffuseColor = c == null? null : c.getRGBColorComponents(null);
return this;
}
public Entity setAmbientAndDiffuseColor(float r, float g, float b) {
this.ambientColor = new float[] { r, g, b, 1 };
this.diffuseColor = new float[] { r, g, b, 1 };
return this;
}
public Entity setAmbientAndDiffuseColor(float r, float g, float b, float alpha) {
this.ambientColor = new float[] { r, g, b, alpha };
this.diffuseColor = new float[] { r, g, b, alpha };
return this;
}
public Entity setAmbientColor(Color c) {
this.ambientColor = c == null? null : c.getRGBColorComponents(null);
return this;
}
public Entity setAmbientColor(float r, float g, float b) {
this.ambientColor = new float[] { r, g, b, 1 };
return this;
}
public Entity setAmbientColor(float r, float g, float b, float alpha) {
this.ambientColor = new float[] { r, g, b, alpha };
return this;
}
public float[] getAmbientColor() {
return ambientColor;
}
public Entity setDiffuseColor(Color c) {
this.diffuseColor = c == null? null : c.getRGBColorComponents(null);
return this;
}
public Entity setDiffuseColor(float r, float g, float b) {
this.diffuseColor = new float[] { r, g, b, 1 };
return this;
}
public Entity setDiffuseColor(float r, float g, float b, float alpha) {
this.diffuseColor = new float[] { r, g, b, alpha };
return this;
}
public float[] getDiffuseColor() {
return diffuseColor;
}
public Entity setSpecularColor(Color c) {
this.specularColor = c == null? null : c.getRGBColorComponents(null);
return this;
}
public Entity setSpecularColor(float r, float g, float b) {
this.specularColor = new float[] { r, g, b, 1 };
return this;
}
public Entity setSpecularColor(float r, float g, float b, float alpha) {
this.specularColor = new float[] { r, g, b, alpha };
return this;
}
public float[] getSpecularColor() {
return specularColor;
}
public Entity setEmissionColor(Color c) {
this.emissionColor = c == null? null : c.getRGBColorComponents(null);
return this;
}
public Entity setEmissionColor(float r, float g, float b) {
this.emissionColor = new float[] { r, g, b, 1 };
return this;
}
public Entity setEmissionColor(float r, float g, float b, float alpha) {
this.emissionColor = new float[] { r, g, b, alpha };
return this;
}
public float[] getEmissionColor() {
return emissionColor;
}
public Entity setShininess(int shininess) {
if (shininess < 0)
this.shininess = -1;
else
this.shininess = Math.max(128, shininess);
return this;
}
public int getShininess() {
return shininess;
}
}