zoukankan      html  css  js  c++  java
  • 几何球

    效果图如下:




    1、首先给出的是用于初始化几何球顶点坐标数据的initvertexData方法:

     <pre name="code" class="java">  
        //自定义的初始化顶点数据的方法
        public void initVertexData(float scale, float aHalf, int n) //大小,黄金长方形长边的一半,分段数
    	{
    		aHalf*=scale;		//长边的一半
    		bHalf=aHalf*0.618034f;		//短边的一半
    		r=(float) Math.sqrt(aHalf*aHalf+bHalf*bHalf);
    		vCount=3*20*n*n;//顶点个数,共有20个三角形,每个三角形都有三个顶点
    		//正20面体坐标数据初始化
    		ArrayList<Float> alVertix20=new ArrayList<Float>();//正20面体的顶点列表(未卷绕)
    		ArrayList<Integer> alFaceIndex20=new ArrayList<Integer>();//正20面体组织成面的顶点的索引值列表(按逆时针卷绕)
    		//正20面体顶点
    		initAlVertix20(alVertix20,aHalf,bHalf);
    		//正20面体索引
    		initAlFaceIndex20(alFaceIndex20);
    		//计算卷绕顶点
    		float[] vertices20=VectorUtil.cullVertex(alVertix20, alFaceIndex20);//只计算顶点
    
    		//坐标数据初始化
    		ArrayList<Float> alVertix=new ArrayList<Float>();//原顶点列表(未卷绕)
    		ArrayList<Integer> alFaceIndex=new ArrayList<Integer>();//组织成面的顶点的索引值列表(按逆时针卷绕)
    		int vnCount=0;//前i-1行前所有顶点数的和
    		for(int k=0;k<vertices20.length;k+=9)//对正20面体每个大三角形循环
    		{
    			float [] v1=new float[]{vertices20[k+0], vertices20[k+1], vertices20[k+2]};
    			float [] v2=new float[]{vertices20[k+3], vertices20[k+4], vertices20[k+5]};
    			float [] v3=new float[]{vertices20[k+6], vertices20[k+7], vertices20[k+8]};
    			//顶点
    			for(int i=0;i<=n;i++)
    			{
    				float[] viStart=VectorUtil.devideBall(r, v1, v2, n, i);
    				float[] viEnd=VectorUtil.devideBall(r, v1, v3, n, i);
    				for(int j=0;j<=i;j++)
    				{
    					float[] vi=VectorUtil.devideBall(r, viStart, viEnd, i, j);
    					alVertix.add(vi[0]); alVertix.add(vi[1]); alVertix.add(vi[2]);
    				}
    			}
    			//索引
    			for(int i=0;i<n;i++)
    			{
    				if(i==0){//若是第0行,直接加入卷绕后顶点索引012
    					alFaceIndex.add(vnCount+0); alFaceIndex.add(vnCount+1);alFaceIndex.add(vnCount+2);
    					vnCount+=1;
    					if(i==n-1){//如果是每个大三角形的最后一次循环,将下一列的顶点个数也加上
    						vnCount+=2;
    					}
    					continue;
    				}
    				int iStart=vnCount;//第i行开始的索引
    				int viCount=i+1;//第i行顶点数
    				int iEnd=iStart+viCount-1;//第i行结束索引
    				
    				int iStartNext=iStart+viCount;//第i+1行开始的索引
    				int viCountNext=viCount+1;//第i+1行顶点数
    				int iEndNext=iStartNext+viCountNext-1;//第i+1行结束的索引
    				//前面的四边形
    				for(int j=0;j<viCount-1;j++)
    				{
    					int index0=iStart+j;//四边形的四个顶点索引
    					int index1=index0+1;
    					int index2=iStartNext+j;
    					int index3=index2+1;
    					alFaceIndex.add(index0); alFaceIndex.add(index2);alFaceIndex.add(index3);//加入前面的四边形
    					alFaceIndex.add(index0); alFaceIndex.add(index3);alFaceIndex.add(index1);				
    				}// j
    				alFaceIndex.add(iEnd); alFaceIndex.add(iEndNext-1);alFaceIndex.add(iEndNext); //最后一个三角形
    				vnCount+=viCount;//第i行前所有顶点数的和
    				if(i==n-1){//如果是每个大三角形的最后一次循环,将下一列的顶点个数也加上
    					vnCount+=viCountNext;
    				}
    			}// i
    		}// k
    		
    		//计算卷绕顶点
    		float[] vertices=VectorUtil.cullVertex(alVertix, alFaceIndex);//只计算顶点
    		float[] normals=vertices;//顶点就是法向量
    		
    		//纹理
    		//正20面体纹理坐标数据初始化
    		ArrayList<Float> alST20=new ArrayList<Float>();//正20面体的纹理坐标列表(未卷绕)
    		ArrayList<Integer> alTexIndex20=new ArrayList<Integer>();//正20面体组织成面的纹理坐标的索引值列表(按逆时针卷绕)
    		//正20面体纹理坐标
    		float sSpan=1/5.5f;//每个纹理三角形的边长
    		float tSpan=1/3.0f;//每个纹理三角形的高
    		//按正二十面体的平面展开图计算纹理坐标
    		for(int i=0;i<5;i++){
    			alST20.add(sSpan+sSpan*i); alST20.add(0f);
    		}
    		for(int i=0;i<6;i++){
    			alST20.add(sSpan/2+sSpan*i); alST20.add(tSpan);
    		}
    		for(int i=0;i<6;i++){
    			alST20.add(sSpan*i); alST20.add(tSpan*2);
    		}
    		for(int i=0;i<5;i++){
    			alST20.add(sSpan/2+sSpan*i); alST20.add(tSpan*3);
    		}
    		//正20面体索引
    		initAlTexIndex20(alTexIndex20);
    
    		//计算卷绕纹理坐标
    		float[] st20=VectorUtil.cullTexCoor(alST20, alTexIndex20);//只计算纹理坐标
    		ArrayList<Float> alST=new ArrayList<Float>();//原纹理坐标列表(未卷绕)
    		for(int k=0;k<st20.length;k+=6)
    		{
    			float [] st1=new float[]{st20[k+0], st20[k+1], 0};//三角形的纹理坐标
    			float [] st2=new float[]{st20[k+2], st20[k+3], 0};
    			float [] st3=new float[]{st20[k+4], st20[k+5], 0};
    			for(int i=0;i<=n;i++)
    			{
    				float[] stiStart=VectorUtil.devideLine(st1, st2, n, i);
    				float[] stiEnd=VectorUtil.devideLine(st1, st3, n, i);
    				for(int j=0;j<=i;j++)
    				{
    					float[] sti=VectorUtil.devideLine(stiStart, stiEnd, i, j);
    					//将纹理坐标加入列表
    					alST.add(sti[0]); alST.add(sti[1]);
    				}
    			}
    		}
    		//计算卷绕后纹理坐标
    		float[] textures=VectorUtil.cullTexCoor(alST, alFaceIndex);
    		
    		//顶点坐标数据初始化
    		ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);//创建顶点坐标数据缓冲
            vbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序
            mVertexBuffer = vbb.asFloatBuffer();//转换为float型缓冲
            mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
            mVertexBuffer.position(0);//设置缓冲区起始位置
            //法向量数据初始化  
            ByteBuffer nbb = ByteBuffer.allocateDirect(normals.length*4);//创建顶点法向量数据缓冲
            nbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序
            mNormalBuffer = nbb.asFloatBuffer();//转换为float型缓冲
            mNormalBuffer.put(normals);//向缓冲区中放入顶点法向量数据
            mNormalBuffer.position(0);//设置缓冲区起始位置
            //st坐标数据初始化		
            ByteBuffer tbb = ByteBuffer.allocateDirect(textures.length*4);//创建顶点纹理数据缓冲
            tbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序
            mTexCoorBuffer = tbb.asFloatBuffer();//转换为float型缓冲
            mTexCoorBuffer.put(textures);//向缓冲区中放入顶点纹理数据
            mTexCoorBuffer.position(0);//设置缓冲区起始位置
    	}
        

    
    2、接着给出的是初始化正二十面体顶点坐标数据的initAI20方法:
    

      public void initAlVertix20(ArrayList<Float> alVertix20,float aHalf,float bHalf){
        	
    		alVertix20.add(0f); alVertix20.add(aHalf); alVertix20.add(-bHalf);//顶正棱锥顶点
    		
    		alVertix20.add(0f); alVertix20.add(aHalf); alVertix20.add(bHalf);//棱柱上的点
    		alVertix20.add(aHalf); alVertix20.add(bHalf); alVertix20.add(0f);
    		alVertix20.add(bHalf); alVertix20.add(0f); alVertix20.add(-aHalf);
    		alVertix20.add(-bHalf); alVertix20.add(0f); alVertix20.add(-aHalf);
    		alVertix20.add(-aHalf); alVertix20.add(bHalf); alVertix20.add(0f);
    		
    		alVertix20.add(-bHalf); alVertix20.add(0f); alVertix20.add(aHalf);
    		alVertix20.add(bHalf); alVertix20.add(0f); alVertix20.add(aHalf);
    		alVertix20.add(aHalf); alVertix20.add(-bHalf); alVertix20.add(0f);
    		alVertix20.add(0f); alVertix20.add(-aHalf); alVertix20.add(-bHalf);
    		alVertix20.add(-aHalf); alVertix20.add(-bHalf); alVertix20.add(0f);
    		
    		alVertix20.add(0f); alVertix20.add(-aHalf); alVertix20.add(bHalf);//底棱锥顶点
    		
        }

    3、初始化构成正二十面体的20个三角形顶点坐标编号数据的initAIfaceIndex20的方法:

     public void initAlFaceIndex20(ArrayList<Integer> alFaceIndex20){ //初始化正二十面体的顶点索引数据
        	
    		alFaceIndex20.add(0); alFaceIndex20.add(1); alFaceIndex20.add(2);
    		alFaceIndex20.add(0); alFaceIndex20.add(2); alFaceIndex20.add(3);
    		alFaceIndex20.add(0); alFaceIndex20.add(3); alFaceIndex20.add(4);
    		alFaceIndex20.add(0); alFaceIndex20.add(4); alFaceIndex20.add(5);
    		alFaceIndex20.add(0); alFaceIndex20.add(5); alFaceIndex20.add(1);
    		
    		alFaceIndex20.add(1); alFaceIndex20.add(6); alFaceIndex20.add(7);
    		alFaceIndex20.add(1); alFaceIndex20.add(7); alFaceIndex20.add(2);
    		alFaceIndex20.add(2); alFaceIndex20.add(7); alFaceIndex20.add(8);
    		alFaceIndex20.add(2); alFaceIndex20.add(8); alFaceIndex20.add(3);
    		alFaceIndex20.add(3); alFaceIndex20.add(8); alFaceIndex20.add(9);
    		alFaceIndex20.add(3); alFaceIndex20.add(9); alFaceIndex20.add(4);
    		alFaceIndex20.add(4); alFaceIndex20.add(9); alFaceIndex20.add(10);
    		alFaceIndex20.add(4); alFaceIndex20.add(10); alFaceIndex20.add(5);
    		alFaceIndex20.add(5); alFaceIndex20.add(10); alFaceIndex20.add(6);
    		alFaceIndex20.add(5); alFaceIndex20.add(6); alFaceIndex20.add(1);
    		
    		alFaceIndex20.add(6); alFaceIndex20.add(11); alFaceIndex20.add(7);
    		alFaceIndex20.add(7); alFaceIndex20.add(11); alFaceIndex20.add(8);
    		alFaceIndex20.add(8); alFaceIndex20.add(11); alFaceIndex20.add(9);
    		alFaceIndex20.add(9); alFaceIndex20.add(11); alFaceIndex20.add(10);
    		alFaceIndex20.add(10); alFaceIndex20.add(11); alFaceIndex20.add(6);
        }

    4、初始化构成正二十面体的20个三角形各个顶点坐标编号数据的initAIfaceIndex20的方法:


     public void initAlTexIndex20(ArrayList<Integer> alTexIndex20) //初始化顶点纹理索引数据
        {
    		alTexIndex20.add(0); alTexIndex20.add(5); alTexIndex20.add(6);
    		alTexIndex20.add(1); alTexIndex20.add(6); alTexIndex20.add(7);
    		alTexIndex20.add(2); alTexIndex20.add(7); alTexIndex20.add(8);
    		alTexIndex20.add(3); alTexIndex20.add(8); alTexIndex20.add(9);
    		alTexIndex20.add(4); alTexIndex20.add(9); alTexIndex20.add(10);
    		
    		alTexIndex20.add(5); alTexIndex20.add(11); alTexIndex20.add(12);
    		alTexIndex20.add(5); alTexIndex20.add(12); alTexIndex20.add(6);
    		alTexIndex20.add(6); alTexIndex20.add(12); alTexIndex20.add(13);
    		alTexIndex20.add(6); alTexIndex20.add(13); alTexIndex20.add(7);
    		alTexIndex20.add(7); alTexIndex20.add(13); alTexIndex20.add(14);
    		alTexIndex20.add(7); alTexIndex20.add(14); alTexIndex20.add(8);
    		alTexIndex20.add(8); alTexIndex20.add(14); alTexIndex20.add(15);
    		alTexIndex20.add(8); alTexIndex20.add(15); alTexIndex20.add(9);
    		alTexIndex20.add(9); alTexIndex20.add(15); alTexIndex20.add(16);
    		alTexIndex20.add(9); alTexIndex20.add(16); alTexIndex20.add(10);
    		
    		alTexIndex20.add(11); alTexIndex20.add(17); alTexIndex20.add(12);
    		alTexIndex20.add(12); alTexIndex20.add(18); alTexIndex20.add(13);
    		alTexIndex20.add(13); alTexIndex20.add(19); alTexIndex20.add(14);
    		alTexIndex20.add(14); alTexIndex20.add(20); alTexIndex20.add(15);
    		alTexIndex20.add(15); alTexIndex20.add(21); alTexIndex20.add(16);
        	
        }
        

    5、最后给出的是向量计算及圆弧拆分相关方法所属的工具类——VectorUtil:

    import java.util.ArrayList;
    
    //计算三角形法向量的工具类
    public class VectorUtil {
    	//向量规格化的方法
    	public static float[] normalizeVector(float [] vec){
    		float mod=module(vec);
    		return new float[]{vec[0]/mod, vec[1]/mod, vec[2]/mod};//返回规格化后的向量
    	}
    	//求向量的模的方法
    	public static float module(float [] vec){
    		return (float) Math.sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
    	}
    	//两个向量叉乘的方法
    	public static float[] crossTwoVectors(float[] a, float[] b)
    	{
    		float x=a[1]*b[2]-a[2]*b[1];
    		float y=a[2]*b[0]-a[0]*b[2];
    		float z=a[0]*b[1]-a[1]*b[0];
    		return new float[]{x, y, z};//返回叉乘结果
    	}
    	//两个向量点乘的方法
    	public static float dotTwoVectors(float[] a, float[] b)
    	{
    		return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];//返回点乘结果
    	}
    
    	//根据原纹理坐标和索引,计算卷绕后的纹理的方法
    	public static float[] cullTexCoor(
    			ArrayList<Float> alST,//原纹理坐标列表(未卷绕)
    			ArrayList<Integer> alTexIndex//组织成面的纹理坐标的索引值列表(按逆时针卷绕)
    			)
    	{
    		float[] textures=new float[alTexIndex.size()*2];
    		//生成顶点的数组
    		int stCount=0;
    		for(int i:alTexIndex){
    			textures[stCount++]=alST.get(2*i);
    			textures[stCount++]=alST.get(2*i+1);
    		}
    		return textures;
    	}
    	public static float[] cullVertex(
    			ArrayList<Float> alv,//原顶点列表(未卷绕)
    			ArrayList<Integer> alFaceIndex//组织成面的顶点的索引值列表(按逆时针卷绕)
    			)
    	{
    		float[] vertices=new float[alFaceIndex.size()*3];
    		//生成顶点的数组
    		int vCount=0;
    		for(int i:alFaceIndex){
    			vertices[vCount++]=alv.get(3*i);
    			vertices[vCount++]=alv.get(3*i+1);
    			vertices[vCount++]=alv.get(3*i+2);
    		}
    		return vertices;
    	}
    	//计算圆弧的n等分点坐标的方法
    	public static float[] devideBall(
    			float r, //球的半径
    			float[] start, //指向圆弧起点的向量
    			float[] end, //指向圆弧终点的向量
    			int n, //圆弧分的份数
    			int i //求第i份在圆弧上的坐标(i为0和n时分别代表起点和终点坐标)
    			)
    	{
    		/* 
    		 * 先求出所求向量的规格化向量,再乘以半径r即可
    		 * s0*x+s1*y+s2*z=cos(angle1)//根据所求向量和起点向量夹角为angle1---1式
    		 * e0*x+e1*y+e2*z=cos(angle2)//根据所求向量和终点向量夹角为angle2---2式
    		 * x*x+y*y+z*z=1//所球向量的规格化向量模为1---3式
    		 * x*n0+y*n1+z*n2=0//所球向量与法向量垂直---4式
    		 * 算法为:将1、2两式用换元法得出x=a1+b1*z,y=a2+b2*z的形式,
    		 * 将其代入4式求出z,再求出x、y,最后将向量(x,y,z)乘以r即为所求坐标。
    		 * 1式和2式是将3式代入得到的,因此已经用上了。
    		 * 由于叉乘的结果做了分母,因此起点、终点、球心三点不能共线
    		 * 注意结果是将劣弧等分
    		 */
    		//先将指向起点和终点的向量规格化
    		float[] s=VectorUtil.normalizeVector(start);
    		float[] e=VectorUtil.normalizeVector(end);
    		if(n==0){//如果n为零,返回起点坐标
    			return new float[]{s[0]*r, s[1]*r, s[2]*r};
    		}
    		//求两个向量的夹角
    		double angrad=Math.acos(VectorUtil.dotTwoVectors(s, e));//起点终点向量夹角
    		double angrad1=angrad*i/n;//所球向量和起点向量的夹角
    		double angrad2=angrad-angrad1;//所球向量和终点向量的夹角
    		//求法向量normal
    		float[] normal=VectorUtil.crossTwoVectors(s, e);
    		//用doolittle分解算法解n元一次线性方程组
    		double matrix[][]={//增广矩阵
    				{s[0],s[1],s[2],Math.cos(angrad1)},
    				{e[0],e[1],e[2],Math.cos(angrad2)},
    				{normal[0],normal[1],normal[2],0}  
    		};
    		double result[]=MyMathUtil.doolittle(matrix);//解
    		//求规格化向量xyz的值
    		float x=(float) result[0];
    		float y=(float) result[1];
    		float z=(float) result[2];
    		//返回圆弧的n等分点坐标
    		return new float[]{x*r, y*r, z*r};
    	}
    	//计算线段的n等分点坐标的方法
    	public static float[] devideLine(
    			float[] start, //线段起点坐标
    			float[] end, //线段终点坐标
    			int n, //线段分的份数
    			int i //求第i份在线段上的坐标(i为0和n时分别代表起点和终点坐标)
    			)
    	{
    		if(n==0){//如果n为零,返回起点坐标
    			return start;
    		}
    		//求起点到终点的向量
    		float[] ab=new float[]{end[0]-start[0], end[1]-start[1], end[2]-start[2]};
    		//求向量比例
    		float vecRatio=i/(float)n;
    		//求起点到所求点的向量
    		float[] ac=new float[]{ab[0]*vecRatio, ab[1]*vecRatio, ab[2]*vecRatio};
    		//所求坐标
    		float x=start[0]+ac[0];
    		float y=start[1]+ac[1];
    		float z=start[2]+ac[2];
    		//返回线段的n等分点坐标
    		return new float[]{x, y, z};
    	}
    }
    




  • 相关阅读:
    背水一战 Windows 10 (90)
    背水一战 Windows 10 (89)
    背水一战 Windows 10 (88)
    背水一战 Windows 10 (87)
    背水一战 Windows 10 (86)
    背水一战 Windows 10 (85)
    背水一战 Windows 10 (84)
    背水一战 Windows 10 (83)
    背水一战 Windows 10 (82)
    背水一战 Windows 10 (81)
  • 原文地址:https://www.cnblogs.com/Anzhongliu/p/6092110.html
Copyright © 2011-2022 走看看