Android openGl 绘制简单图形的实现示例
学习五部曲,弄清楚5个W一个H(when(什么时候使用)、where(在哪个地方使用?)、who(对谁使用)、what(是个什么东西)、why(为什么要这么用?).一个H即:how(到底该怎么用?)),基本的概念篇主要围绕这几个方面进行分析
1.What?openGl是什么?openGlES又是什么?
相信很多人从事开发的都或多或少听到过有关OpenGl这个东西,但是平时用的少,只知道有这么个东西,而且学起来不简单,所以大多数人都不能讲出个个所以然来。
官方对OpenGl的描述为:
OpenGL(OpenGraphicsLibrary开发图形接口)是一个跨平台的图形API,用于指定3D图形处理硬件中的标准软件接口。
OpenGl的前身是SGI公司为其图形工作站开发的IRISGL,后来因为IRISGL的移植性不好,所以在其基础上,开发出了OpenGl。OpenGl一般用于在图形工作站,PC端使用,由于性能各方面原因,在移动端使用OpenGl基本带不动。为此,Khronos公司就为OpenGl提供了一个子集,OpenGlES(OpenGlforEmbeddedSystem)
什么是OpenGlES呢?
OpenGlES是免费的跨平台的功能完善的2D/3D图形库接口的API,是OpenGL的一个子集。
移动端使用到的基本上都是OpenGlES,当然Android开发下还专门为OpenGl提供了android.opengl包,并且提供了GlSurfaceView,GLU,GlUtils等工具类。
2.How?Android中的openGL如何使用?
在了解OpenGl的使用之前,我们需要了解两个基本类别的Android框架:GlSurfaceView和GlSurfaceView.Renderer
3.GlSurfaceView是什么?GLSurfaceView的作用是什么?GLSurfaceView如何使用?
GlSurfaceView从名字就可以看出,它是一个SurfaceView,看源码可知,GlSurfaceView继承自SurfaceView。并增加了Renderer.它的作用就是专门为OpenGl显示渲染使用的。
GLSurfaceView的使用方法:
可以通过创建的实例使用这个类,并增加你的Renderer.
@Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); GLSurfaceViewglSurfaceView=newGLSurfaceView(this); glSurfaceView.setRenderer(newGLSurfaceView.Renderer(){ @Override publicvoidonSurfaceCreated(GL10gl,EGLConfigconfig){ } @Override publicvoidonSurfaceChanged(GL10gl,intwidth,intheight){ } @Override publicvoidonDrawFrame(GL10gl){ } }); setContentView(glSurfaceView); }
4.GlSurfaceView.Renderer是什么?GLSurfaceView.Renderer的作用?GLSurfaceView.Renderer的用法?
该接口定义了用于绘制在图形所需的方法GLSurfaceView。你必须提供这个接口作为一个单独的类的实现,并将其连接到您的GLSurfaceView使用实例GLSurfaceView.setRenderer()。如上面的代码所示。作用就是提供各种渲染方法,OpenGl的渲染操作均在此接口中实习。下面说下实现该接口的方法含义:
- onSurfaceCreated():系统调用这个方法一次创建时GLSurfaceView。使用此方法来执行只需要发生一次的操作,比如设置OpenGL的环境参数或初始化的OpenGL图形对象。
- onDrawFrame():系统调用上的每个重绘此方法GLSurfaceView。使用此方法作为主要执行点用于绘制(和重新绘制)的图形对象。
- 系统调用此方法时的GLSurfaceView几何形状的变化,包括尺寸变化GLSurfaceView或设备屏幕的取向。例如,当设备从纵向变为横向的系统调用这个方法。使用此方法可以在变化做出反应GLSurfaceView容器。
介绍完了GlSurfaceView和GlSurfaceView.renderer之后,接下来说下如何使用GlSurfaceView;
1.创建一个GlSurfaceView
2.为这个GlSurfaceView设置渲染
3.在GlSurfaceView.renderer中绘制处理显示数据
5.OpenGl的简单使用实例(绘制一个三角形)
在使用OpenGl之前,需要在AndroidManifest.xml中设置OpenGl的版本:这里我们使用的是OpenGlES2.0,所以需要添加如下说明:
使用GLSufaceView(上面有介绍)
- 具体在GlSurfaceView.Renderer中的绘制步骤:
- 设置视图展示窗口(viewport):在onSurfaceChanged中调用GLES20.glViewport(0,0,width,height);
- 创建图形类,确定好顶点位置和图形颜色,将顶点和颜色数据转换为OpenGl使用的数据格式
- 加载顶点找色器和片段着色器用来修改图形的颜色,纹理,坐标等属性
- 创建投影和相机视图来显示视图的显示状态,并将投影和相机视图的转换传递给着色器。
- 创建项目(Program),连接顶点着色器片段着色器。
- 将坐标数据传入到OpenGlES程序中:
使用OpenGl修改背景颜色
创建一个GlSurfaceView,并为其设置渲染OneGlRenderer;
publicclassOneGlSurfaceViewextendsGLSurfaceView{ privatefinalOneGlRenderermRenderer; publicOneGlSurfaceView(Contextcontext){ super(context); //CreateanOpenGLES2.0context setEGLContextClientVersion(2); mRenderer=newOneGlRenderer(); //SettheRendererfordrawingontheGLSurfaceView setRenderer(mRenderer); } }
实现渲染接口
publicclassOneGlRendererimplementsGLSurfaceView.Renderer{ publicvoidonSurfaceCreated(GL10unused,EGLConfigconfig){ //Setthebackgroundframecolor GLES20.glClearColor(0.0f,0.0f,0.0f,1.0f); } publicvoidonDrawFrame(GL10unused){ //Redrawbackgroundcolor GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); } publicvoidonSurfaceChanged(GL10unused,intwidth,intheight){ GLES20.glViewport(0,0,width,height); } }
展示渲染后的GlSurfaceView
publicclassOneOpenGlActivityextendsAppCompatActivity{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); OneGlSurfaceViewglSurfaceView=newOneGlSurfaceView(this); setContentView(glSurfaceView); } }
效果如下:就是简单给GlSurfaceView渲染一层黑色。
使用OpenGl绘制几何图形
一:图形创建
创建一个几何图形(这里主要列举三角形和正方形),需要注意一点,我们设置图形的顶点坐标后,需要将顶点坐标转为ByteBuffer,这样OpenGl才能进行图形处理。
三角形图形创建:
publicclassTriangle{ privateFloatBuffervertexBuffer; //numberofcoordinatespervertexinthisarray staticfinalintCOORDS_PER_VERTEX=3; staticfloattriangleCoords[]={//incounterclockwiseorder: 0.0f,0.5f,0.0f,//top -0.5f,-0.5f,0.0f,//bottomleft 0.5f,-0.5f,0.0f//bottomright }; //Setcolorwithred,green,blueandalpha(opacity)values floatcolor[]={255,0,0,1.0f}; publicTriangle(){ //初始化ByteBuffer,长度为arr数组的长度*4,因为一个float占4个字节 ByteBufferbb=ByteBuffer.allocateDirect(triangleCoords.length*4); //数组排列用nativeOrder bb.order(ByteOrder.nativeOrder()); //从ByteBuffer创建一个浮点缓冲区 vertexBuffer=bb.asFloatBuffer(); //将坐标添加到FloatBuffer vertexBuffer.put(triangleCoords); //设置缓冲区来读取第一个坐标 vertexBuffer.position(0); } }
正方型图:
publicclassSquare{ privateFloatBuffervertexBuffer; privateShortBufferdrawListBuffer; //numberofcoordinatespervertexinthisarray staticfinalintCOORDS_PER_VERTEX=3; staticfloatsquareCoords[]={ -0.5f,0.5f,0.0f,//topleft -0.5f,-0.5f,0.0f,//bottomleft 0.5f,-0.5f,0.0f,//bottomright 0.5f,0.5f,0.0f};//topright privateshortdrawOrder[]={0,1,2,0,2,3};//ordertodrawvertices publicSquare(){ //初始化ByteBuffer,长度为arr数组的长度*4,因为一个float占4个字节 ByteBufferbb=ByteBuffer.allocateDirect(squareCoords.length*4); bb.order(ByteOrder.nativeOrder()); vertexBuffer=bb.asFloatBuffer(); vertexBuffer.put(squareCoords); vertexBuffer.position(0); //初始化ByteBuffer,长度为arr数组的长度*2,因为一个short占2个字节 ByteBufferdlb=ByteBuffer.allocateDirect(drawOrder.length*2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer=dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0); } }
创建图形基本没什么技巧可言,按部就班就行了,为什么数据需要转换格式呢?主要是因为Java的缓冲区数据存储结构为大端字节序(BigEdian),而OpenGl的数据为小端字节序(LittleEdian),因为数据存储结构的差异,所以,在Android中使用OpenGl的时候必须要进行下转换。当然,一般我们在使用的时候都会做个简单的工具类。这里提供几个简单的封装。(占几个字节就初始化ByteBuffer长度的时候*几)
将int[]转成IntBuffer
privateIntBufferintBufferUtil(int[]arr) { IntBuffermBuffer; //初始化ByteBuffer,长度为arr数组的长度*4,因为一个int占4个字节 ByteBufferqbb=ByteBuffer.allocateDirect(arr.length*4); //数组排列用nativeOrder qbb.order(ByteOrder.nativeOrder()); mBuffer=qbb.asIntBuffer(); mBuffer.put(arr); mBuffer.position(0); returnmBuffer; }
将float[]数组转为OpenGl所需要的FloatBuffer
privateFloatBufferfloatBufferUtil(float[]arr) { FloatBuffermBuffer; //初始化ByteBuffer,长度为arr数组的长度*4,因为一个int占4个字节 ByteBufferqbb=ByteBuffer.allocateDirect(arr.length*4); //数组排列用nativeOrder qbb.order(ByteOrder.nativeOrder()); mBuffer=qbb.asFloatBuffer(); mBuffer.put(arr); mBuffer.position(0); returnmBuffer; }
当然,依葫芦画瓢,如何将short[]转ShortBuffer这个就照着写就ok了
privateShortBuffershortBufferUtil(short[]arr){ ShortBuffermBuffer; //初始化ByteBuffer,长度为arr数组的长度*2,因为一个short占2个字节 ByteBufferdlb=ByteBuffer.allocateDirect( //(#ofcoordinatevalues*2bytespershort) arr.length*2); dlb.order(ByteOrder.nativeOrder()); mBuffer=dlb.asShortBuffer(); mBuffer.put(arr); mBuffer.position(0); returnmBuffer; }
创建完形状之后,我们就要进行我们的第二步了,将这些形状渲染到GlSurfaceView中去。主要可分为下面几步:
1.首先我们需要在GlSurfaceView.Renderer中初始化需要渲染的几何图形
privateTrianglemTriangle; privateSquaremSquare; publicvoidonSurfaceCreated(GL10unused,EGLConfigconfig){ //设置背景颜色 GLES20.glClearColor(0.0f,0.0f,0.0f,1.0f); //初始化triangle mTriangle=newTriangle(); //初始化square mSquare=newSquare(); }
二.:绘制图形,因为需要提供很多细节的图形渲染管线,所以绘制图形前至少需要一个顶点着色器来绘制形状和一个片段着色器的颜色,形状。这些着色器必须被编译,然后加入到一个OpenGLES程序,然后将其用于绘制形状。简单介绍下这几个概念:
-顶点着色器(VertexShader)顶点着色器是GPU上运行的小程序,由名字可以知道,通过它来处理顶点,他用于渲染图形顶点的OpenGLES图形代码。顶点着色器可用来修改图形的位置,颜色,纹理坐标,不过不能用来创建新的顶点坐标。
-片段着色器(FragmentShader)用于呈现与颜色或纹理的形状的面的OpenGLES代码。
-项目(Program)-包含要用于绘制一个或多个形状着色器的OpenGLES的对象。
下面给Triangle类定义一个基本的着色器代码:
publicclassTriangle{ privatefinalStringvertexShaderCode= "attributevec4vPosition;"+ "voidmain(){"+ "gl_Position=vPosition;"+ "}"; privatefinalStringfragmentShaderCode= "precisionmediumpfloat;"+ "uniformvec4vColor;"+ "voidmain(){"+ "gl_FragColor=vColor;"+ "}"; ... }
当然,上面我们创建了着色器的编译代码,代码编写完成,需要写个方法来执行这段代码,这里我们在渲染器中写一个如下方法来执行着色器代码:
publicstaticintloadShader(inttype,StringshaderCode){ //创造顶点着色器类型(GLES20.GL_VERTEX_SHADER) //或者是片段着色器类型(GLES20.GL_FRAGMENT_SHADER) intshader=GLES20.glCreateShader(type); //添加上面编写的着色器代码并编译它 GLES20.glShaderSource(shader,shaderCode); GLES20.glCompileShader(shader); returnshader; }
这里有一点需要注意,因为着色器的代码执行是很昂贵滴,所以避免多次执行,需要我们一般将执行代码的逻辑写带图形类的构造方法中。比如上面的Triangle,我们就这么写:
privatefinalintmProgram; publicTriangle(){ ......//数据转换 intvertexShader=OneGlRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); intfragmentShader=OneGlRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); //创建空的OpenGLES程序 mProgram=GLES20.glCreateProgram(); //添加顶点着色器到程序中 GLES20.glAttachShader(mProgram,vertexShader); //添加片段着色器到程序中 GLES20.glAttachShader(mProgram,fragmentShader); //创建OpenGLES程序可执行文件 GLES20.glLinkProgram(mProgram); }
最后,所有绘制的所有基本配置都配置完成之后,我们来写绘制图形的方法,我们在图形类(Triangle)中创建一个绘制的方法onDraw(),可以在onDraw()方法中设置绘制逻辑。
privateintmPositionHandle; privateintmColorHandle; privatefinalintvertexCount=triangleCoords.length/COORDS_PER_VERTEX; privatefinalintvertexStride=COORDS_PER_VERTEX*4;//4bytespervertex publicvoiddraw(){ //将程序添加到OpenGLES环境 GLES20.glUseProgram(mProgram); //获取顶点着色器的位置的句柄 mPositionHandle=GLES20.glGetAttribLocation(mProgram,"vPosition"); //启用三角形顶点位置的句柄 GLES20.glEnableVertexAttribArray(mPositionHandle); //准备三角形坐标数据 GLES20.glVertexAttribPointer(mPositionHandle,COORDS_PER_VERTEX, GLES20.GL_FLOAT,false, vertexStride,vertexBuffer); //获取片段着色器的颜色的句柄 mColorHandle=GLES20.glGetUniformLocation(mProgram,"vColor"); //设置绘制三角形的颜色 GLES20.glUniform4fv(mColorHandle,1,color,0); //绘制三角形 GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,vertexCount); //禁用顶点数组 GLES20.glDisableVertexAttribArray(mPositionHandle); }
完成上面所有步骤,只需要在GlSurfaceView.Renderer的onDrawFrame()方法中调用图形类的绘制方法即可(上面的onDraw()):
publicvoidonDrawFrame(GL10unused){ mTriangle.draw(); }
最后的呈现效果如下图所示:
运用投影和相机视图
通常情况下,OpenGl中展示的视图和在Android上显示的图形会有偏差。借用官方图片:
投影的定义
使用OpenGl绘制的3D图形,需要展示在移动端2D设备上,这就是投影。AndroidOpenGlES中有两种投影方式:一种是正交投影,一种是透视投影:
正交投影投影物体的带下不会随观察点的远近而发生变化,我们可以使用下面方法来执行正交投影:
Matrix.orthoM(float[]m,//接收正交投影的变换矩阵 intmOffset,//变换矩阵的起始位置(偏移量) floatleft,//相对观察点近面的左边距 floatright,//相对观察点近面的右边距 floatbottom,//相对观察点近面的下边距 floattop,//相对观察点近面的上边距 floatnear,//相对观察点近面距离 floatfar)//相对观察点远面距离
透视投影:随观察点的距离变化而变化,观察点越远,视图越小,反之越大,我们可以通过如下方法来设置透视投影:
Matrix.frustumM(float[]m,//接收透视投影的变换矩阵 intmOffset,//变换矩阵的起始位置(偏移量) floatleft,//相对观察点近面的左边距 floatright,//相对观察点近面的右边距 floatbottom,//相对观察点近面的下边距 floattop,//相对观察点近面的上边距 floatnear,//相对观察点近面距离 floatfar)//相对观察点远面距离
相机视图
什么是相机视图?简单来说生活中我们拍照,你站的高度,拿相机的位置,姿势不同,拍出来的照片也就不一样,相机视图就是来修改相机位置,观察方式以及相机的倾斜角度等属性。我们可以通过下面方法来修改相机视图属性:
Matrix.setLookAtM(float[]rm,//接收相机变换矩阵 intrmOffset,//变换矩阵的起始位置(偏移量) floateyeX,floateyeY,floateyeZ,//相机位置 floatcenterX,floatcenterY,floatcenterZ,//观察点位置 floatupX,floatupY,floatupZ)//up向量在xyz上的分量
转换矩阵(变换矩阵)
转换矩阵用来做什么的呢?是否记得上面我们绘制的图形坐标需要转换为OpenGl中能处理的小端字节序(LittleEdian),没错,转换矩阵就是用来将数据转为OpenGlES可用的数据字节,我们将相机视图和投影设置的数据相乘,便得到一个转换矩阵,然后我们再讲此矩阵传给顶点着色器,具体使用方法及参数说明如下:
Matrix.multiplyMM(float[]result,//接收相乘结果 intresultOffset,//接收矩阵的起始位置(偏移量) float[]lhs,//左矩阵 intlhsOffset,//左矩阵的起始位置(偏移量) float[]rhs,//右矩阵 intrhsOffset)//右矩阵的起始位置(偏移量)
下面简单讲解下如何使用投影和相机视图来实现矩阵变换并传递给顶点着色器;
定义一个投影:
//mMVPMatrixisanabbreviationfor"ModelViewProjectionMatrix" privatefinalfloat[]mMVPMatrix=newfloat[16]; privatefinalfloat[]mProjectionMatrix=newfloat[16]; privatefinalfloat[]mViewMatrix=newfloat[16]; publicvoidonSurfaceChanged(GL10unused,intwidth,intheight){ GLES20.glViewport(0,0,width,height); floatratio=(float)width/height; //这个投影矩阵被应用于对象坐标在onDrawFrame()方法中 Matrix.frustumM(mProjectionMatrix,0,-ratio,ratio,-1,1,3,7); }
定义一个相机视图
@Override publicvoidonDrawFrame(GL10unused){ ... //Setthecameraposition(Viewmatrix) Matrix.setLookAtM(mViewMatrix,0,0,0,-3,0f,0f,0f,0f,1.0f,0.0f); //Calculatetheprojectionandviewtransformation Matrix.multiplyMM(mMVPMatrix,0,mProjectionMatrix,0,mViewMatrix,0); //Drawshape mTriangle.draw(mMVPMatrix); }
修改图形类执行代码
publicclassTriangle{ privatefinalStringvertexShaderCode= //Thismatrixmembervariableprovidesahooktomanipulate //thecoordinatesoftheobjectsthatusethisvertexshader "uniformmat4uMVPMatrix;"+ "attributevec4vPosition;"+ "voidmain(){"+ //thematrixmustbeincludedasamodifierofgl_Position //NotethattheuMVPMatrixfactor*mustbefirst*inorder //forthematrixmultiplicationproducttobecorrect. "gl_Position=uMVPMatrix*vPosition;"+ "}"; //Usetoaccessandsettheviewtransformation privateintmMVPMatrixHandle; ... }
投影和相机视图代码到图形类的绘制方法中去onDraw()
publicvoiddraw(float[]mvpMatrix){ ...... //得到形状的变换矩阵的句柄 mMVPMatrixHandle=GLES20.glGetUniformLocation(mProgram,"uMVPMatrix"); //将投影和视图转换传递给着色器 GLES20.glUniformMatrix4fv(mMVPMatrixHandle,1,false,mvpMatrix,0); //画三角形 GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,vertexCount); //禁用顶点数组 GLES20.glDisableVertexAttribArray(mPositionHandle); }
做完这些,我们就能得到如下图:
没错,这才没有变形的视图。到这里,基本的通过OpenGl绘制简单图形就over了,下面我们讲解下如何添加一些交互动作。
添加动作
前面都是简单的动作介绍,使用OpenGl在屏幕上绘制对象是使用openGl的基本功。下面我来说下如何添加旋转形状。使用OpenGl的描绘对象是相对简单的,首先需要在渲染器中创建一组旋转矩阵,然后使用之前提到过的投影和相机视图变换矩阵结合起来使用:
privatefloat[]mRotationMatrix=newfloat[16]; publicvoidonDrawFrame(GL10gl){ float[]scratch=newfloat[16]; ... //创建一个旋转矩阵 longtime=SystemClock.uptimeMillis()%4000L; floatangle=0.090f*((int)time); Matrix.setRotateM(mRotationMatrix,0,angle,0,0,-1.0f); //将旋转矩阵与投影和相机视图组合在一起 //NotethatthemMVPMatrixfactor*mustbefirst*inorder //forthematrixmultiplicationproducttobecorrect. Matrix.multiplyMM(scratch,0,mMVPMatrix,0,mRotationMatrix,0); //Drawtriangle mTriangle.draw(scratch); }
运行效果图如下:
修改顶点颜色
一个颜色是不是太单调了?如何让做成多彩的呢?接下来我们来做一个多彩三角形,如何来做一个多彩三角形?我们通过顶点着色器来做。基于上面的代码,我们只需要做一点点改动,下面是基本步骤:
1.修改着色器代码
2.将颜色值修改为float数组并转为floatBuffer
3.将获取的floatBuffer传递给顶点着色器。
修改着色器代码:
privatefinalStringvertexShaderCode= "attributevec4vPosition;"+ "uniformmat4uMVPMatrix;"+ "varyingvec4vColor;"+ "attributevec4aColor;"+ "voidmain(){"+ "gl_Position=uMVPMatrix*vPosition;"+ "vColor=aColor;"+ "}"; privatefinalStringfragmentShaderCode= "precisionmediumpfloat;"+ "varyingvec4vColor;"+ "voidmain(){"+ "gl_FragColor=vColor;"+ "}";
shader的变量类型(uniform,attribute和varying)的区别
关于shader的变量类型(uniform,attribute和varying)的区别及使用,下面做下说明:
1.uniform:uniform变量在vertex和fragment两者之间声明方式完全一样,则它可以在vertex和fragment共享使用。(相当于一个被vertex和fragmentshader共享的全局变量)uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。在代码中通过GLES20.glGetUniformLocation(intprogram,Stringname)来获取属性值。并通过GLES20.glUniformMatrix4fv(intlocation,intcount,booleantranspose,float[]value,intoffset);方法将数据传递给着色器。
2.attribute:这个变量只能在顶点着色器中使用(vertexShader),用来表示顶点的数据,比如顶点坐标,顶点颜色,法线,纹理坐标等。在绘制的时候通过GLES20.glGetAttribLocation(intprogram,Stringname)来获取变量值,通过GLES20.glEnableVertexAttribArray(intindex)来启动句柄,最后通过GLES20.glVertexAttribPointer(intindx,intsize,inttype,booleannormalized,intstride,java.nio.Bufferptr)来设置图形数据。
3.varying变量:这个变量只能用来在vertex和fragmentshader之间传递数据时使用,不可以通过代码获取其变量值。
接来下我们进行数据转换:
floatcolor[]={ 1.0f,0f,0f,1.0f, 0f,1.0f,0f,1.0f, 0f,0f,1.0f,1.0f }; publicTriangle(){ ...... ByteBufferdd=ByteBuffer.allocateDirect( color.length*4); dd.order(ByteOrder.nativeOrder()); colorBuffer=dd.asFloatBuffer(); colorBuffer.put(color); colorBuffer.position(0); }
最后我们需要获取着色器的句柄并设置着色器的颜色:
publicvoiddraw(float[]mvpMatrix){ ...... /*//获取片段着色器的vColor成员的句柄 mColorHandle=GLES20.glGetUniformLocation(mProgram,"vColor"); //设置绘制三角形的颜色 GLES20.glUniform4fv(mColorHandle,1,colorBuffer,0);*/ //获取片元着色器的vColor成员的句柄 mColorHandle=GLES20.glGetAttribLocation(mProgram,"aColor"); //设置绘制三角形的颜色 GLES20.glEnableVertexAttribArray(mColorHandle); GLES20.glVertexAttribPointer(mColorHandle,4, GLES20.GL_FLOAT,false, 0,colorBuffer); ...... }
6.参考链接:
opengl官网
opengl的环境搭建及基本教程
7.项目地址:
AserbaosAndroid此项目为博主所有的系列学习的代码汇总项目,该文章的代码位于:opengl/OneOpenGl/OneOpenGlActivity
到此这篇关于AndroidopenGl绘制简单图形的实现示例的文章就介绍到这了,更多相关AndroidopenGl绘制简单图形内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。