OpenglES2.0 Android:画矩形

OpenglES2.0 for Android:来画个矩形吧

原文链接:https://blog.csdn.net/cassiePython/article/details/51553842

OK,开始动手做吧,首先在上一节的项目中的shape目录下新建一个类——Square (Square.java),然后定义矩形的四个顶点的坐标,此时代码如下(Square.java):

 

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 right

private 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);

}

}


接下来就是着色器的编写,读取与编译,链接,获取program ID的操作,我们仍然使用上一节的着色器就好,其他的过程也与上一节相同,这里就不再说明了,

copy一下拿来用吧~~,当然你想进一步封装一下着色器的操作更好。现在的代码(Square.java):

 

 
  1.  

  2.  

 

接下来就是绘制了,这是我们这一节的重点,我们应该如何绘制一个矩形呢? 我们知道在OpenglES中支持的绘制方式有3 类 :点 ,线 , 三角形 ,每一类又有一种或多种绘制方式。 那我们来绘制一个矩形 ,其绘制方式是不是也有多种呢 ?答案是肯定的 。我们先用线段的方式来绘制这个矩形 。

 

线段的几种绘制方式:

 

GL_LINES : 将传入的顶点按照顺序,两两组织成线段进行绘制,若顶点个数为奇数,则会自动忽略掉最后一个顶点。

 

GL_LINE_STRIP:将传入的顶点按照顺序依次连接进行绘制

 

GL_LINE_LOOP:将传入的顶点按照顺序依次连接进行绘制,但是最后一个顶点会与第一个连接,形成线段环

 

 

我们就按照 GL_LINE_LOOP 的方式来绘制这个矩形,添加draw方式,此时代码如下 (Square.java):

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 right


private 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


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的id

program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);

GLES20.glUseProgram(program);

}

}

 

  1. <span style="font-size:14px;">package com.cumt.shape;

  2.  
  3. import java.nio.ByteBuffer;

  4. import java.nio.ByteOrder;

  5. import java.nio.FloatBuffer;

  6.  
  7. import com.cumt.openglestwo_test_one.R;

  8. import com.cumt.utils.ShaderHelper;

  9. import com.cumt.utils.TextResourceReader;

  10. import android.content.Context;

  11. import android.opengl.GLES20;

  12.  
  13. public class Square {

  14.  
  15. private Context context;

  16.  
  17. //float类型的字节数

  18. private static final int BYTES_PER_FLOAT = 4;

  19. // 数组中每个顶点的坐标数

  20. static final int COORDS_PER_VERTEX = 2;

  21. //矩形顶点坐标

  22. static float squareCoords[] = { -0.5f, 0.5f , // top left

  23. -0.5f, -0.5f , // bottom left

  24. 0.5f, -0.5f , // bottom right

  25. 0.5f, 0.5f }; // top right

  26.  
  27. private FloatBuffer vertexBuffer;

  28.  
  29. //------------第一步 : 定义两个标签,分别于着色器代码中的变量名相同,

  30. //------------第一个是顶点着色器的变量名,第二个是片段着色器的变量名

  31. private static final String A_POSITION = "a_Position";

  32. private static final String U_COLOR = "u_Color";

  33.  
  34. //------------第二步: 定义两个ID,我们就是通ID来实现数据的传递的,这个与前面

  35. //------------获得program的ID的含义类似的

  36. private int uColorLocation;

  37. private int aPositionLocation;

  38.  
  39. private int program;//保存program的id

  40.  
  41. //---------第四步:定义坐标元素的个数,这里有三个顶点

  42. private static final int POSITION_COMPONENT_COUNT = 4;

  43.  
  44.  
  45. public Square(Context context) {

  46. this.context = context;

  47. vertexBuffer = ByteBuffer

  48. .allocateDirect(squareCoords.length * BYTES_PER_FLOAT)

  49. .order(ByteOrder.nativeOrder())

  50. .asFloatBuffer();

  51. // 把坐标们加入FloatBuffer中

  52. vertexBuffer.put(squareCoords);

  53. // 设置buffer,从第一个坐标开始读

  54. vertexBuffer.position(0);

  55.  
  56. getProgram();

  57.  
  58. //----------第三步: 获取这两个ID ,是通过前面定义的标签获得的

  59. uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);

  60. aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);

  61.  
  62. //---------第五步: 传入数据

  63. GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,

  64. GLES20.GL_FLOAT, false, 0, vertexBuffer);

  65. GLES20.glEnableVertexAttribArray(aPositionLocation);

  66. }

  67.  
  68. //获取program

  69. private void getProgram(){

  70. //获取顶点着色器文本

  71. String vertexShaderSource = TextResourceReader

  72. .readTextFileFromResource(context, R.raw.simple_vertex_shader);

  73. //获取片段着色器文本

  74. String fragmentShaderSource = TextResourceReader

  75. .readTextFileFromResource(context, R.raw.simple_fragment_shader);

  76. //获取program的id

  77. program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);

  78. GLES20.glUseProgram(program);

  79. }

  80.  
  81. //以GL_LINE_LOOP方式绘制

  82. public void draw(){

  83. GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);

  84. GLES20.glDrawArrays(GLES20.GL_LINE_LOOP, 0, POSITION_COMPONENT_COUNT);

  85. }

  86. }</span>


