效果


实现

使用openGL ES 2.0,分别画出三棱锥的4个面(包括底面),分别给4个面涂上纹理。

着色器

顶点着色器:
    private final String mVertexShaderWithTexture=            "attribute vec3 aPosition;\n"            +"uniform mat4 uMvp;\n"            +"attribute vec2 aTextureCoord;\n"            +"varying vec2 vTextureCoord;\n"            +"void main(){\n"            +"  vTextureCoord=aTextureCoord;"            +"  vec4 vertex=vec4(aPosition[0],aPosition[1],aPosition[2],1.0);"            +"  gl_Position = uMvp*vertex;\n"            +"}";
aPosition用于存放顶点坐标,uMvp为准换矩阵,aTextureCoord用于存放纹理坐标; 片元着色器:
    private final String mFragmentShaderWithTexture=            "precision mediump float;\n"            +"uniform sampler2D uSample;\n"            +"varying vec2 vTextureCoord;\n"            +"void main(){\n"            +"  gl_FragColor =texture2D(uSample,vTextureCoord);\n"            +"}";

uSample为纹理采集器,vTextureCoord是顶点着色器传过来的经过插值后的顶点坐标。 由内置方法texture2D,通过纹理采集器和对应纹理坐标得到纹理值给gl_FragColor赋值。

创建渲染程序

通过加载着色器源码,编译着色器获取顶点和片元着色器; 创建渲染程序,为其添加着色器,链接程序,从而得到需要使用的渲染程序。 基础的东西,只罗列了步骤。

绘前准备

获取着色器中对应变量的引用:
            mAPositionLoc=GLES20.glGetAttribLocation(mShader,"aPosition");            mUMvpLoc=GLES20.glGetUniformLocation(mShader,"uMvp");            mUSamplerLoc=GLES20.glGetUniformLocation(mShader,"uSample");            mATextureCoordLoc=GLES20.glGetAttribLocation(mShader,"aTextureCoord");
准备数据:
            mVertexFB=transFloat(mVertex);            parseVertexInd();            mTextureCoordFB=transFloat(mTextureCoords);
其中,transFloat()将float的数组转换为FloatBuffer; 因为要单独绘制出每个面,parseVertexInd()将顶点索引数组划分为4个索引数组。
    private FloatBuffer transFloat(float[] floatArray){        ByteBuffer bb = ByteBuffer.allocateDirect(floatArray.length * 4);        bb.order(ByteOrder.nativeOrder());        FloatBuffer fb = bb.asFloatBuffer();        fb.put(floatArray);        fb.position(0);        return fb;    }
    private void parseVertexInd(){        m1stInd=Arrays.copyOfRange(mVertexInd,0,3);        m1stSB=transShort(m1stInd);        m2ndInd=Arrays.copyOfRange(mVertexInd,3,6);        m2ndSB=transShort(m2ndInd);        m3rdInd=Arrays.copyOfRange(mVertexInd,6,9);        m3rdSB=transShort(m3rdInd);        m4thInd=Arrays.copyOfRange(mVertexInd,9,12);        m4thSB=transShort(m4thInd);    }

开始绘制

        GLES20.glUseProgram(mShader);        GLES20.glEnable(GLES20.GL_CULL_FACE);        GLES20.glCullFace(GLES20.GL_BACK);        GLES20.glFrontFace(GLES20.GL_CCW);
使用渲染程序,剔除背面,且设置逆时针方向绘制的面为正面。

设置转换矩阵

            Matrix.setIdentityM(mRotateM,0);            Matrix.multiplyMM(mRotateM,0,mRotateY,0,mRotateX,0);            Matrix.multiplyMM(mRotateM,0,mRotateZ,0,mRotateM,0);            Matrix.setIdentityM(mViewM,0);            Matrix.setLookAtM(mViewM,0,mEyeX,mEyeY,mEyeZ,mDstX,mDstY,mDstZ,mUpX,mUpY,mUpZ);            Matrix.setIdentityM(mProjectionM,0);            Matrix.frustumM(mProjectionM,0,-mFrustumRatio/mDisplayRatio,mFrustumRatio/mDisplayRatio,-mFrustumRatio,                    mFrustumRatio,mFrustumNear,mFrustumFar);            Matrix.multiplyMM(mMvpMatrix,0,mViewM,0,mRotateM,0);            Matrix.multiplyMM(mMvpMatrix,0,mProjectionM,0,mMvpMatrix,0);
