Java-Applet – Metaballs rendern (Animation)

aIn den letzten Tagen habe ich ein kleines Java-Applet geschrieben, um Metaballs darzustellen bzw. zu rendern. Metaballs gehören zu den klassischen Effekten in der Demo-Szene (Realtime-Berechnungen). Auf Wikipedia gibt es mehr Informationen zu Metaballs. In dem Java-Applet werden 2D-Metaballs dargstellt. Im Vorschaubild sind 3 Metaballs zu sehen: 2 positive und 1 negativer Ball (schwarz).

Applet

Start Applet

Zwei positive Metaballs treffen aufeinander:

b c d e

Source-Code:

File: VisualPotential.class

  1. import java.awt.*;
  2. import java.applet.*;
  3. import java.awt.Graphics2D;
  4.  
  5. public class VisualPotential extends Applet
  6. {
  7.     private Image buffer;
  8.     private Graphics2D gBuffer;
  9.  
  10.     // number of charges/balls
  11.     private int c_numbers=3;
  12.     // direction array for every charge/ball
  13.     private int[] direction=new int[c_numbers];
  14.     // charge array
  15.     private Charge[] c_array=new Charge[c_numbers];
  16.     // "position change" for ball physics
  17.     private double pos_change=0.01;
  18.     // scale factor (bigger/smaller balls)
  19.     private int scale=40;
  20.     private int size_width,size_height;
  21.  
  22.     // scroller attributes
  23.     private int x_s,y_s=0;
  24.     private int font_width=15;
  25.     private int scroll_speed=2;
  26.     private int scroll_wait=100;
  27.     private String scroller="SCROLLER ALERT! WUB WUB HUE - code by declis @ xdec.de";
  28.  
  29.     public void init()
  30.     {
  31.         size_width=this.getSize().width;
  32.         size_height=this.getSize().height;
  33.         x_s=size_width;
  34.  
  35.         // we are moving in unit square
  36.         // 1.0
  37.         // |
  38.         // |
  39.         // |----- 1.0
  40.  
  41.         c_array[0]=new Charge(0.15,0.35,0.7);
  42.         c_array[1]=new Charge(0.8,0.25,-0.7);
  43.         c_array[2]=new Charge(0.4,0.5,0.5);
  44.  
  45.         direction[0]=4;
  46.         direction[1]=2;
  47.         direction[2]=3;
  48.     }
  49.  
  50.     public void paint(Graphics g)
  51.     {
  52.         // Double-Buffering , THANKS @ JJAM.DE
  53.         if (buffer==null)
  54.         {
  55.             buffer=createImage(size_width,size_height);
  56.             gBuffer=(Graphics2D)buffer.getGraphics();
  57.             gBuffer.setFont(new Font("Arial",Font.BOLD,12));
  58.         }
  59.  
  60.         // calculate potential for every pixel-------------------------------
  61.         for(int h=0;h<size_height;h++)
  62.         {
  63.             for(int w=0;w<size_width;w++)
  64.             {
  65.                 double x_q=(double)w/size_width;
  66.                 double y_q=(double)h/size_height;
  67.                 double potential=0.0;
  68.  
  69.                 for(int i=0;i<c_array.length;i++)
  70.                     potential+=c_array[i].potentialAt(x_q,y_q,scale);
  71.  
  72.                 int red=130+(int)potential;
  73.                 int green=10+(int)potential;
  74.                 int blue=90+(int)potential;
  75.  
  76.                 if(red<0) red=0;        if(red>255) red=255;
  77.                 if(green<0) green=0;    if(green>255) green=255;
  78.                 if(blue<0) blue=0;      if(blue>255) blue=255;
  79.  
  80.                 gBuffer.setColor(new Color(red,green,blue));
  81.                 gBuffer.drawLine(w,h,w,h);
  82.             }
  83.         }
  84.         // ------------------------------------------------------------------
  85.  
  86.         // sine scroller-----------------------------------------------------
  87.         gBuffer.setColor(new Color(255,255,255));
  88.         if(x_s<-(scroller.length()*font_width)-scroll_wait)
  89.             x_s=size_width;     // start again
  90.         for(int i=0;i<scroller.length();i++)
  91.         {
  92.             // check left side of buffer, if char is outside of buffer, next char
  93.             if(x_s+((i+1)*font_width)>0)
  94.             {
  95.                 y_s=(int)(10*Math.sin(0.05*(x_s+(i*font_width)))+20);
  96.                 gBuffer.drawString(""+scroller.charAt(i),x_s+(i*font_width),y_s);
  97.             }
  98.             // check right side of buffer, if char outside, break for()
  99.             if(x_s+((i+1)*font_width)>size_width) i=scroller.length();
  100.         }
  101.         x_s-=scroll_speed;
  102.         // ------------------------------------------------------------------
  103.  
  104.         g.drawImage (buffer,0,0,this);
  105.         try {Thread.sleep(10);}
  106.         catch (InterruptedException e){}
  107.  
  108.         /* ******************************************************************
  109.          * small ball physics for n-balls with different directions
  110.          *
  111.          *  0
  112.          *  |
  113.          *  |   1     2
  114.          *  |       /
  115.          *  |     (b)
  116.          *  |    /
  117.          *  |   3     4
  118.          *  -------------- x=1.0
  119.          * y=1.0
  120.          *
  121.          *  1: upper left
  122.          *  2: upper right
  123.          *  3: bottom left
  124.          *  4: bottom right
  125.          *
  126.          ****************************************************************** */
  127.         for(int i=0;i<c_array.length;i++)
  128.         {
  129.             if(direction[i]==1)     // move to upper left
  130.             {
  131.                 c_array[i].set_y(c_array[i].get_y()-pos_change);
  132.                 c_array[i].set_x(c_array[i].get_x()-pos_change);
  133.             }
  134.             if(direction[i]==2)     // move to upper right
  135.             {
  136.                 c_array[i].set_y(c_array[i].get_y()-pos_change);
  137.                 c_array[i].set_x(c_array[i].get_x()+pos_change);
  138.             }
  139.             if(direction[i]==3)     // move to bottom left
  140.             {
  141.                 c_array[i].set_y(c_array[i].get_y()+pos_change);
  142.                 c_array[i].set_x(c_array[i].get_x()-pos_change);
  143.             }
  144.             if(direction[i]==4)     // move to bottom right
  145.             {
  146.                 c_array[i].set_y(c_array[i].get_y()+pos_change);
  147.                 c_array[i].set_x(c_array[i].get_x()+pos_change);
  148.             }
  149.  
  150.             // for every direction ->2 possible over-/underflows
  151.             if(direction[i]==2&&c_array[i].get_x()>1.0)
  152.                 direction[i]=1;
  153.             if(direction[i]==4&&c_array[i].get_x()>1.0)
  154.                 direction[i]=3;
  155.             if(direction[i]==3&&c_array[i].get_y()>1.0)
  156.                 direction[i]=1;
  157.             if(direction[i]==4&&c_array[i].get_y()>1.0)
  158.                 direction[i]=2;
  159.  
  160.             if(direction[i]==1&&c_array[i].get_x()<0)
  161.                 direction[i]=2;  // ok
  162.             if(direction[i]==3&&c_array[i].get_x()<0)
  163.                 direction[i]=4; // ok
  164.             if(direction[i]==2&&c_array[i].get_y()<0)
  165.                 direction[i]=4;
  166.             if(direction[i]==1&&c_array[i].get_y()<0)
  167.                 direction[i]=3;
  168.         }
  169.  
  170.         repaint();
  171.     }
  172.  
  173.     public void update(Graphics g) {paint(g);}
  174. }
