立方体の表と裏を表現する

立方体の表と裏を表現する

 次は立方体の表と裏を表現することをしてみたいと思います。
今までの立方体は、線で表していましたが、ここでは立方体の面に色を付けてみます。
本で紹介されていたのを参考に、立方体の遠近に応じて面の色を変化させます。

 最初は立方体の頂点を配列にしていましたが、これに加えて、立方体の面を三角形に分割して表現します。三角形の3頂点位置を左回りで配列にしています。
以下は、CubeVert.javaです。Faseというクラスを追加し、左回り頂点の配列を追加しています。


public class CubeVert {
	public static Vertex vt[];
	public static Vertex ax[];
	static int vt_num=8;
	static double phi0=0.1;
	static double theta0=-0.2;
	static double phi=phi0;
	static double theta=theta0;

	static int fc_num = 12;
    static Face fc[];
    
	  // 初期化されないコンストラクタ
	  private CubeVert(){
		  setReangl();
	  }
	
	public static int getVt_num() {
		return vt_num;
	}
	public static int getFc_num() {
		return fc_num;
	}
	
	  public static  void setModelData() {
	        vt  = new Vertex[vt_num];
	        ax=new Vertex[3];
	        fc  = new Face[fc_num];
	        
	        vt[0]=new Vertex( -1, -1, 1);
	        vt[1]=new Vertex( -1, 1, 1);
	        vt[2]=new Vertex( 1, 1, 1);
	        vt[3]=new Vertex( 1, -1, 1);
	        vt[4]=new Vertex( -1, -1,-1);
	        vt[5]=new Vertex( -1, 1,-1);
	        vt[6]=new Vertex( 1, 1,-1);
	        vt[7]=new Vertex( 1, -1,-1);
	        
	        ax[0]=new Vertex( 2, 0, 0);	//x
	        ax[1]=new Vertex( 0, 2, 0);	//y
	        ax[2]=new Vertex( 0, 0, 2);	//z	     
	        
//左回り三角形の設定
	        fc[0]=new Face( vt[0], vt[3], vt[2]);
	        fc[1]=new Face( vt[0], vt[2], vt[1]);
	        fc[2]=new Face( vt[3], vt[7], vt[6]);
	        fc[3]=new Face( vt[3], vt[6], vt[2]);
	        fc[4]=new Face( vt[7], vt[4], vt[5]);
	        fc[5]=new Face( vt[7], vt[5], vt[6]);
	        fc[6]=new Face( vt[4], vt[0], vt[1]);
	        fc[7]=new Face( vt[4], vt[1], vt[5]); 
	        fc[8]=new Face( vt[1], vt[2], vt[6]);
	        fc[9]=new Face( vt[1], vt[6], vt[5]);
	        fc[10]=new Face( vt[4], vt[7], vt[3]);
	        fc[11]=new Face( vt[4], vt[3], vt[0]);
	  }

	public static void rotate() {
		double cosp=Math.cos(phi),sinp=Math.sin(phi);
		double cost=Math.cos(theta),sint=Math.sin(theta);	
		double dtx,dty;
		for(int i=0;i<vt_num;i++){
			dty=vt[i].y;
			vt[i].y= dty*cosp -vt[i].z*sinp;
			  vt[i].z= dty*sinp +vt[i].z*cosp;
			  dtx=vt[i].x;
			  vt[i].x= dtx*cost +vt[i].z*sint;
			  vt[i].z= -dtx*sint +vt[i].z*cost;
		 }

		for(int i=0;i<3;i++){
			dty=ax[i].y;
			ax[i].y= dty*cosp -ax[i].z*sinp;
			ax[i].z= dty*sinp +ax[i].z*cosp;
			dtx=ax[i].x;
			ax[i].x= dtx*cost +ax[i].z*sint;
			ax[i].z= -dtx*sint +ax[i].z*cost;
		 }
	}

	public static void setangl(double phai, double thet) {
		phi=phai;
		theta=thet;		
	}
	public static void setangl() {
		setReangl();
		setModelData();
		rotate();
	}
	
	static void setReangl(){
		phi=phi0;
		theta=theta0;	
	}
}

//==================
// Vertex クラス
//==================
  class Vertex
  {
      public double x,y,z;
  
      public Vertex(double x,double y,double z)
      {
          this.x = x;
          this.y = y;
          this.z = z;
      }
  }
  
