Android 中使用OpenGL ES进行2D开发(绘制第一个三角形)

前面也说过,OpenGL ES不能直接绘制矩形,只能绘制三角形,两个三角形能组合成一个矩形,一个3D的模型就有N多的三角形了。

1.绘制三角形需要的理论知识

绘制三角形需要3步:

  1. 在虚拟3D空间定义三个点的坐标位置
  2. 在虚拟3D空间定义视椎体(VIewPort)
  3. 转换显示到屏幕中

1.1在虚拟3D空间定义三个点的坐标位置

1.1.1我们先来看在代码中是如何实现在虚拟3D空间定义三个点的坐标位置

在3D空间中进行绘制,首先要指定一系列的点,每个点有3个值,分别对应于x,y,z坐标。
坐标示例:
new float[] coords= {  -0.5f,   -0.5f, 0.0f          //p1(x1,y1,z1)
                       0.5f,   -0.5f, 0.0f         //p2(x2,y2,z2)
                       0.0f,    0.5f, 0.0f };      //p3(x3,y3,z3)
new float[] coords1= {  -0.5f,   -0.5f             //p1(x1,y1,0)
                         0.5f,   -0.5f             //p2(x2,y2,0)
                         0.0f,    0.5f };         //p3(x3,y3,0)



如上面的浮点数组所示,可以只定义两个点,第三个点Z轴坐标上就会默认是0。
一个问题:0.5到底有多宽,最终显示到屏幕上的三角形有多大呢?
现在只能解释,最终显示到屏幕上的三角形的大小不只是跟三个点的位置有关,还跟视椎体(VIewPort)的大小有关,还跟第三步“转换显示到屏幕中”有关。后面就慢慢明白了。


如上图所示,我们定义的三个点的位置在虚拟空间中是这样的。

1.1.2定义完三个点的浮点数组后,要介绍一个很抽象的东西了:“创建NIO浮点值缓冲区”


要绘制那3个点,需要通过glVertexPointer方法将它们传递给OpenGL Es.为了提高效率,glVertexPointer仅接受与语言无关的本地缓冲区,而不是浮点数组。所以需要将基于java的浮点数组转换为可接受的类似C的本地缓冲区,需要使用java.nio类将浮点数组转换为本地缓冲区。
每个点有3个浮点值,因为有3个坐标轴,每个浮点值为4字节,所以每个点需要3*4=12字节,而一个三角形有3个点,所以需要36个字节,当然如果只用2个坐标轴,那么只需要3*2*4=24字节。
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(3 * 3 * 4);
//Z轴默认为0
//ByteBuffer byteBuffer = ByteBuffer.allocateDirect(3 * 2 * 4);
byteBuffer.order(ByteOrder.nativeOrder());             
vertices = byteBuffer.asFloatBuffer();gl.glVertexPointer(int size, int type, int stride, Buffer pointer);
gl.glVertexPointer( 3, GL10.GL_FLOAT, 0, byteBuffer);
//Z轴默认为0
//gl.glVertexPointer( 2, GL10.GL_FLOAT, 0, byteBuffer);

第三个参数为stride,表示将每个点分开的字节数,在这里,它是0,因为一个点紧挨着一个点。有时可以在缓冲区中每个点之后添加颜色特性,如果希望添加颜色特性,需要设置stride来跳过这些部分,这里不细讲。有空写个彩色三角形的示例。

1.1.3点缓冲区创建索引和设置颜色

ShortBuffer indices; 
ByteBuffer indicesBuffer= ByteBuffer.allocateDirect(3 * 2);
indicesBuffer.order(ByteOrder.nativeOrder()); 
indices = byteBuffer.asShortBuffer();
indices.put(new short[] { 0, 1, 2});  
indices.flip();
gl.glColor4f(1, 0, 0, 1);  //表示红色
glDrawElements(GL10.GL_TRIANGLE_STRIP,3,GL10.GL_UNSIGNED_SHORT, indicesBuffer) 

跟上面的3个点的浮点缓冲区类似,shortBuffer只需要2个字节,这里索引类似三角形的三个边。
gl.glColor4f()中的4f表示该方法接受4个参数,每个参数为浮点值,这4个参数是红,绿,蓝和alpha(颜色渐变)的分量