import java.awt.*;
import java.applet.*;
import java.awt.Graphics2D;

public class VisualPotential extends Applet
{
    private Image buffer;
    private Graphics2D gBuffer;

    // number of charges/balls
    private int c_numbers=3;
    // direction array for every charge/ball
    private int[] direction=new int[c_numbers];
    // charge array
    private Charge[] c_array=new Charge[c_numbers];
    // "position change" for ball physics
    private double pos_change=0.01;
    // scale factor (bigger/smaller balls)
    private int scale=40;
    private int size_width,size_height;

    // scroller attributes
    private int x_s,y_s=0;
    private int font_width=15;
    private int scroll_speed=2;
    private int scroll_wait=100;
    private String scroller="SCROLLER ALERT! WUB WUB HUE - code by declis @ xdec.de";

    public void init()
    {
        size_width=this.getSize().width;
        size_height=this.getSize().height;
        x_s=size_width;

        // we are moving in unit square
        // 1.0
        // |
        // |
        // |----- 1.0

        c_array[0]=new Charge(0.15,0.35,0.7);
        c_array[1]=new Charge(0.8,0.25,-0.7);
        c_array[2]=new Charge(0.4,0.5,0.5);

        direction[0]=4;
        direction[1]=2;
        direction[2]=3;
    }