最后在MyRender中创建对象,调用draw来绘制 ,代码如下 (MyRender.java):

 

 
  1. <span style="font-size:14px;">package com.cumt.render;

  2.  
  3. import javax.microedition.khronos.egl.EGLConfig;

  4. import javax.microedition.khronos.opengles.GL10;

  5.  
  6. import com.cumt.shape.Square;

  7. import com.cumt.shape.Triangle;

  8.  
  9. import android.content.Context;

  10. import android.opengl.GLSurfaceView.Renderer;

  11. import android.util.Log;

  12. import static android.opengl.GLES20.glClear;

  13. import static android.opengl.GLES20.glClearColor;

  14. import static android.opengl.GLES20.glViewport;

  15. import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;

  16.  
  17. public class MyRender implements Renderer {

  18.  
  19. private Context context;

  20.  
  21. public MyRender(Context context){

  22. this.context = context;

  23. }

  24.  
  25. //定义三角形对象

  26. Triangle triangle;

  27. Square square;

  28.  
  29. public void onSurfaceCreated(GL10 gl, EGLConfig config) {

  30. Log.w("MyRender","onSurfaceCreated");

  31. // TODO Auto-generated method stub

  32. //First:设置清空屏幕用的颜色,前三个参数对应红绿蓝,最后一个对应alpha

  33. glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

  34. // triangle = new Triangle(context);

  35. square = new Square(context);

  36. }

  37.  
  38. public void onSurfaceChanged(GL10 gl, int width, int height) {

  39. Log.w("MyRender","onSurfaceChanged");

  40. // TODO Auto-generated method stub

  41. //Second:设置视口尺寸,即告诉opengl可以用来渲染的surface大小

  42. glViewport(0,0,width,height);

  43. }

  44.  
  45. public void onDrawFrame(GL10 gl) {

  46. Log.w("MyRender","onDrawFrame");

  47. // TODO Auto-generated method stub

  48. //Third:清空屏幕,擦除屏幕上所有的颜色,并用之前glClearColor定义的颜色填充整个屏幕

  49. glClear(GL_COLOR_BUFFER_BIT);

  50. //绘制三角形

  51. // triangle.draw();

  52. square.draw();

  53. }

  54. }</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):

 

 
  1. <span style="font-size:14px;">package com.cumt.shape;

  2.  
  3. import java.nio.ByteBuffer;

  4. import java.nio.ByteOrder;

  5. import java.nio.FloatBuffer;

  6.  
  7. import com.cumt.openglestwo_test_one.R;

  8. import com.cumt.utils.ShaderHelper;

  9. import com.cumt.utils.TextResourceReader;

  10.  
  11. import android.content.Context;

  12. import android.opengl.GLES20;

  13.  
  14. public class Square2 {

  15.  
  16. private Context context;

  17.  
  18. //float类型的字节数

  19. private static final int BYTES_PER_FLOAT = 4;

  20. // 数组中每个顶点的坐标数

  21. static final int COORDS_PER_VERTEX = 2;

  22.  
  23. /*------------------第一步: 修改顶点数据-------------------------*/

  24. //矩形顶点坐标

  25. static float squareCoords[] = { -0.5f, 0.5f , // top left

  26. 0.5f, 0.5f , // top right

  27. -0.5f, -0.5f , // bottom left

  28. -0.5f, -0.5f , // bottom left

  29. 0.5f, -0.5f , // bottom right

  30. 0.5f, 0.5f }; // top right

  31.  
  32. private FloatBuffer vertexBuffer;

  33.  
  34. //------------第一个是顶点着色器的变量名,第二个是片段着色器的变量名

  35. private static final String A_POSITION = "a_Position";

  36. private static final String U_COLOR = "u_Color";

  37.  
  38. //------------获得program的ID的含义类似的

  39. private int uColorLocation;

  40. private int aPositionLocation;

  41.  
  42. private int program;//保存program的id

  43.  
  44. /*------------------第二步: 修改顶点个数-------------------------*/

  45. private static final int POSITION_COMPONENT_COUNT = 6;

  46.  
  47.  
  48. public Square2(Context context) {

  49. this.context = context;

  50. vertexBuffer = ByteBuffer

  51. .allocateDirect(squareCoords.length * BYTES_PER_FLOAT)

  52. .order(ByteOrder.nativeOrder())

  53. .asFloatBuffer();

  54. // 把坐标们加入FloatBuffer中

  55. vertexBuffer.put(squareCoords);

  56. // 设置buffer,从第一个坐标开始读

  57. vertexBuffer.position(0);

  58.  
  59. getProgram();

  60.  
  61. uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);

  62. aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);

  63.  
  64. GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,

  65. GLES20.GL_FLOAT, false, 0, vertexBuffer);

  66. GLES20.glEnableVertexAttribArray(aPositionLocation);

  67. }

  68.  
  69. //获取program

  70. private void getProgram(){

  71. //获取顶点着色器文本

  72. String vertexShaderSource = TextResourceReader

  73. .readTextFileFromResource(context, R.raw.simple_vertex_shader);

  74. //获取片段着色器文本

  75. String fragmentShaderSource = TextResourceReader

  76. .readTextFileFromResource(context, R.raw.simple_fragment_shader);

  77. //获取program的id

  78. program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);

  79. GLES20.glUseProgram(program);

  80. }

  81.  
  82. //以GL_LINE_LOOP方式绘制

  83. public void draw(){

  84. GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);

  85.  
  86. /*------------------第三步: 修改绘制方式-------------------------*/

  87. GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);

  88. }

  89. }</span>


