L'animazione 3D della fusione è stato realizzato con Eclipse e con le libreie JOGL.
Main.java
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import javax.swing.border.EmptyBorder;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.WindowUpdateEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.util.FPSAnimator;
import java.awt.event.WindowAdapter;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
public class Main extends JFrame {
private JPanel contentPane;
private GLRenderer renderer;
private GLWindow window;
private FPSAnimator animator;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Main() {
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
window.destroy();
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(0, 150, 296, 167);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JButton btnStart = new JButton("Start");
btnStart.setFocusPainted(false);
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
animator.start();
}
});
contentPane.add(btnStart, BorderLayout.WEST);
JButton btnStop = new JButton("Stop");
btnStop.setFocusPainted(false);
btnStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
animator.stop();
}
});
contentPane.add(btnStop, BorderLayout.EAST);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.CENTER);
SpringLayout sl_panel = new SpringLayout();
panel.setLayout(sl_panel);
JButton btnReset = new JButton("Reset");
btnReset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
renderer.reset();
window.display();
}
});
sl_panel.putConstraint(SpringLayout.NORTH, btnReset, 10, SpringLayout.NORTH, panel);
sl_panel.putConstraint(SpringLayout.WEST, btnReset, 10, SpringLayout.WEST, panel);
panel.add(btnReset);
window = GLWindow.create(new GLCapabilities(GLProfile.getDefault()));
window.setSize(500, 500);
renderer = new GLRenderer();
window.addGLEventListener(renderer);
window.setPosition(600, 100);
window.setVisible(true);
animator = new FPSAnimator(window, 60, true);
window.addWindowListener(new WindowListener(){
@Override
public void windowResized(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowMoved(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDestroyNotify(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDestroyed(WindowEvent e) {
System.exit(0);
}
@Override
public void windowGainedFocus(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowLostFocus(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowRepaint(WindowUpdateEvent e) {
// TODO Auto-generated method stub
}
});
}
}
GLRenderer.java
import java.util.ArrayList;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.util.gl2.GLUT;
public class GLRenderer implements GLEventListener {
//telecamera
private int dist = 20, w = 0, h = 0;
private double rX = -20, rY = -10, rXInc = 0, rYInc = 0;
private double scale = 1;
private double xCam = 0, zCam = 0;
//elementi
private double r = 0.5;
public final double DIST_INIZ = 80;
private double xEl1 = -Math.cos(30 * Math.PI / 180.0) * DIST_INIZ, zEl1 = -Math.sin(30 * Math.PI / 180.0) * DIST_INIZ;
private double xEl2 = Math.cos(65 * Math.PI / 180.0) * DIST_INIZ, zEl2 = -Math.sin(65 * Math.PI / 180.0) * DIST_INIZ;
//animazioni
private double tAnimazione1 = 8, delayAnimazione2 = 1, tAnimazione2 = 5;
private int frame = 0;
//tracce
private ArrayList tracciaEl1 = new ArrayList();
private ArrayList tracciaEl2 = new ArrayList();
private ArrayList tracciaP1 = new ArrayList();
private ArrayList tracciaP2 = new ArrayList();
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL2.GL_LEQUAL);
gl.glShadeModel(GL2.GL_SMOOTH);
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
//luce
float[] lAmbiente = new float[]{1, 1, 1, 0};
float[] lDiffusa = new float[]{1, 1, 1, 1};
float[] lSpeculare = new float[]{0, 0, 0, 0};
float[] lPosizione = new float[]{5, 0, 0, 0};
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, lDiffusa, 0);
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, lSpeculare, 0);
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, lPosizione, 0);
gl.glEnable(GL2.GL_LIGHT0);
gl.glEnable(GL2.GL_LIGHTING);
gl.glEnable(GL2.GL_COLOR_MATERIAL);
}
@Override
public void dispose(GLAutoDrawable drawable) {
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
GLUT glut = new GLUT();
GLU glu = new GLU();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
//camera su elemento 1 (deuterio)
if(frame < (2 * tAnimazione1 / 8.0) * 60)
{
xCam = xEl1;
zCam = zEl1;
rX += (280.0 + 20.0) / ((2 * tAnimazione1 / 8.0) * 60);
rY += (0.0 + 10.0) / ((2 * tAnimazione1 / 8.0) * 60);
}
//transizione a elemento 2
if((frame >= (2 * tAnimazione1 / 8.0) * 60) && (frame < (3 * tAnimazione1 / 8.0) * 60))
{
xCam += (xEl2 - xCam) / (((3 *tAnimazione1 / 8.0) * 60) - frame);
zCam += (zEl2 - zCam) / (((3 *tAnimazione1 / 8.0) * 60) - frame);
rX += (340.0 - 280.0) / ((tAnimazione1 / 8.0) * 60);
}
//camera su elemento 2 (trizio)
if((frame >= (3 * tAnimazione1 / 8.0) * 60) && (frame < (5 * tAnimazione1 / 8.0) * 60))
{
xCam = xEl2;
zCam = zEl2;
rX += (150.0 + 20.0) / ((2 * tAnimazione1 / 8.0) * 60);
rY += (10.0 - 0.0) / ((2 * tAnimazione1 / 8.0) * 60);
}
//transizione a scontro
if((frame >= (5 * tAnimazione1 / 8.0) * 60) && (frame < (6 * tAnimazione1 / 8.0) * 60))
{
xCam += (0 - xCam) / (((6 *tAnimazione1 / 8.0) * 60) - frame);
zCam += (0 - zCam) / (((6 *tAnimazione1 / 8.0) * 60) - frame);
rX += ((360.0 + 15.0) - 150.0) / ((tAnimazione1 / 8.0) * 60);
}
//camera sullo scontro
if((frame >= (6 * tAnimazione1 / 8.0) * 60) &&(frame < tAnimazione1 * 60))
{
xCam = 0;
zCam = 0;
scale += (1.2 - 1.0) / ((2 * tAnimazione1 / 8.0) * 60);
}
//transizione ai prodotti
if((frame >= tAnimazione1 * 60) && (frame < (tAnimazione1 + delayAnimazione2) * 60))
{
rX += (195.0 - 15.0) / (delayAnimazione2 * 60);
rY += (20.0 - 10.0) / (delayAnimazione2 * 60);
scale += (1.0 - 1.2) / (delayAnimazione2 * 60);
}
//transizione a prodotto 2 (neutrone)
if((frame >= (tAnimazione1 + delayAnimazione2) * 60) && (frame < (tAnimazione1 + delayAnimazione2 + (tAnimazione2 / 5.0)) * 60))
{
xCam += (xEl2 - xCam) / (((tAnimazione1 + delayAnimazione2 + (tAnimazione2 / 5.0)) * 60) - frame);
zCam += (zEl2 - zCam) / (((tAnimazione1 + delayAnimazione2 + (tAnimazione2 / 5.0)) * 60) - frame);
rX += (210.0 - 195.0) / ((tAnimazione2 / 5.0) * 60);
}
//camera su prodotto 2
if((frame >= (tAnimazione1 + delayAnimazione2 + (tAnimazione2 / 5.0)) * 60) && (frame < (tAnimazione1 + delayAnimazione2 + (2 * tAnimazione2 / 5.0)) * 60))
{
xCam = xEl2;
zCam = zEl2;
rX += (310.0 - 210.0) / ((tAnimazione2 / 5.0) * 60);
rY += (5.0 - 20.0) / ((tAnimazione2 / 5.0) * 60);
}
//transizione a prodotto 1
if((frame >= (tAnimazione1 + delayAnimazione2 + (2 * tAnimazione2 / 5.0)) * 60) && (frame < (tAnimazione1 + delayAnimazione2 + (3 * tAnimazione2 / 5.0)) * 60))
{
xCam += (xEl1 - xCam) / (((tAnimazione1 + delayAnimazione2 + (3 *tAnimazione2 / 5.0)) * 60) - frame);
zCam += (zEl1 - zCam) / (((tAnimazione1 + delayAnimazione2 + (3 *tAnimazione2 / 5.0)) * 60) - frame);
rX += (360.0 - 310.0) / ((tAnimazione2 / 5.0) * 60);
}
//camera su prodotto 1 (elio)
if((frame >= (tAnimazione1 + delayAnimazione2 + (3 * tAnimazione2 / 5.0)) * 60) && (frame < (tAnimazione1 + delayAnimazione2 + (5 * tAnimazione1 / 5.0)) * 60))
{
xCam = xEl1;
zCam = zEl1;
rX += (300.0 - 0.0) / ((2 * tAnimazione2 / 5.0) * 60);
rY += (-10.0 - 5.0) / ((2 * tAnimazione2 / 5.0) * 60);
}
if(rX >= 360)
{
rX = rX - (Math.floor(rX / 360.0) * 360);
}
glu.gluPerspective(45, (float) w / h, 1, 200);
glu.gluLookAt(xCam + (dist * Math.cos((rY + rYInc) * Math.PI / 180.0) * Math.sin((rX + rXInc) * Math.PI / 180.0)),
(dist * Math.sin((rY + rYInc) * Math.PI / 180.0)), zCam + (dist * Math.cos((rY + rYInc) * Math.PI / 180.0) * Math.cos((rX + rXInc) * Math.PI / 180.0)), xCam, 0, zCam, 0, 1, 0);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
if(frame < tAnimazione1 * 60)
{
//elemento 1 (deuterio)
gl.glLoadIdentity();
gl.glScaled(scale, scale, scale);
gl.glTranslated(xEl1, 0, zEl1);
gl.glRotated(60, 0, 1, 0);
gl.glRotated(30, 0, 0, 1);
gl.glTranslated(-r/2, 0, 0);
gl.glColor3d(0.8, 0.8, 0.8);
glut.glutSolidSphere(r, 16, 16);
gl.glTranslated(r, 0, 0);
gl.glColor3d(1, 0, 0);
glut.glutSolidSphere(r, 16, 16);
//elemento 2 (trizio)
gl.glLoadIdentity();
gl.glScaled(scale, scale, scale);
gl.glTranslated(xEl2, 0, zEl2);
gl.glRotated(25, 0, 1, 0);
gl.glTranslated(r/2, 0, 0);
gl.glColor3d(0.8, 0.8, 0.8);
glut.glutSolidSphere(r, 16, 16);
gl.glTranslated(-r/2 + (r/2 * Math.cos(120.0 / 180.0 * Math.PI)), r/2 * Math.sin(120.0 / 180.0 * Math.PI), 0);
gl.glColor3d(1, 0, 0);
glut.glutSolidSphere(r, 16, 16);
gl.glTranslated(r/2 * Math.cos(120.0 / 180.0 * Math.PI), -2 * r/2 * Math.sin(120.0 / 180.0 * Math.PI), 0);
gl.glColor3d(0.8, 0.8, 0.8);
glut.glutSolidSphere(r, 16, 16);
//tracce elementi iniziali
tracciaP1.add(new Point(xEl1, 0 , zEl1));
if(tracciaP1.size() >= 40)
tracciaP1.remove(0);
tracciaP2.add(new Point(xEl2, 0, zEl2));
if(tracciaP2.size() >= 40)
tracciaP2.remove(0);
gl.glLoadIdentity();
gl.glScaled(scale, scale, scale);
gl.glBegin(GL2.GL_LINES);
Point p1, p2;
for(int i = tracciaP1.size() - 1; i > 0; i--)
{
p1 = tracciaP1.get(i);
p2 = tracciaP1.get(i - 1);
gl.glColor3d(1 - 0.01 * (tracciaP1.size() - 1 - i), 1 - 0.01 * (tracciaP1.size() - 1 - i),1 - 0.01 * (tracciaP1.size() - 1 - i));
gl.glVertex3d(p1.getX(), p1.getY(), p1.getZ());
gl.glVertex3d(p2.getX(), p2.getY(), p2.getZ());
}
for(int i = tracciaP2.size() - 1; i > 0; i--)
{
p1 = tracciaP2.get(i);
p2 = tracciaP2.get(i - 1);
gl.glColor3d(1 - 0.01 * (tracciaP2.size() - 1 - i), 1 - 0.01 * (tracciaP2.size() - 1 - i),1 - 0.01 * (tracciaP2.size() - 1 - i));
gl.glVertex3d(p1.getX(), p1.getY(), p1.getZ());
gl.glVertex3d(p2.getX(), p2.getY(), p2.getZ());
}
gl.glEnd();
//movimento elementi iniziali
xEl1 += Math.cos(30 * Math.PI / 180.0) * DIST_INIZ / (tAnimazione1 * 60);
zEl1 += Math.sin(30 * Math.PI / 180.0) * DIST_INIZ / (tAnimazione1 * 60);
xEl2 -= Math.cos(65 * Math.PI / 180.0) * DIST_INIZ / (tAnimazione1 * 60);
zEl2 += Math.sin(65 * Math.PI / 180.0) * DIST_INIZ / (tAnimazione1 * 60);
}
else
{
//flash
if(frame == tAnimazione1 * 60){
float[] lAmbiente = new float[]{1, 1, 1, 0};
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, lAmbiente, 0);
xEl1 += 1.2 * r;
zEl1 += 0;
}
if(frame == (tAnimazione1 * 60) + 10){
float[] lAmbiente = new float[]{0, 0, 0, 0};
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, lAmbiente, 0);
}
//prodotto 1 (elio)
gl.glLoadIdentity();
gl.glScaled(scale, scale, scale);
gl.glTranslated(xEl1, 0, zEl1);
gl.glRotated(45, 0, 1, 0);
gl.glTranslated(r/2, -Math.sqrt(7) / (4.0 * Math.sqrt(2)) * r, 0);
gl.glColor3d(0.8, 0.8, 0.8);
glut.glutSolidSphere(r, 16, 16);
gl.glTranslated(-r, 0, 0);
gl.glColor3d(1, 0, 0);
glut.glutSolidSphere(r, 16, 16);
gl.glTranslated(r/2, Math.sqrt(7) / (2.0 * Math.sqrt(2)) * r, r/2);
gl.glColor3d(0.8, 0.8, 0.8);
glut.glutSolidSphere(r, 16, 16);
gl.glTranslated(0, 0, -r);
gl.glColor3d(1, 0, 0);
glut.glutSolidSphere(r, 16, 16);
//prodotto 2 (neutrone)
gl.glLoadIdentity();
gl.glScaled(scale, scale, scale);
gl.glTranslated(xEl2, 0, zEl2);
gl.glRotated(5, 0, 1, 0);
gl.glColor3d(0.8, 0.8, 0.8);
glut.glutSolidSphere(r, 16, 16);
//tracce prdotti
tracciaP1.add(new Point(xEl1, 0 , zEl1));
if(tracciaP1.size() >= 40)
tracciaP1.remove(0);
tracciaP2.add(new Point(xEl2, 0, zEl2));
if(tracciaP2.size() >= 40)
tracciaP2.remove(0);
gl.glLoadIdentity();
gl.glScaled(scale, scale, scale);
gl.glBegin(GL2.GL_LINES);
Point p1, p2;
for(int i = tracciaEl1.size() - 1; i > 0; i--)
{
p1 = tracciaEl1.get(i);
p2 = tracciaEl1.get(i - 1);
gl.glColor3d(1 - 0.01 * (tracciaEl1.size() - 1 - i), 1 - 0.01 * (tracciaEl1.size() - 1 - i),1 - 0.01 * (tracciaEl1.size() - 1 - i));
gl.glVertex3d(p1.getX(), p1.getY(), p1.getZ());
gl.glVertex3d(p2.getX(), p2.getY(), p2.getZ());
}
if(frame < (tAnimazione1 + delayAnimazione2 + (3 * tAnimazione2 / 5.0)) * 60)
{
for(int i = tracciaEl2.size() - 1; i > 0; i--)
{
p1 = tracciaEl2.get(i);
p2 = tracciaEl2.get(i - 1);
gl.glColor3d(1 - 0.01 * (tracciaEl2.size() - 1 - i), 1 - 0.01 * (tracciaEl2.size() - 1 - i),1 - 0.01 * (tracciaEl2.size() - 1 - i));
gl.glVertex3d(p1.getX(), p1.getY(), p1.getZ());
gl.glVertex3d(p2.getX(), p2.getY(), p2.getZ());
}
}
//tracce elementi iniziali (per non farli sparire di colpo)
if(tracciaEl1.size() >= 1)
tracciaEl1.remove(0);
if(tracciaEl2.size() >= 1)
tracciaEl2.remove(0);
for(int i = tracciaP1.size() - 1; i > 0; i--)
{
p1 = tracciaP1.get(i);
p2 = tracciaP1.get(i - 1);
gl.glColor3d(1 - 0.01 * (tracciaP1.size() - 1 - i), 1 - 0.01 * (tracciaP1.size() - 1 - i),1 - 0.01 * (tracciaP1.size() - 1 - i));
gl.glVertex3d(p1.getX(), p1.getY(), p1.getZ());
gl.glVertex3d(p2.getX(), p2.getY(), p2.getZ());
}
for(int i = tracciaP2.size() - 1; i > 0; i--)
{
p1 = tracciaP2.get(i);
p2 = tracciaP2.get(i - 1);
gl.glColor3d(1 - 0.01 * (tracciaP2.size() - 1 - i), 1 - 0.01 * (tracciaP2.size() - 1 - i),1 - 0.01 * (tracciaP2.size() - 1 - i));
gl.glVertex3d(p1.getX(), p1.getY(), p1.getZ());
gl.glVertex3d(p2.getX(), p2.getY(), p2.getZ());
}
gl.glEnd();
//movimento prodotti
if(frame > (tAnimazione1 + delayAnimazione2) * 60)
{
xEl1 += Math.cos(45 * Math.PI / 180.0) * 20 / (tAnimazione2 * 60);
zEl1 += Math.sin(45 * Math.PI / 180.0) * 20 / (tAnimazione2 * 60);
xEl2 -= Math.cos(85 * Math.PI / 180.0) * 60 / (tAnimazione2 * 60);
zEl2 += Math.sin(85 * Math.PI / 180.0) * 60 / (tAnimazione2 * 60);
}
if(frame > (tAnimazione1 + delayAnimazione2 + tAnimazione2) * 60){
reset();
}
}
frame++;
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
GL2 gl = drawable.getGL().getGL2();
GLU glu = new GLU();
this.w = w;
this.h = h;
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void reset(){
frame = 0;
xEl1 = -Math.cos(30 * Math.PI / 180.0) * DIST_INIZ;
zEl1 = -Math.sin(30 * Math.PI / 180.0) * DIST_INIZ;
xEl2 = Math.cos(65 * Math.PI / 180.0) * DIST_INIZ;
zEl2 = -Math.sin(65 * Math.PI / 180.0) * DIST_INIZ;
rX = -20;
rY = -10;
scale = 1;
tracciaEl1.clear();
tracciaEl2.clear();
tracciaP1.clear();
tracciaP2.clear();
}
}
Point.java
public class Point {
double x, y, z;
public Point(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
}