    public void paint(Graphics g)
    {
        // Double-Buffering , THANKS @ JJAM.DE
        if (buffer==null)
        {
            buffer=createImage(size_width,size_height);
            gBuffer=(Graphics2D)buffer.getGraphics();
            gBuffer.setFont(new Font("Arial",Font.BOLD,12));
        }

        // calculate potential for every pixel-------------------------------
		for(int h=0;h<size_height;h++)
		{
			for(int w=0;w<size_width;w++)
			{
				double x_q=(double)w/size_width;
				double y_q=(double)h/size_height;
				double potential=0.0;

				for(int i=0;i<c_array.length;i++)
					potential+=c_array[i].potentialAt(x_q,y_q,scale);

				int red=130+(int)potential;
				int green=10+(int)potential;
				int blue=90+(int)potential;

				if(red<0) red=0; 		if(red>255) red=255;
				if(green<0) green=0; 	if(green>255) green=255;
				if(blue<0) blue=0;		if(blue>255) blue=255;

				gBuffer.setColor(new Color(red,green,blue));
				gBuffer.drawLine(w,h,w,h);
			}
		}
		// ------------------------------------------------------------------

		// sine scroller-----------------------------------------------------
		gBuffer.setColor(new Color(255,255,255));
		if(x_s<-(scroller.length()*font_width)-scroll_wait)
			x_s=size_width; 	// start again
		for(int i=0;i<scroller.length();i++)
		{
			// check left side of buffer, if char is outside of buffer, next char
			if(x_s+((i+1)*font_width)>0)
			{
				y_s=(int)(10*Math.sin(0.05*(x_s+(i*font_width)))+20);
				gBuffer.drawString(""+scroller.charAt(i),x_s+(i*font_width),y_s);
			}
			// check right side of buffer, if char outside, break for()
			if(x_s+((i+1)*font_width)>size_width) i=scroller.length();
		}
		x_s-=scroll_speed;
		// ------------------------------------------------------------------

        g.drawImage (buffer,0,0,this);
        try {Thread.sleep(10);}
        catch (InterruptedException e){}

        /* ******************************************************************
         * small ball physics for n-balls with different directions
         *
         *  0
         *  |
         *  |   1     2
         *  |       /
         *  |     (b)
         *  |    /
         *  |   3     4
         *  -------------- x=1.0
         * y=1.0
         *
         *  1: upper left
         *  2: upper right
         *  3: bottom left
         *  4: bottom right
         *
         ****************************************************************** */
        for(int i=0;i<c_array.length;i++)
        {
        	if(direction[i]==1) 	// move to upper left
        	{
        		c_array[i].set_y(c_array[i].get_y()-pos_change);
        		c_array[i].set_x(c_array[i].get_x()-pos_change);
        	}
        	if(direction[i]==2)		// move to upper right
        	{
        		c_array[i].set_y(c_array[i].get_y()-pos_change);
        		c_array[i].set_x(c_array[i].get_x()+pos_change);
        	}
        	if(direction[i]==3)		// move to bottom left
        	{
        		c_array[i].set_y(c_array[i].get_y()+pos_change);
        		c_array[i].set_x(c_array[i].get_x()-pos_change);
        	}
        	if(direction[i]==4)		// move to bottom right
        	{
        		c_array[i].set_y(c_array[i].get_y()+pos_change);
        		c_array[i].set_x(c_array[i].get_x()+pos_change);
        	}

        	// for every direction ->2 possible over-/underflows
        	if(direction[i]==2&&c_array[i].get_x()>1.0)
        		direction[i]=1;
        	if(direction[i]==4&&c_array[i].get_x()>1.0)
        		direction[i]=3;
        	if(direction[i]==3&&c_array[i].get_y()>1.0)
        		direction[i]=1;
        	if(direction[i]==4&&c_array[i].get_y()>1.0)
        		direction[i]=2;

        	if(direction[i]==1&&c_array[i].get_x()<0)
        		direction[i]=2;  // ok
        	if(direction[i]==3&&c_array[i].get_x()<0)
        		direction[i]=4;	// ok
        	if(direction[i]==2&&c_array[i].get_y()<0)
        		direction[i]=4;
        	if(direction[i]==1&&c_array[i].get_y()<0)
        		direction[i]=3;
        }

        repaint();
    }

    public void update(Graphics g) {paint(g);}
}

File: Charge.class

  1. public class Charge
  2. {
  3.     private double x,y,charge_load;
  4.  
  5.     public Charge(double x,double y,double charge_load)
  6.     {
  7.         this.x=x;
  8.         this.y=y;
  9.         this.charge_load=charge_load;
  10.     }
  11.  
  12.     // V=kQ/r (electric potential)
  13.     // r = distance between 2 points
  14.     // Q = point charge
  15.     // k = const. = 8.99 * 10^9 N*m^2/C^2
  16.     // x,y = coordinates in unit square
  17.     // k is set to a lower value (for color creation)
  18.  
  19.     public double potentialAt(double x,double y,int k_factor)
  20.     {return (k_factor*charge_load)/(Math.sqrt((this.x-x)*(this.x-x)+(this.y-y)*(this.y-y)));}
  21.  
  22.     public double get_x(){return x;}
  23.     public double get_y(){return y;}
  24.     public double get_q(){return charge_load;}
  25.     public void set_x(double x){this.x=x;}
  26.     public void set_y(double y){this.y=y;}
  27.     public void set_charge_load(double q){this.charge_load=q;}
  28. }
public class Charge
{
	private double x,y,charge_load;

	public Charge(double x,double y,double charge_load)
	{
		this.x=x;
		this.y=y;
		this.charge_load=charge_load;
	}

	// V=kQ/r (electric potential)
	// r = distance between 2 points
	// Q = point charge
	// k = const. = 8.99 * 10^9 N*m^2/C^2
	// x,y = coordinates in unit square
	// k is set to a lower value (for color creation)

	public double potentialAt(double x,double y,int k_factor)
	{return (k_factor*charge_load)/(Math.sqrt((this.x-x)*(this.x-x)+(this.y-y)*(this.y-y)));}

	public double get_x(){return x;}
	public double get_y(){return y;}
	public double get_q(){return charge_load;}
	public void set_x(double x){this.x=x;}
	public void set_y(double y){this.y=y;}
	public void set_charge_load(double q){this.charge_load=q;}
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.