然后在MyRender类中就可以new 该对象并调用其draw方法绘制了 ,运行效果:

 

 

虽然这种方式满足了我们的需求,但是造成了数据的冗余,我们可以使用后两种绘制方式来解决这个问题。这里给出后两者方式的数据和draw方法:

 

 

GL_TRIANGLE_STRIP方式 :

 
  1. <span style="font-size:14px;">//GL_TRIANGLE_STRIP

  2. static float squareCoords[] = { -0.5f, 0.5f , // top left

  3. 0.5f, 0.5f , // top right

  4. -0.5f, -0.5f , // bottom left

  5. 0.5f, -0.5f }; // bottom right

  6. private static final int POSITION_COMPONENT_COUNT = 4;

  7.  
  8. public void draw(){

  9. GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);

  10.  
  11. GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, POSITION_COMPONENT_COUNT);

  12. }</span>


GL_TRIANGLE_FAN方式:

 

 
  1. <span style="font-size:14px;"> //GL_TRIANGLE_FAN 要注意点的顺序问题 (试试将 bottom right和bottom left交换位置看看绘制的是否还是矩形)

  2. static float squareCoords[] = { -0.5f, 0.5f , // top left

  3. 0.5f, 0.5f , // top right

  4. 0.5f, -0.5f , // bottom right

  5. -0.5f, -0.5f }; // bottom left

  6. private static final int POSITION_COMPONENT_COUNT = 4;

  7.  
  8. public void draw(){

  9. GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);

  10. GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0 , POSITION_COMPONENT_COUNT);

  11. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值