//===========================================================================
//Face クラス
//
//===========================================================================
  class Face
  {
      public Vertex vt[]=new Vertex[3];
      public double nx,ny,nz,depth;
      
  
      public Face(Vertex v0,Vertex v1,Vertex v2)
      {
          vt[0]=v0;
          vt[1]=v1;
          vt[2]=v2;
          depth=0;
          nx=0;
          ny=0;
          nz=0;
      }
      
      public double getDepth(){
   	   return (vt[0].z+vt[1].z+vt[2].z);
   	   
      }
  }

次は、DrawGraphi.javaです。本に書いてあるのを参考にして、ベクトルの外積を計算し三角形の表裏を判別しています。
三角形で見えている面の中から、一番奥にある三角形から順番に並び替えて、色の明るさを可変しています。これにより立方体が3D表示みたいになります。
変更したのはこの二つのファイルだけです。


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;

public class DrawGraphi {
		static double Center_x,Center_y;
		static int Canvas_w,Canvas_h;
		static double Factor;
		
	DrawGraphi(){
		initial();
	}

	void initial(){
		CubeVert.setModelData();
		CubeVert.rotate();
	}
	
	public void Draw(Graphics g){
		Graphics2D g2 = (Graphics2D)g;
		vtnum=CubeVert.getVt_num();
	    fcnum=CubeVert.getFc_num();

		
		
		Canvas_w = Viewp.getFrameSizeX();
		Canvas_h = Viewp.getFrameSizeY();
		Center_x= Canvas_w/2;
		Center_y= Canvas_h/2;
		Viewp. setViewPort();
		Factor=Viewp.Factor;
		int x0,y0;
		int g_Scale=100;
		int line[][]=new int[8][2];
		g2.setBackground(backColor);
		g2.clearRect(0,0,Canvas_w,Canvas_h);
		
//ここから三角形の表裏処理を追加
  	    int    px[]  = new int[3];
        int    py[]  = new int[3];
        int    count = 0;
        int    tmp[] = new int[fcnum];

        double tmp_depth[]= new double[fcnum];
        double a1,a2,a3,b1,b2,b3,nx,ny,nz;
        boolean nomal_inverse = true;		//前後表示反転
  	  
        for(int i = 0; i < fcnum; i++)
        {
            a1 = CubeVert.fc[i].vt[1].x - CubeVert.fc[i].vt[0].x;
            a2 = CubeVert.fc[i].vt[1].y - CubeVert.fc[i].vt[0].y;
            a3 = CubeVert.fc[i].vt[1].z - CubeVert.fc[i].vt[0].z;
            b1 = CubeVert.fc[i].vt[2].x - CubeVert.fc[i].vt[1].x;
            b2 = CubeVert.fc[i].vt[2].y - CubeVert.fc[i].vt[1].y;
            b3 = CubeVert.fc[i].vt[2].z - CubeVert.fc[i].vt[1].z; 

            CubeVert.fc[i].nx = a2 * b3 - a3 * b2;   
            CubeVert.fc[i].ny = a3 * b1 - a1 * b3;
            CubeVert.fc[i].nz = a1 * b2 - a2 * b1;
            
            if(nomal_inverse)  {		//前後反転処理
            	CubeVert.fc[i].nx = -CubeVert.fc[i].nx;
            	CubeVert.fc[i].ny = -CubeVert.fc[i].ny;
            	CubeVert.fc[i].nz = -CubeVert.fc[i].nz;
            }
            
            if( CubeVert.fc[i].nz < 0)  {			//外積が負なら表向き
                tmp[count] = i;
                tmp_depth[count] = CubeVert.fc[i].getDepth();
                count++;
           }
        }

        double t;
        int ti;
        int lim = count-1;  

        do{
            int m = 0;
            for(int n = 0;n <= lim-1; n++)
            {
            	if(nomal_inverse)  {
            		if(tmp_depth[n] &qt tmp_depth[n+1])
                	{						//Z軸重心位置の大きい順に並べ替える
                    	t = tmp_depth[n];
                    	tmp_depth[n] = tmp_depth[n+1];
                    	tmp_depth[n+1] = t;
                    	ti = tmp[n];
                    	tmp[n] = tmp[n+1];
                    	tmp[n+1] = ti;
                    	m = n;
                	}  
            	}else{
                	t = tmp_depth[n];		//Z軸重心位置の小さい順に並べ替える
                	tmp_depth[n] = tmp_depth[n+1];
                	tmp_depth[n+1] = t;
                	ti = tmp[n];
                	tmp[n] = tmp[n+1];
                	tmp[n+1] = ti;
                	m = n;
            	}
            }
            lim = m;
        }while(lim!=0);
        
        
        int B;
        double l;
        
        for(int m=0;m<count;m++)     
        {
            int i = tmp[m];
            l = Math.sqrt(CubeVert.fc[i].nx * CubeVert.fc[i].nx + CubeVert.fc[i].ny * CubeVert.fc[i].ny +
            		CubeVert.fc[i].nz * CubeVert.fc[i].nz );

            B = (int)( 75 -180 * CubeVert.fc[i].nz / l);

            if( B < 0  )B = 0;
            if( B &qt 255)B = 255;
            Color cc;
            cc = Color.getHSBColor((float)0.18,(float)0.8,(float)B / 255);
//				Hue(色調), Saturation(鮮明度), Brightness(輝度)
            //   0.1,1.0=yellow 0.3,0.5= green  0.04,0.04 glay
            g2.setColor(cc);
          
            for(int j=0; j < 3; j++) {	
                px[j]=(int)( Center_x+CubeVert.fc[i].vt[j].x* g_Scale*Factor);
                py[j]=(int)(Center_y-CubeVert.fc[i].vt[j].y * g_Scale*Factor);
            }

            g2.fillPolygon(px,py,3); 
        }
        
        
//ここから立方体とxyzの線を描く 前回と同じ	
		for(int i=0;i<vtnum;i++){
			x0=(int)((CubeVert.vt[i].x) * g_Scale) ;
			y0=(int)((CubeVert.vt[i].y) * g_Scale) ;
			line[i][0]=x0;line[i][1]=y0;
		}

		g2.setColor(new Color(255,255,255));	//white
		for(int j=0;j<vtnum;j++){
			if(j==3){
	            g2.draw(new Line2D.Double(Center_x+line[j][0]*Factor,Center_y-line[j][1]*Factor,Center_x+line[j-3][0]*Factor,Center_y-line[j-3][1]*Factor));
				
			}else if(j==7){	//うまくor処理ができないので分離した
	            g2.draw(new Line2D.Double(Center_x+line[j][0]*Factor,Center_y-line[j][1]*Factor,Center_x+line[j-3][0]*Factor,Center_y-line[j-3][1]*Factor));
			}else{
	            g2.draw(new Line2D.Double(Center_x+line[j][0]*Factor,Center_y-line[j][1]*Factor,Center_x+line[j+1][0]*Factor,Center_y-line[j+1][1]*Factor));
			}
		}
		for(int i=0;i<vtnum/2;i++){
            g2.draw(new Line2D.Double(Center_x+line[i][0]*Factor,Center_y-line[i][1]*Factor,Center_x+line[i+4][0]*Factor,Center_y-line[i+4][1]*Factor));
		}
		
		//xyz line
		g2.setColor(new Color(100,255,255));	//シアン
		
		for(int i=0;i<3;i++){
			if(i==1){
				g2.setColor(new Color(0,255,0));	//green
			}else if(i==2){
				g2.setColor(new Color(0,0,255));	//blue
			}
			x0=(int)((CubeVert.ax[i].x) * g_Scale) ;
			y0=(int)((CubeVert.ax[i].y) * g_Scale) ;
            g2.draw(new Line2D.Double(Center_x,Center_y,Center_x+x0*Factor,Center_y-y0*Factor));
		}
	  }
	
	
		int vtnum=0,fcnum=0;
		private Color dc =new Color(255,0,255);	//pink
		private Color backColor = new Color(0,0,80);//dark blue
}



実行すると、右図のようになります。
立方体が回転すると、面の色がそれとなく変わりましたでしょうか?

これでこのシリーズは終わりです。今回のフレームに絵を描くというのを参考に、色々なものを絵で表示するプログラムを紹介できたらなぁと思っています。







今回変更した恥ずかしい内容の二つのjavaファイルを添付しておきましょう。