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

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 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);
	}
}</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 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);
    }
}</span>

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

线段的几种绘制方式:

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

	//---------第四步:定义坐标元素的个数,这里有三个顶点
	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的id
		program = 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:设置清空屏幕用的颜色,前三个参数对应红绿蓝,最后一个对应alpha
		glClearColor(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 right

	private 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的id
		program = 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>

时间: 2024-08-06 04:11:06

OpenglES2.0 for Android:来画个矩形吧的相关文章

OpenglES2.0 for Android:来画个球吧

OpenglES2.0 for Android:来画个球吧 理解球坐标系 首先看下球的坐标系 ,如图 : (图来自百度百科 ) 设球上有一点 A ,球心为O ,OA在 xOy上的投影与X轴夹角为 φ (范围为 0 到360 ,单位 :度), OA在与Z的夹角为 θ (范围为 0 到 180  ,单位:度 ),球的半径为r,则有 ; r * sin θ = y / sin φ    r * sinθ  = x / cos φ   z = r * cos θ 由此可得 X,Y,Z坐标 我们前面已经知

OpenglES2.0 for Android:来画个立方体吧

OpenglES2.0 for Android:来画个立方体吧 前言: 前面一直在说OpenglES2.0二维图形的绘制,接下来我们步入三维的世界 ,三维世界远比二维要有趣的多,与此同时复杂性也要高得多,在unity3D中我们可以很容易的就创建 一个立方体,而在OpenglES2.0中这个过程要复杂得多,但是更加有趣 .先来看下我们的整个流程: 摄像机的设置: 想想你的摄像头,它的位置不同,朝向不同,对同一个事物拍摄得到的画面肯定是不同的,Opengl中的摄像头和我们日常生活中的摄像头是一样的道

OpenglES2.0 for Android:来画个三角形吧

OpenglES2.0 for Android:来画个三角形吧 先看看我们的整个流程: 理解坐标系: 左侧是Opengl默认的坐标系,右边是典型的android设备屏幕的坐标系.左侧的瘦瘦的三角形映射到android屏幕上就变成了胖胖的三角形(屏幕横向的时候),我们可以使用 camera和投影解决这个问题,具体怎么解决这里就先不累述了.这里我们只需要知道屏幕的左上角是(-1.0,1.0)横向向右为X轴正向,纵向向下为Y轴 负向,其范围都是从 -1到 +1. 定义三角形顶点: 我们在第一个andr

OpenglES2.0 for Android:再谈纹理映射

OpenglES2.0 for Android:再谈纹理映射 前言 上一节我们实现了一个简单的纹理映射的例子--一个简单的贴图,这节我们来做一些稍微复杂一点的例子,最后再给我们前面的立方体做一个纹理. 纹理拉伸 重复拉伸方式 这种是经常使用的一张纹理拉伸方式,常用于绘制一些重复的元素,比如我们在游戏绘制一幅方格式的地图时.使用重复拉伸方式使得纹理能够根据目标平 面的大小自动重复,这样既不会失去纹理图的效果,也可以节省内存.如下图所示: 实现起来很简单,我们回到上节的项目,找到我们纹理的工具类Te

OpenglES2.0 for Android:纹理映射

OpenglES2.0 for Android:纹理映射 前言 纹理映射又叫做纹理贴图,是将纹理空间中的纹理像素映射到屏幕空间中的像素的过程.就是把一幅图像贴到三维物体的表面上来增强真实感, 可以和光照计算.图像混合等技术结合起来形成许多非常漂亮的效果 (百度百科).简单来说,纹理就是一个图形或者照片,我们可以将它们 加载到Opengl中用以美化我们绘制的物体. 前期准备 我们现在准备实现这样一个功能:将一张图片贴到一个正方形中 .我们在以前画矩形的那节代码的基础上进行实现纹理贴图.这里我们新建

OpenglES2.0 for Android:各种变换来一波

OpenglES2.0 for Android:各种变换来一波 监听屏幕事件 在进行各种变换之前,我们先来了解一下如何监听屏幕的事件.我们下面的变换都需要用立方体来演示,所以我们继续使用上一节的绘制立方体的内容 首先新建一个项目 OpengESChange ,将上一节中关于绘制立方体的代码复制过来 .在前面我们一直在使用 android.opengl.GLSurfaceView 在第一篇中我们已经知道了这个类的作用,为了监听屏幕事件,我们创建一个类继承自该类,重写其onTouchEvent方法.

Android上使用OpenglES2.0遇到的一点问题

按照教程开发OpenglES2.0应用,遇到Logcat报错“Called unimplemented OpenGL ES API” 在论坛和stackoverflow上找到了答案. 1.manifest里面加上 <uses-feature android:glEsVersion="0x00020000" android:required="true" /> 2.surfaceView要设置 mGLSurfaceView.setEGLContextCli

android gridview画分割线

dongyangzhang android gridview画分割线,如图: 1.先上图: 2.具体实现代码: public class LineGridView extends GridView { public LineGridView(Context context) { super(context); // TODO Auto-generated constructor stub } public LineGridView(Context context, AttributeSet at

[转]html5 Canvas画图教程(9)—canvas中画出矩形和圆形

本文讲一下在canvas中画出矩形和圆形的办法,他们属于基础图形.当然,基础图形本来不止他们,但在canvas中,只有画矩形与圆形不需要用其他方法模拟. canvas画矩形 1,fillRect与strokeRect fillRect可以直接填充出一个矩形,填充样式是你当前设置的样式:同理strokeRect就是直接描边一个矩形 他们的参数是一致的,依次是(起点x坐标,起点y,矩形的宽,矩形的高).这里的起点,注意,是指矩形的左上角那个点. 我们通常用他们来做简单的事,他们也只能做简单的事.为什