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 ArrayListtracciaEl1 = 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; } }