3D模擬自然——山體

算法上使用分形插值算法。渲染上,效率和擴展性中最理想的是用shader,但爲了方便也可以用封裝好的pixmap或shapeRenderer。這裏用pixmap來繪製3d山。值得一提,1.6.1API:Color.toIntBits(int r,int g,int b,int a)是錯的,參數位置前後倒了,導致山體一片紅,所以順着對的修改完畢。可以重置,修改blend模式以及精細程度。

以下是代碼和效果圖。

           

(可以看到n值爲2倍後內存消耗增加不止1倍,渲染算法上是需要改進的)

package indi.dawn.ff.work;

import java.util.StringTokenizer;

import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Blending;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.utils.Disposable;

class MountainC extends Actor implements Disposable{
	ShapeRenderer jj;
	 int n = 32, n1,  h,w,h2,w2, mx0,my0,  xPol[],yPol[], iCol[][][];
	  double rnd,  fiX = .2, fiY = .3, dfi = .01, scale = .8, m20,m21,m22;
	  double vert[][][], vert1[][][], Norm[][][][], Norm1z[][][], M[];
	  Color col[][];
	  boolean painted;
	  Texture buffImage;Pixmap buffGraphics;
	  InputListener ip;
	public MountainC(){
		ip=new InputListener(){

			@Override
			public boolean touchDown(InputEvent event, float x, float y,
					int pointer, int button) {
				// TODO Auto-generated method stub
				 mx0 = (int) x;  my0 = (int) y;
				  if ( Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) ){
				    setup();
//				    repaint();
				    }
				  if ( Gdx.input.isKeyPressed(Input.Keys.ALT_LEFT) ){
				    if (Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) ){ n /= 2;  if (n < 1) n = 1;}
				    else n *= 2;
				    setup();
//				    repaint();
				    }
				  if(Gdx.app.getType()==ApplicationType.Android){
					  if (pointer==1){
						  n *= 2;
						    setup();
//						    repaint();
					  }
					  if (pointer==2 )
					  { n /= 2;  if (n < 1) n = 1;}
				  }
					  
				  return true;
			}

