圆锥体

来源:互联网 发布:杭州软件信息技术开发 编辑:程序博客网 时间:2024/05/17 01:02

效果图如下:




1、首先给出的是圆锥面中的顶点坐标、纹理坐标和法向量生成的相关代码:

import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import android.opengl.GLES20;//圆锥侧面public class ConeSide {int mProgram;//自定义渲染管线着色器程序id    int muMVPMatrixHandle;//总变换矩阵引用    int maPositionHandle; //顶点位置属性引用     int maTexCoorHandle; //顶点纹理坐标属性引用        int muMMatrixHandle;//位置、旋转、缩放变换矩阵    int maCameraHandle; //摄像机位置属性引用    int maNormalHandle; //顶点法向量属性引用    int maLightLocationHandle;//光源位置属性引用         String mVertexShader;//顶点着色器代码脚本     String mFragmentShader;//片元着色器代码脚本FloatBuffer   mVertexBuffer;//顶点坐标数据缓冲FloatBuffer   mTexCoorBuffer;//顶点纹理坐标数据缓冲FloatBuffer   mNormalBuffer;//顶点法向量数据缓冲    int vCount=0;       float xAngle=0;//绕x轴旋转的角度    float yAngle=0;//绕y轴旋转的角度    float zAngle=0;//绕z轴旋转的角度        public ConeSide(MySurfaceView mv,float scale,float r,float h,int n)    {        //调用初始化顶点数据的initVertexData方法    initVertexData(scale,r,h,n);    //调用初始化着色器的intShader方法       initShader(mv);    }        //自定义初始化顶点坐标数据的方法    public void initVertexData(    float scale,//尺寸大小    float r,//半径    float h,//高度    int n//切分的份数    )    {    r=scale*r;    h=scale*h;float angdegSpan=360.0f/n;vCount=3*n*4;//顶点个数,共有3*n*4个三角形,每个三角形都有三个顶点//坐标数据初始化float[] vertices=new float[vCount*3];float[] textures=new float[vCount*2];//顶点纹理S、T坐标值数组float[] normals=new float[vertices.length];//法向量数组//坐标数据初始化int count=0;int stCount=0;int norCount=0;for(float angdeg=0;Math.ceil(angdeg)<360;angdeg+=angdegSpan)//侧面{double angrad=Math.toRadians(angdeg);//当前弧度double angradNext=Math.toRadians(angdeg+angdegSpan);//下一弧度//顶点(圆锥最高的点)vertices[count++]=0; vertices[count++]=h; vertices[count++]=0;//纹理坐标textures[stCount++]=0.5f;//st坐标textures[stCount++]=0;//当前点vertices[count++]=(float) (-r*Math.sin(angrad));vertices[count++]=0;vertices[count++]=(float) (-r*Math.cos(angrad));//纹理坐标textures[stCount++]=(float) (angrad/(2*Math.PI));textures[stCount++]=1;//下一点vertices[count++]=(float) (-r*Math.sin(angradNext));vertices[count++]=0;vertices[count++]=(float) (-r*Math.cos(angradNext));//纹理坐标textures[stCount++]=(float) (angradNext/(2*Math.PI));textures[stCount++]=1;}//法向量数据的初始化for(int i=0;i<vertices.length;i=i+3){//如果当前的顶点为圆锥的最高点if(vertices[i]==0&&vertices[i+1]==h&&vertices[i+2]==0){normals[norCount++]=0;normals[norCount++]=1;normals[norCount++]=0;}else{//当前的顶点为底面圆上的顶点float [] norXYZ=VectorUtil.calConeNormal(//通过三个顶点求出法向量0, 0, 0, //底面圆的中心点vertices[i], vertices[i+1], vertices[i+2], //当前的顶点坐标0, h, 0);//顶点坐标(圆锥最高点)normals[norCount++]=norXYZ[0];normals[norCount++]=norXYZ[1];normals[norCount++]=norXYZ[2];}}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 cbb = ByteBuffer.allocateDirect(textures.length*4);//创建顶点纹理数据缓冲        cbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序        mTexCoorBuffer = cbb.asFloatBuffer();//转换为float型缓冲        mTexCoorBuffer.put(textures);//向缓冲区中放入顶点纹理数据        mTexCoorBuffer.position(0);//设置缓冲区起始位置    }    //自定义初始化着色器的initShader方法    public void initShader(MySurfaceView mv)    {    //加载顶点着色器的脚本内容        mVertexShader=ShaderUtil.loadFromAssetsFile("vertex_tex_light.sh", mv.getResources());        //加载片元着色器的脚本内容        mFragmentShader=ShaderUtil.loadFromAssetsFile("frag_tex_light.sh", mv.getResources());          //基于顶点着色器与片元着色器创建程序        mProgram = createProgram(mVertexShader, mFragmentShader);        //获取程序中顶点位置属性引用id          maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");        //获取程序中顶点纹理坐标属性引用id          maTexCoorHandle= GLES20.glGetAttribLocation(mProgram, "aTexCoor");        //获取程序中总变换矩阵引用id        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");                //获取程序中顶点法向量属性引用id          maNormalHandle= GLES20.glGetAttribLocation(mProgram, "aNormal");         //获取程序中摄像机位置引用id        maCameraHandle=GLES20.glGetUniformLocation(mProgram, "uCamera");         //获取程序中光源位置引用id        maLightLocationHandle=GLES20.glGetUniformLocation(mProgram, "uLightLocation");         //获取位置、旋转变换矩阵引用id        muMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix");                      }        public void drawSelf(int texId)    {             //制定使用某套shader程序     GLES20.glUseProgram(mProgram);                 //将最终变换矩阵传入shader程序         GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);         //将位置、旋转变换矩阵传入shader程序         GLES20.glUniformMatrix4fv(muMMatrixHandle, 1, false, MatrixState.getMMatrix(), 0);          //将摄像机位置传入shader程序            GLES20.glUniform3fv(maCameraHandle, 1, MatrixState.cameraFB);         //将光源位置传入shader程序            GLES20.glUniform3fv(maLightLocationHandle, 1, MatrixState.lightPositionFB);                  //传送顶点位置数据         GLES20.glVertexAttribPointer           (         maPositionHandle,            3,          GLES20.GL_FLOAT,          false,                3*4,                   mVertexBuffer         );                //传送顶点纹理坐标数据         GLES20.glVertexAttribPointer           (        maTexCoorHandle,          2,          GLES20.GL_FLOAT,          false,                2*4,                   mTexCoorBuffer         );          //传送顶点法向量数据         GLES20.glVertexAttribPointer           (        maNormalHandle,          4,          GLES20.GL_FLOAT,          false,                3*4,                   mNormalBuffer         );                   //启用顶点位置数据         GLES20.glEnableVertexAttribArray(maPositionHandle);         //启用顶点纹理数据         GLES20.glEnableVertexAttribArray(maTexCoorHandle);           //启用顶点法向量数据         GLES20.glEnableVertexAttribArray(maNormalHandle);         //绑定纹理         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);                  //绘制纹理矩形         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);     }}

2、接着给出的是用于计算圆锥面顶点法向量的工具类:

public class VectorUtil {//计算圆锥顶点法向量的方法public static float[] calConeNormal(//三角形三个顶点坐标float x0,float y0,float z0,//A,中心点(底面圆的圆心)float x1,float y1,float z1,//B,底面圆上一点float x2,float y2,float z2 //C,顶点(最高的点)){float[] a={x1-x0, y1-y0, z1-z0};//向量ABfloat[] b={x2-x0, y2-y0, z2-z0};//向量ACfloat[] c={x2-x1, y2-y1, z2-z1};//向量BC//先球垂直于平面ABC的向量kfloat[] k=crossTwoVectors(a,b);//将c和k做叉乘,得出所求向量dfloat[] d=crossTwoVectors(c,k);return normalizeVector(d);//返回规格化后的法向量}//向量规格化的方法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};//返回法向量}}


0 0
原创粉丝点击