mRotateX、mRotateY和mRotateZ是分别绕X、Y和Z轴旋转的矩阵(调用了Matrix.rotateM()方法得到的结果); Matrix.setLookAtM()设置视线; Matrix.frustumM()设置透视矩阵。 最终将三种旋转的结果存放在mMvpMatrix中。

创建Textures

            GLES20.glGenTextures(4,mTextureId,0);            for (int i=0;i<4;i++){                generateTexture(i);            }
其中generateTexure()方法为如下:
    private void generateTexture(int index){        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureId[index]);        GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT,1);        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT);        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,mTextures[index],0);    }
要绘制4个面,且4个面有不同的纹理,则需要4个Texture。

激活纹理单元和纹理坐标

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);        GLES20.glUniform1i(mUSamplerLoc,0);        GLES20.glVertexAttribPointer(mATextureCoordLoc,2,GLES20.GL_FLOAT,false,0,mTextureCoordFB);        GLES20.glEnableVertexAttribArray(mATextureCoordLoc);
激活了默认纹理单元0,并将片元着色器的sampler2D对象绑定至该纹理单元。绑定纹理坐标的引用和值,并激活它。

逐面绘制

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureId[0]);        GLES20.glDrawElements(GLES20.GL_TRIANGLES,3,GLES20.GL_UNSIGNED_SHORT,m1stSB);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureId[1]);        GLES20.glDrawElements(GLES20.GL_TRIANGLES,3,GLES20.GL_UNSIGNED_SHORT,m2ndSB);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureId[2]);        GLES20.glDrawElements(GLES20.GL_TRIANGLES,3,GLES20.GL_UNSIGNED_SHORT,m3rdSB);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureId[3]);        GLES20.glDrawElements(GLES20.GL_TRIANGLES,3,GLES20.GL_UNSIGNED_SHORT,m4thSB);
绘制每个面前,首先将特定纹理绑定至纹理单元0,让sampler2D对象能采集到正确的数据; 接着调用drawElements方法,drawElements方法将使用之前绑定的顶点数组。注意,最后1个参数是索引数组,可以看到每次绘制时索引数组都是不同的。 这些索引数组是在parseVertexInd()方法中得到的。

完整demo

完整的demo在如下的地址中查找: https://github.com/lyzirving/TrianglePyramidInAndroid.git
在完整的demo中,我将上述方法封装到了Triangle类中,可以选择通过颜色或是纹理来涂画三棱锥的表面。 上述代码和demo中的代码并不完善,有所缺漏还请大家多多交流!


















更多相关文章

  1. Android自动背光调节机制分析
  2. android中往字符串数组动态添加元素
  3. Android(安卓)OpenGLES2.0(二)——绘制一个三角形
  4. Android(安卓)基于 Comparator 对象列表数组排序
  5. 初步了解OpenGL开启摄像头
  6. Android(安卓)使用ViewPager实现左右循环滑动图片
  7. Android(安卓)获取外部存储设备列表
  8. Android(安卓)OpenGL(二) 学习《Android(安卓)3D 游戏开发技术宝
  9. PHP将数据库查询内容转换为JSON格式且显示中文

随机推荐

  1. 获取系统内存
  2. Android访问WEBAPI,传递json
  3. Android(安卓)手机状态
  4. Android(安卓)HFP Profile 连接过程
  5. android滑动删除的一个开源项目SwipeDelM
  6. Android(安卓)P Wifi Enable 之后扫描流
  7. Android(安卓)中的 requestWindowFeature
  8. android:SQLiteOpenHelper
  9. BackHandler是全局的!!!
  10. ScrollView去掉半月阴影