OpenglES2.0 for Android:来画个矩形吧
来源:互联网 发布:社交大数据 编辑:程序博客网 时间:2024/06/05 22:33
OpenglES2.0 for Android:来画个矩形吧
上一节中我们绘制了一个三角形,我们在上一节的基础上来完成矩形的绘制 。
OK,开始动手做吧,首先在上一节的项目中的shape目录下新建一个类——Square (Square.java),然后定义矩形的四个顶点的坐标,此时代码如下(Square.java):
<span style="font-size:14px;">package com.cumt.shape;public class Square {//float类型的字节数private static final int BYTES_PER_FLOAT = 4;// 数组中每个顶点的坐标数 static final int COORDS_PER_VERTEX = 2;//矩形顶点坐标static float squareCoords[] = { -0.5f, 0.5f , // top left -0.5f, -0.5f , // bottom left 0.5f, -0.5f , // bottom right 0.5f, 0.5f }; // top right}</span>
和上一节一样,我们需要将float[ ]的数据转换为 floatbuffer ,此时代码如下 (Square.java):
<span style="font-size:14px;">package com.cumt.shape;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import android.content.Context;public class Square {private Context context;//float类型的字节数private static final int BYTES_PER_FLOAT = 4;// 数组中每个顶点的坐标数 static final int COORDS_PER_VERTEX = 2;//矩形顶点坐标static float squareCoords[] = { -0.5f, 0.5f , // top left -0.5f, -0.5f , // bottom left 0.5f, -0.5f , // bottom right 0.5f, 0.5f }; // top rightprivate FloatBuffer vertexBuffer;public Square(Context context) {this.context = context;vertexBuffer = ByteBuffer .allocateDirect(squareCoords.length * BYTES_PER_FLOAT) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); // 把坐标们加入FloatBuffer中 vertexBuffer.put(squareCoords); // 设置buffer,从第一个坐标开始读 vertexBuffer.position(0);}}</span>
接下来就是着色器的编写,读取与编译,链接,获取program ID的操作,我们仍然使用上一节的着色器就好,其他的过程也与上一节相同,这里就不再说明了,
copy一下拿来用吧~~,当然你想进一步封装一下着色器的操作更好。现在的代码(Square.java):
<span style="font-size:14px;">package com.cumt.shape;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import com.cumt.openglestwo_test_one.R;import com.cumt.utils.ShaderHelper;import com.cumt.utils.TextResourceReader;import android.content.Context;import android.opengl.GLES20;public class Square {private Context context;//float类型的字节数private static final int BYTES_PER_FLOAT = 4;// 数组中每个顶点的坐标数 static final int COORDS_PER_VERTEX = 2;//矩形顶点坐标static float squareCoords[] = { -0.5f, 0.5f , // top left -0.5f, -0.5f , // bottom left 0.5f, -0.5f , // bottom right 0.5f, 0.5f }; // top rightprivate FloatBuffer vertexBuffer;//------------第一步 : 定义两个标签,分别于着色器代码中的变量名相同, //------------第一个是顶点着色器的变量名,第二个是片段着色器的变量名private static final String A_POSITION = "a_Position";private static final String U_COLOR = "u_Color";//------------第二步: 定义两个ID,我们就是通ID来实现数据的传递的,这个与前面//------------获得program的ID的含义类似的private int uColorLocation;private int aPositionLocation;private int program;//保存program的idpublic Square(Context context) {this.context = context;vertexBuffer = ByteBuffer .allocateDirect(squareCoords.length * BYTES_PER_FLOAT) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); // 把坐标们加入FloatBuffer中 vertexBuffer.put(squareCoords); // 设置buffer,从第一个坐标开始读 vertexBuffer.position(0); getProgram(); //----------第三步: 获取这两个ID ,是通过前面定义的标签获得的 uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);//---------第五步: 传入数据GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false, 0, vertexBuffer);GLES20.glEnableVertexAttribArray(aPositionLocation);}//获取program private void getProgram(){ //获取顶点着色器文本 String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_vertex_shader); //获取片段着色器文本String fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_fragment_shader);//获取program的idprogram = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);GLES20.glUseProgram(program); }}</span>
线段的几种绘制方式:
GL_LINES : 将传入的顶点按照顺序,两两组织成线段进行绘制,若顶点个数为奇数,则会自动忽略掉最后一个顶点。
GL_LINE_STRIP:将传入的顶点按照顺序依次连接进行绘制
GL_LINE_LOOP:将传入的顶点按照顺序依次连接进行绘制,但是最后一个顶点会与第一个连接,形成线段环
我们就按照 GL_LINE_LOOP 的方式来绘制这个矩形,添加draw方式,此时代码如下 (Square.java):
<span style="font-size:14px;">package com.cumt.shape;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import com.cumt.openglestwo_test_one.R;import com.cumt.utils.ShaderHelper;import com.cumt.utils.TextResourceReader;import android.content.Context;import android.opengl.GLES20;public class Square {private Context context;//float类型的字节数private static final int BYTES_PER_FLOAT = 4;// 数组中每个顶点的坐标数 static final int COORDS_PER_VERTEX = 2;//矩形顶点坐标static float squareCoords[] = { -0.5f, 0.5f , // top left -0.5f, -0.5f , // bottom left 0.5f, -0.5f , // bottom right 0.5f, 0.5f }; // top rightprivate FloatBuffer vertexBuffer;//------------第一步 : 定义两个标签,分别于着色器代码中的变量名相同, //------------第一个是顶点着色器的变量名,第二个是片段着色器的变量名private static final String A_POSITION = "a_Position";private static final String U_COLOR = "u_Color";//------------第二步: 定义两个ID,我们就是通ID来实现数据的传递的,这个与前面//------------获得program的ID的含义类似的private int uColorLocation;private int aPositionLocation;private int program;//保存program的id//---------第四步:定义坐标元素的个数,这里有三个顶点private static final int POSITION_COMPONENT_COUNT = 4;public Square(Context context) {this.context = context;vertexBuffer = ByteBuffer .allocateDirect(squareCoords.length * BYTES_PER_FLOAT) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); // 把坐标们加入FloatBuffer中 vertexBuffer.put(squareCoords); // 设置buffer,从第一个坐标开始读 vertexBuffer.position(0); getProgram(); //----------第三步: 获取这两个ID ,是通过前面定义的标签获得的 uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);//---------第五步: 传入数据GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false, 0, vertexBuffer);GLES20.glEnableVertexAttribArray(aPositionLocation);}//获取program private void getProgram(){ //获取顶点着色器文本 String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_vertex_shader); //获取片段着色器文本String fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_fragment_shader);//获取program的idprogram = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);GLES20.glUseProgram(program); } //以GL_LINE_LOOP方式绘制 public void draw(){GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);GLES20.glDrawArrays(GLES20.GL_LINE_LOOP, 0, POSITION_COMPONENT_COUNT); }}</span>
最后在MyRender中创建对象,调用draw来绘制 ,代码如下 (MyRender.java):
<span style="font-size:14px;">package com.cumt.render;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import com.cumt.shape.Square;import com.cumt.shape.Triangle;import android.content.Context;import android.opengl.GLSurfaceView.Renderer;import android.util.Log;import static android.opengl.GLES20.glClear;import static android.opengl.GLES20.glClearColor;import static android.opengl.GLES20.glViewport;import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;public class MyRender implements Renderer {private Context context;public MyRender(Context context){this.context = context;}//定义三角形对象Triangle triangle;Square square;public void onSurfaceCreated(GL10 gl, EGLConfig config) {Log.w("MyRender","onSurfaceCreated");// TODO Auto-generated method stub//First:设置清空屏幕用的颜色,前三个参数对应红绿蓝,最后一个对应alphaglClearColor(0.0f, 0.0f, 0.0f, 0.0f);//triangle = new Triangle(context);square = new Square(context);}public void onSurfaceChanged(GL10 gl, int width, int height) {Log.w("MyRender","onSurfaceChanged");// TODO Auto-generated method stub//Second:设置视口尺寸,即告诉opengl可以用来渲染的surface大小glViewport(0,0,width,height);}public void onDrawFrame(GL10 gl) {Log.w("MyRender","onDrawFrame");// TODO Auto-generated method stub//Third:清空屏幕,擦除屏幕上所有的颜色,并用之前glClearColor定义的颜色填充整个屏幕glClear(GL_COLOR_BUFFER_BIT);//绘制三角形//triangle.draw();square.draw();}}</span>
运行结果:
好吧,貌似看不太清楚,我们把背景颜色改为白色,把 MyRender.java 中 onSurfaceCreated 方法的glClearColor(0.0f, 0.0f, 0.0f, 0.0f) 改为 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
再运行一下:
看到我们实际上画出了一个矩形框,中间是没有着色的。下面我们来使用三角形的方式来绘制。
三角形的几种绘制方式:
GL_TRIANGGLES :将传入的顶点按照没3个一组组成一个三角形进行绘制
GL_TRIANGLE_TRIP:将传入的顶点按照顺序三个一组组成三角形进行,前面三个顶点的后两个顶点做为下一个三角形的前两个顶点,
比如 有v0 v1 v2 v3 四个顶点顺序排列,则v0 v1 v2组成一个三角形,v1,v2,v3组成一个三角形。
GL_TRIANGLE_FAN:三角形扇的形式,将传入的顶点数据的第一个顶点做为中心点,其他点做为边缘点绘制一系列组成扇形的相邻三角形。
我们先使用第一种方式来画这个矩形,此时我们需要画两个三角形,所以需要6个顶点数据,我们copy一下Square.java,重命名为Square2.java,
首先 修改顶点数据 ,然后修改绘制方式 ,代码及步骤(见代码中 /* */注释的内容 ) 如下 (Square2.java):
<span style="font-size:14px;">package com.cumt.shape;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import com.cumt.openglestwo_test_one.R;import com.cumt.utils.ShaderHelper;import com.cumt.utils.TextResourceReader;import android.content.Context;import android.opengl.GLES20;public class Square2 {private Context context;//float类型的字节数private static final int BYTES_PER_FLOAT = 4;// 数组中每个顶点的坐标数 static final int COORDS_PER_VERTEX = 2; /*------------------第一步: 修改顶点数据-------------------------*///矩形顶点坐标static float squareCoords[] = { -0.5f, 0.5f , // top left 0.5f, 0.5f , // top right-0.5f, -0.5f , // bottom left-0.5f, -0.5f , // bottom left 0.5f, -0.5f , // bottom right 0.5f, 0.5f }; // top rightprivate FloatBuffer vertexBuffer; //------------第一个是顶点着色器的变量名,第二个是片段着色器的变量名private static final String A_POSITION = "a_Position";private static final String U_COLOR = "u_Color";//------------获得program的ID的含义类似的private int uColorLocation;private int aPositionLocation;private int program;//保存program的id/*------------------第二步: 修改顶点个数-------------------------*/private static final int POSITION_COMPONENT_COUNT = 6;public Square2(Context context) {this.context = context;vertexBuffer = ByteBuffer .allocateDirect(squareCoords.length * BYTES_PER_FLOAT) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); // 把坐标们加入FloatBuffer中 vertexBuffer.put(squareCoords); // 设置buffer,从第一个坐标开始读 vertexBuffer.position(0); getProgram(); uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false, 0, vertexBuffer);GLES20.glEnableVertexAttribArray(aPositionLocation);}//获取program private void getProgram(){ //获取顶点着色器文本 String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_vertex_shader); //获取片段着色器文本String fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_fragment_shader);//获取program的idprogram = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);GLES20.glUseProgram(program); } //以GL_LINE_LOOP方式绘制 public void draw(){GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);/*------------------第三步: 修改绘制方式-------------------------*/GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT); }}</span>
然后在MyRender类中就可以new 该对象并调用其draw方法绘制了 ,运行效果:
虽然这种方式满足了我们的需求,但是造成了数据的冗余,我们可以使用后两种绘制方式来解决这个问题。这里给出后两者方式的数据和draw方法:
GL_TRIANGLE_STRIP方式 :
<span style="font-size:14px;">//GL_TRIANGLE_STRIP static float squareCoords[] = { -0.5f, 0.5f , // top left 0.5f, 0.5f , // top right -0.5f, -0.5f , // bottom left 0.5f, -0.5f }; // bottom right private static final int POSITION_COMPONENT_COUNT = 4; public void draw(){GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, POSITION_COMPONENT_COUNT); }</span>
GL_TRIANGLE_FAN方式:
<span style="font-size:14px;"> //GL_TRIANGLE_FAN 要注意点的顺序问题 (试试将 bottom right和bottom left交换位置看看绘制的是否还是矩形) static float squareCoords[] = { -0.5f, 0.5f , // top left 0.5f, 0.5f , // top right 0.5f, -0.5f , // bottom right -0.5f, -0.5f }; // bottom left private static final int POSITION_COMPONENT_COUNT = 4; public void draw(){GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0 , POSITION_COMPONENT_COUNT); }</span>
0 0
- OpenglES2.0 for Android:来画个矩形吧
- OpenglES2.0 for Android:来画个三角形吧
- OpenglES2.0 for Android:来画个立方体吧
- OpenglES2.0 for Android:来做个地球吧
- OpenglES2.0 for Android:来画个圆吧
- OpenglES2.0 for Android:来画个球吧
- OpenglES2.0 for Android:各种变换来一波
- OpenglES2.0 for Android:纹理映射
- Opengles2.0 for android入门笔记(一)
- OpenglES2.0 for Android:第一个OpenglES应用
- OpenglES2.0 for Android:再谈纹理映射
- Android opengles2.0 背景透明
- Android OpenGLES2.0(一)——了解OpenGLES2.0
- Android OpenGLES2.0(一)——了解OpenGLES2.0
- android下opengles2.0多线程问题
- android模拟器运行opengles2.0程序
- Android OpenGLES2.0 直接导出YUV420数据
- Android Opengles2.0 多纹理融合
- 杂记录---sift学习
- Android:screenOrientation设定屏幕旋转方向
- java源码分析(5)-StringBuilder
- 设计模式学习(2)
- JVM理解其实并不难!
- OpenglES2.0 for Android:来画个矩形吧
- 将数据划分为训练数据及测试数据(div_train_val.py 解析)
- 【公司简介】之腾讯
- No such file or directory: 解决方法
- Android中颜色的设置
- 浏览器跟js交互、NPAPI之NPRuntime开发
- An App ID with Identifier "bundle id名字"is not available
- 第3章 理由是什么
- Maven安装本地jar