通过glVertexPointer指定了一系列的点之后,可以使用glDrawElements来绘制这些点。注意:OpenGL 是一种状态机。它以累积方式调用下一个方法时,会记住一个方法所设置的值。所以无需显式将glVertexPointer设置的点传递给glDrawElements.
glDrawElements(int mode, int count, int type, Buffer indices)
glDrawElements(GL10.GL_TRIANGLE_STRIP,3,GL10.GL_UNSIGNED_SHORT, indicesBuffer)
GL_TRIANGLE_STRIP表示三角形条带,此参数还包括,GL_POINTS,GL_LINES等。
GL_TRIANGLE_STRIP中的STRIP概念用于在使用旧点时添加新点。
Points(v1,v2,v3,v4)
Indices(v1,v2,v3,    v2,v3,v4)
指定4个点,引用6次来绘制2个三角形

1.2在虚拟3D空间定义视椎体(VIewPort)

注意我们这里是2D开发,所以用的是平行投射,平行投射用到了下面两个方法

gl.glMatrixMode(GL10.GL_PROJECTION)
GL10.glOrthof(int left, int right, int bottom, int top, int near, int far)


说明:glOrtho是创建一个正交平行的视景体。Orthographic(正字法;正字学 )
具体示例:gl.glOrthof(0, 480, 0, 320, 1, -1);

因为我们定义的点的Z坐标是0,所以我们Viewport中Z轴区域只是1到-1。
gl.glOrthof(0, 480, 0, 320, 1, -1)和gl.glOrthof(0, 480, 0, 320, 1000, -1)两种定义,Viewport大小会不一样,但是因为是平行投射,所以最终显示到手机上的三角形大小还是一样的。

1.3转换显示到屏幕中

glViewport(int x, int y, int width, int height )

glOrtho函数只是负责使用什么样的视景体来截取图像,并不负责使用某种规则把图像呈现在屏幕上。
glViewport主要完成这样的功能。它负责把视景体截取的图像按照怎样的高和宽显示到屏幕上。
我们代码中的具体应用:
gl.glViewport(0, 0, glView.getWidth(), glView.getHeight());


2.绘制三角形的具体代码

package com.waitingfy.android.glbasics;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;


public class FirstTriangleTest extends Activity {
	public GLSurfaceView glView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// 去掉activity的标题,全屏显示
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		glView = new GLSurfaceView(this);
		glView.setRenderer(new SimpleRenderer());
		setContentView(glView);
	}

	@Override
	public void onResume() {
		super.onPause();
		glView.onResume();
	}

	@Override
	public void onPause() {
		super.onPause();
		glView.onPause();
	}

	class SimpleRenderer implements Renderer {

		FloatBuffer vertices;
		ShortBuffer indices;

		public SimpleRenderer() {

			ByteBuffer byteBuffer = ByteBuffer.allocateDirect(3 * 3 * 4);
			byteBuffer.order(ByteOrder.nativeOrder());
			vertices = byteBuffer.asFloatBuffer();
			vertices.put(new float[] { 0f, 0f, 0f, 
					           320f, 0f, 0f, 
					           160f, 480f, 0f });
			ByteBuffer indicesBuffer = ByteBuffer.allocateDirect(3 * 2);
			indicesBuffer.order(ByteOrder.nativeOrder());
			indices = indicesBuffer.asShortBuffer();
			indices.put(new short[] { 0, 1, 2 });
			//indices.flip() == indices.position(0)
			indices.flip();
			vertices.flip();
		}

		@Override
		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
			Log.d("GLSurfaceViewTest", "surface created");
		}

		@Override
		public void onSurfaceChanged(GL10 gl, int width, int height) {
			Log.d("GLSurfaceViewTest", "surface changed: " + width + "x"
					+ height);
		}

		@Override
		public void onDrawFrame(GL10 gl) {
			//定义显示在屏幕上的什么位置(opengl 自动转换)
			gl.glViewport(0, 0, glView.getWidth(), glView.getHeight());
			// gl.glViewport(50, 50,430, 550);
			gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
			gl.glMatrixMode(GL10.GL_PROJECTION);
			gl.glLoadIdentity();
			//设置视锥体的大小,一个很扁的长方体
			gl.glOrthof(0, 320, 0, 480, 0, 1);
			//颜色设置为红色
			gl.glColor4f(1, 0, 0, 1);
			gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertices);
			//画出这个三角形
			gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 3,
					GL10.GL_UNSIGNED_SHORT, indices);
		}
	}
}

3.代码效果图(左边是手机上的效果,右边是虚拟3D中的效果):

  

下面是示例代码下载:gl-basics


文章源地址: http://www.waitingfy.com/?p=34

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

瓦力冫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值