			@Override
			public void touchDragged(InputEvent event, float x, float y,
					int pointer) {
				// TODO Auto-generated method stub
				int x1 = (int) x;  int y1 = (int) y;
				  if ( Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) )  scale *= Math.exp(-(y1 - my0)/(double)w);
				  else   fiX += dfi*(y1 - my0);
				  fiY += dfi*(x1 - mx0);   mx0 = x1;  my0 = y1;
				  rotate();
//				  repaint();
			}
			
		};
		init();
		/*for(int i=0;i<4;i++){
			for(Color c:col[i]){
				System.out.println(c.toIntBits());
			}
		}*/
		
		
	}
	private Color calCol(int r,int g,int b){
		return new Color(Color.toIntBits(255, b, g, r));
	};
	int getN(){
		return 32;
	}
	Color getCol(){
		return Color.WHITE;
	}
	Color bgColor;
	int pmWidth=600,pmHeight=800;
	public void init(){
//		w=(int) getWidth();h=(int) getHeight();
		  w = pmWidth;  h = pmHeight;  
		  w2 = w/2;  h2 = h/2;
//		  n=getN();
		  xPol = new int[3];  yPol = new int[3];
		  buffGraphics=new Pixmap(w, h, Pixmap.Format.RGB888);
//		  buffGraphics.setBlending(Blending.SourceOver);
		  
		  buffImage= new Texture(buffGraphics);
		  col = new Color[4][256];
		  for (int i = 0; i < 256; i++){
		    col[0][i] = calCol(0, 0, i);
		    col[1][i] = calCol(0, (i*220)/256, 0);
		    col[2][i] = calCol((i*150)/256, (i*150)/256, (i*50)/256);
		    col[3][i] = calCol(i, i, i);}
		  for(int i=0;i<4;i++){
			  for(Color c:col[i]){
				  System.out.println(c);
			  }
		  }
		  bgColor=getCol();
		 if(bgColor==null)
			 bgColor=Color.WHITE;
		addListener(ip);
		  setup();
		}

		public double R(){ return rnd*(Math.random()-.5);}

		public void setup(){
		  rnd = 1;
		  n1 = n+1;
		  iterate();
		  vert = new double[n1][n1][3];  vert1 = new double[n1][n1][2];
		  double dx = w/(double)n;
		  int t = 0;
		  for (int i = 0; i < n1; i++) 
		   for (int j = 0; j < n1; j++){
		    vert[i][j][0] = dx*i - w2;  vert[i][j][2] = dx*j - w2;
		    double mi = M[t++];
		    if (mi < 0) mi = .01*Math.random();
		    vert[i][j][1] = w*mi - w2/2;}
		  Norm = new double[n1][n1][2][3];  Norm1z = new double[n1][n1][2];
		  iCol = new int[n][n][2];
		  for (int i = 0; i < n; i++)
		   for (int j = 0; j < n; j++){
		     double s =
		      ((vert[i][j][1] + vert[i+1][j][1] + vert[i+1][j+1][1])/3 + w2/2)/w;
		     if (s < .01) iCol[i][j][0] = 0;
		     else if (s+.1*Math.random() > .35) iCol[i][j][0] = 3;
		      else if (s+.1*Math.random() > .15)  iCol[i][j][0] = 2;
		       else  iCol[i][j][0] = 1;
		     s = ((vert[i][j][1] + vert[i][j+1][1] + vert[i+1][j+1][1])/3 + w2/2)/w;
		     if (s < .01) iCol[i][j][1] = 0;
		     else if (s+.1*Math.random() > .35) iCol[i][j][1] = 3;
		      else if (s+.1*Math.random() > .15)  iCol[i][j][1] = 2;
		       else  iCol[i][j][1] = 1;
		    Norm[i][j][0][0] = vert[i][j][1] - vert[i+1][j][1];
		    Norm[i][j][0][1] = dx;
		    Norm[i][j][0][2] = vert[i+1][j][1] - vert[i+1][j+1][1];
		    double mod = Math.sqrt(Norm[i][j][0][0]*Norm[i][j][0][0] + Norm[i][j][0][1]*
		     Norm[i][j][0][1] + Norm[i][j][0][2]*Norm[i][j][0][2]) / 255.5;
		    Norm[i][j][0][0] /= mod; Norm[i][j][0][1] /= mod; Norm[i][j][0][2] /= mod;
		    Norm[i][j][1][0] = vert[i][j+1][1] - vert[i+1][j+1][1];
		    Norm[i][j][1][1] = dx;
		    Norm[i][j][1][2] = vert[i][j][1] - vert[i][j+1][1];
		    mod = Math.sqrt(Norm[i][j][1][0]*Norm[i][j][1][0] + Norm[i][j][1][1]*
		     Norm[i][j][1][1] + Norm[i][j][1][2]*Norm[i][j][1][2]) / 255.5;
		    Norm[i][j][1][0] /= mod; Norm[i][j][1][1] /= mod; Norm[i][j][1][2] /= mod;}
		  rotate();
		}

		public void iterate(){
		  int nc=n, Max=n1*n1, ncn1;
		  double Min=-1;
		  M = new double[Max];
		  for (int i=n+2; i < n*n1-1; i++) M[i] = Min;
		  for (int i=2*n1; i < n*n1; i += n1) M[i] = M[i-1] = 0;
		  while ( (nc /= 2) >= 1){
		    ncn1 = nc*n1;
		    for (int j=ncn1; j < Max; j += ncn1+ncn1){
		      for (int i= nc; i < n; i += nc+nc){
		        if (M[i+j]==Min)
		           M[i+j] = (M[i+j+nc-ncn1] + M[i+j-nc+ncn1])/2.+R();
		        if (M[i+j+nc]==Min)
		           M[i+j+nc] = (M[i+j+nc+ncn1] + M[i+j+nc-ncn1])/2.+R();
		        if (M[i+j+ncn1]==Min)
		           M[i+j+ncn1] = (M[i+j-nc+ncn1] + M[i+j+nc+ncn1])/2.+R(); }}
		    rnd /= 2.;}
		}
		public void rotate(){
			  double ct = Math.cos(fiX), cf = Math.cos(fiY),
			         st = Math.sin(fiX), sf = Math.sin(fiY),
			         m00 =  scale*cf,    m02 =  scale*sf,
			         m10 = scale*st*sf, m11 =  scale*ct, m12 = -scale*st*cf;
			         m20 = -ct*sf; m21 = st; m22 = ct*cf;
			  for (int i = 0; i < n1; i++)
			   for (int j = 0; j < n1; j++){
			    vert1[i][j][0] = m00*vert[i][j][0] + m02*vert[i][j][2];
			    vert1[i][j][1] = m10*vert[i][j][0] + m11*vert[i][j][1] + m12*vert[i][j][2];}
			  for (int i = 0; i < n; i++)
			   for (int j = 0; j < n; j++)
			    for (int k = 0; k < 2; k++)
			     Norm1z[i][j][k] = m20*Norm[i][j][k][0] + m21*Norm[i][j][k][1] +
			      m22*Norm[i][j][k][2];
			  painted = false;
			}
	@Override
	public void draw(Batch batch, float parentAlpha) {
		// TODO Auto-generated method stub
		 if ( !painted ){
			 if(buffImage!=null){
				 buffImage.dispose();
				 buffImage=null;
				/* buffGraphics.dispose();
				 buffGraphics=new Pixmap(w, h, Format.RGB888);*/
			 }
//			 buffGraphics.dispose();
//			 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
			 buffGraphics.setColor(Color.WHITE);
			 buffGraphics.fill();
			  int ib=0, ie=n, sti=1,  jb=0, je=n, stj=1;
			  if (m20 < 0){ ib = n; ie = -1; sti = -1;}
			  if (m22 < 0){ jb = n; je = -1; stj = -1;}
			  for (int i = ib; i != ie; i += sti)
			   for (int j = jb; j != je; j += stj){
			    if (Norm1z[i][j][0] > 0){
			     xPol[0] = w2 + (int)vert1[i][j][0];
			     xPol[1] = w2 + (int)vert1[i+1][j][0];
			     xPol[2] = w2 + (int)vert1[i+1][j+1][0];
			     yPol[0] = h2 - (int)vert1[i][j][1];
			     yPol[1] = h2 - (int)vert1[i+1][j][1];
			     yPol[2] = h2 - (int)vert1[i+1][j+1][1];
			     System.out.println(iCol[i][j][0]+"?"+(int)(Norm1z[i][j][0]));
			     System.out.println(col[iCol[i][j][0]][(int)(Norm1z[i][j][0])].toString());
			     buffGraphics.setColor(col[iCol[i][j][0]][(int)(Norm1z[i][j][0])]);
			     buffGraphics.fillTriangle(xPol[0], yPol[0], xPol[1], yPol[1], xPol[2], yPol[2]);
//			     buffGraphics.fillPolygon(xPol,yPol, 3);
			     }
			    if (Norm1z[i][j][1] > 0){
			     xPol[0] = w2 + (int)vert1[i][j][0];
			     xPol[1] = w2 + (int)vert1[i][j+1][0];
			     xPol[2] = w2 + (int)vert1[i+1][j+1][0];
			     yPol[0] = h2 - (int)vert1[i][j][1];
			     yPol[1] = h2 - (int)vert1[i][j+1][1];
			     yPol[2] = h2 - (int)vert1[i+1][j+1][1];
			     buffGraphics.setColor(col[iCol[i][j][1]][(int)(Norm1z[i][j][1])]);
			     buffGraphics.fillTriangle(xPol[0], yPol[0], xPol[1], yPol[1], xPol[2], yPol[2]);} }
			  painted = true;
			  buffImage=new Texture(buffGraphics, true);
			  
			 }
//		 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		 	batch.draw(buffImage, getX(), getY());
		 		
		 		
		
		/*if(!painted){
			buffGraphics.setColor(col(255, 0, 0));
			buffGraphics.fill();
			buffImage=new Texture(buffGraphics);
			 painted = true;
		}batch.draw(buffImage, getX(), getY());*/
		
//			 g.drawImage(buffImage, 0, 0, this);
	}

	
	@Override
	public void dispose() {
		// TODO Auto-generated method stub
		buffGraphics.dispose();
		buffImage.dispose();
	}
	/***************************************************/
	/*public void init2(){
		  w = getSize().width;  h = getSize().height;   w2 = w/2;  h2 = h/2;
		  String s=getParameter("N");  if (s != null) n = Integer.parseInt(s);
		  xPol = new int[3];  yPol = new int[3];
		  buffImage = createImage(w, h);   buffGraphics = buffImage.getGraphics();
		  col = new Color[4][256];
		  for (int i = 0; i < 256; i++){
		    col[0][i] = new Color(0, 0, i);
		    col[1][i] = new Color(0, (i*220)/256, 0);
		    col[2][i] = new Color((i*150)/256, (i*150)/256, (i*50)/256);
		    col[3][i] = new Color(i, i, i);}
		  s = getParameter("bgColor"); if (s != null){
		  StringTokenizer st = new StringTokenizer(s);
		   int red = Integer.parseInt(st.nextToken());
		   int green = Integer.parseInt(st.nextToken());
		   int blue = Integer.parseInt(st.nextToken());
		   setBackground( new Color(red, green, blue));}
		  else setBackground(new Color(255,255,255));
		  addMouseListener(this);
		  addMouseMotionListener(this);
		  setup();
		  for(int i=0;i<4;i++){
				for(Color c:col[i]){
					int a=c.getRed();
					int b=c.getGreen();
					int g=c.getBlue();
					int r=			c.getAlpha();
					int m=(a << 24) | (b << 16) | (g << 8) | r;
					System.out.println(m);
				}
			}
		}*/
	public void rotate2(){
		  double ct = Math.cos(fiX), cf = Math.cos(fiY),
		         st = Math.sin(fiX), sf = Math.sin(fiY),
		         m00 =  scale*cf,    m02 =  scale*sf,
		         m10 = scale*st*sf, m11 =  scale*ct, m12 = -scale*st*cf;
		         m20 = -ct*sf; m21 = st; m22 = ct*cf;
		  for (int i = 0; i < n1; i++)
		   for (int j = 0; j < n1; j++){
		    vert1[i][j][0] = m00*vert[i][j][0] + m02*vert[i][j][2];
		    vert1[i][j][1] = m10*vert[i][j][0] + m11*vert[i][j][1] + m12*vert[i][j][2];}
		  for (int i = 0; i < n; i++)
		   for (int j = 0; j < n; j++)
		    for (int k = 0; k < 2; k++)
		     Norm1z[i][j][k] = m20*Norm[i][j][k][0] + m21*Norm[i][j][k][1] +
		      m22*Norm[i][j][k][2];
		  painted = false;
		}
	public void iterate2(){
		  int nc=n, Max=n1*n1, ncn1;
		  double Min=-1;
		  M = new double[Max];
		  for (int i=n+2; i < n*n1-1; i++) M[i] = Min;
		  for (int i=2*n1; i < n*n1; i += n1) M[i] = M[i-1] = 0;
		  while ( (nc /= 2) >= 1){
		    ncn1 = nc*n1;
		    for (int j=ncn1; j < Max; j += ncn1+ncn1){
		      for (int i= nc; i < n; i += nc+nc){
		        if (M[i+j]==Min)
		           M[i+j] = (M[i+j+nc-ncn1] + M[i+j-nc+ncn1])/2.+R();
		        if (M[i+j+nc]==Min)
		           M[i+j+nc] = (M[i+j+nc+ncn1] + M[i+j+nc-ncn1])/2.+R();
		        if (M[i+j+ncn1]==Min)
		           M[i+j+ncn1] = (M[i+j-nc+ncn1] + M[i+j+nc+ncn1])/2.+R(); }}
		    rnd /= 2.;}
		}
	public void setup2(){
		  rnd = 1;
		  n1 = n+1;
		  iterate();
		  vert = new double[n1][n1][3];  vert1 = new double[n1][n1][2];
		  double dx = w/(double)n;
		  int t = 0;
		  for (int i = 0; i < n1; i++) 
		   for (int j = 0; j < n1; j++){
		    vert[i][j][0] = dx*i - w2;  vert[i][j][2] = dx*j - w2;
		    double mi = M[t++];
		    if (mi < 0) mi = .01*Math.random();
		    vert[i][j][1] = w*mi - w2/2;}
		  Norm = new double[n1][n1][2][3];  Norm1z = new double[n1][n1][2];
		  iCol = new int[n][n][2];
		  for (int i = 0; i < n; i++)
		   for (int j = 0; j < n; j++){
		     double s =
		      ((vert[i][j][1] + vert[i+1][j][1] + vert[i+1][j+1][1])/3 + w2/2)/w;
		     if (s < .01) iCol[i][j][0] = 0;
		     else if (s+.1*Math.random() > .35) iCol[i][j][0] = 3;
		      else if (s+.1*Math.random() > .15)  iCol[i][j][0] = 2;
		       else  iCol[i][j][0] = 1;
		     s = ((vert[i][j][1] + vert[i][j+1][1] + vert[i+1][j+1][1])/3 + w2/2)/w;
		     if (s < .01) iCol[i][j][1] = 0;
		     else if (s+.1*Math.random() > .35) iCol[i][j][1] = 3;
		      else if (s+.1*Math.random() > .15)  iCol[i][j][1] = 2;
		       else  iCol[i][j][1] = 1;
		    Norm[i][j][0][0] = vert[i][j][1] - vert[i+1][j][1];
		    Norm[i][j][0][1] = dx;
		    Norm[i][j][0][2] = vert[i+1][j][1] - vert[i+1][j+1][1];
		    double mod = Math.sqrt(Norm[i][j][0][0]*Norm[i][j][0][0] + Norm[i][j][0][1]*
		     Norm[i][j][0][1] + Norm[i][j][0][2]*Norm[i][j][0][2]) / 255.5;
		    Norm[i][j][0][0] /= mod; Norm[i][j][0][1] /= mod; Norm[i][j][0][2] /= mod;
		    Norm[i][j][1][0] = vert[i][j+1][1] - vert[i+1][j+1][1];
		    Norm[i][j][1][1] = dx;
		    Norm[i][j][1][2] = vert[i][j][1] - vert[i][j+1][1];
		    mod = Math.sqrt(Norm[i][j][1][0]*Norm[i][j][1][0] + Norm[i][j][1][1]*
		     Norm[i][j][1][1] + Norm[i][j][1][2]*Norm[i][j][1][2]) / 255.5;
		    Norm[i][j][1][0] /= mod; Norm[i][j][1][1] /= mod; Norm[i][j][1][2] /= mod;}
		  rotate();
		}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章