使用OpenGL开发Android应用详解系列三

简介: 注:近三篇转载中的视锥体部分结合着来看,再参照老罗的3d变换,基本可以初步理解和完成相关视锥体调整。 使用OpenGL开发Android应用详解系列三 【原创】转载请注明出处 我一家网 http://www.5yijia.com 前面两节主要介绍了一下OpenGL的基本概念,以及在Android开发中引入OpenGL时,Android项目的基本构成情况。

注:近三篇转载中的视锥体部分结合着来看,再参照老罗的3d变换,基本可以初步理解和完成相关视锥体调整。

使用OpenGL开发Android应用详解系列三

【原创】转载请注明出处 我一家网 http://www.5yijia.com
前面两节主要介绍了一下OpenGL的基本概念,以及在Android开发中引入OpenGL时,Android项目的基本构成情况。这一节开始,我们通过具体的实例,来进行简单3D图形的描画。
注:代码基础还是采用上一节: 使用OpenGL开发Android应用详解系列二中使用的代码结构。

通过OpenGL来绘制简单立体图形

在进行绘制立体图形之前,我们先来了解一些相关术语,如果这些概念理解透彻的话,对Android中使用OpenGL开发很有帮助。

1. 相关术语理解
这里的术语包括: 坐标系,视锥体(frustum)和视窗(viewport)
(1)坐标系
为了制定三维空间内物体的位置,需要引入坐标系。下面是OpenGL的三维坐标系(注:和DirectX完全相反)

通过坐标系我们可以定义实际的物体,但是物体定义好了以后应该放在什么位置,接下来就是frustum来定义了.

2. 视锥体(frustum)

或者叫做视景,他主要用来定义物体可以表示的空间领域。

视锥体的视线方向是 -Z方向,也就是说,他是坐标轴中Z轴的反方向。请看下图:

通过从-Z方向作为视点来查看的话,视角(看的角度)与离得较近的切面,以及较远切面之间是成比例关系的.

(3)视窗(viewport)

上面图中那个蓝色的切面就是viewport,OpenGL中经常叫的视窗(viewport)。

2.OpenGL开发中使用视窗和视锥体

glViewport用来指定从标准设备的Window坐标的转换矩阵。矩阵变换主要指的是放大,缩小,旋转,截断,平行移动,线性变换的组合操作。

glViewport(GLint x,GLint y,GLsizei width,GLsizei height)为其函数原型。

参数说明:

x,y    以像素为单位,指定了视窗的左下角位置。

width,height   表示这个视窗矩形的宽度和高度,根据窗口的实时变化重绘窗口。

 

上面那个笑脸图像就是以左边图形的左下角的(x,y)坐标来投影右边图像的宽和高(width,height)。由于左边和右边的设备类别不同,导致投影后的图像变形了。为了防止变形,我们需要通过视锥体(frustum)的宽高比(aspect ratio),来让实际的设备保持和原有设备同样的比例。

在上面章节中讲过,设备大小或者纵横的方向改变时,会调用onSurfaceChanged方法,为了防止变形,我们可以通过下面的代码来控制.

@Override
	public void onSurfaceChanged(GL10 arg0, int width, int height) {
		arg0.glViewport(0, 0, width, height);

		arg0.glMatrixMode(GL10.GL_PROJECTION);
		arg0.glLoadIdentity();    
		GLU.gluPerspective(arg0, 45f,(float) width / height, 1f, 50f);
		// TODO Auto-generated method stub
	}

如果是直接绘制图形的话,opengl是没有空间的位置观念的,因为它根本不能分辨物体的前后关系。所以为了让OpenGL有前后位置的概念,我们需要使用深度缓冲区。

下面的代码设置Depth Test有效。

@Override
	public void onSurfaceCreated(GL10 arg0, EGLConfig config) {
		arg0.glEnable(GL10.GL_DEPTH_TEST);
		arg0.glDepthFunc(GL10.GL_LEQUAL);
		// TODO Auto-generated method stub
	}

3. 正方体的定义

接下来我们来定义一个正方体

package com.wuyijia.opengltest;

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

import javax.microedition.khronos.opengles.GL10;

public class MyOpenGLCube {

	//浮点缓冲区:批量get
	private final FloatBuffer mVertexBuffer;

	  /**
	   * 定义正方体坐标
	   */
	  public MyOpenGLCube(){

	    float vertices[] = {
	      //正方体前面
	      -0.5f, -0.5f, 0.5f,
	      0.5f, -0.5f, 0.5f,
	      -0.5f, 0.5f, 0.5f,
	      0.5f, 0.5f, 0.5f,

	      //正方体后面
	      -0.5f, -0.5f, -0.5f,
	      0.5f, -0.5f, -0.5f,
	      -0.5f, 0.5f, -0.5f,
	      0.5f, 0.5f, -0.5f,

	      //正方体左面
	      -0.5f, -0.5f, 0.5f,
	      -0.5f, -0.5f, -0.5f,
	      -0.5f, 0.5f, 0.5f,
	      -0.5f, 0.5f, -0.5f,

	      //正方体右面
	      0.5f, -0.5f, 0.5f,
	      0.5f, -0.5f, -0.5f,
	      0.5f, 0.5f, 0.5f,
	      0.5f, 0.5f, -0.5f,

	      //正方体上面
	      -0.5f, 0.5f, 0.5f,
	      0.5f, 0.5f, 0.5f,
	      -0.5f, 0.5f, -0.5f,
	      0.5f, 0.5f, -0.5f,

	      //正方体底面
	      -0.5f, -0.5f, 0.5f,
	      0.5f, -0.5f, 0.5f,
	      -0.5f, -0.5f, -0.5f,
	      0.5f, -0.5f, -0.5f
	    };

	    ByteBuffer vbb = 
	      ByteBuffer.allocateDirect(vertices.length * 4);
	    vbb.order(ByteOrder.nativeOrder());
	    mVertexBuffer = vbb.asFloatBuffer();
	    mVertexBuffer.put(vertices);
	    mVertexBuffer.position(0);

	  }

	  /**
	   * 绘制正方体
	   * @param gl
	   */
	  public void draw(GL10 gl){

	    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
	    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);

	    //正方体前面
	    gl.glNormal3f(0, 0, 1.0f);
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

	    //正方体后面
	    gl.glNormal3f(0, 0, -1.0f);
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);

	    //正方体左面
	    gl.glNormal3f(-1.0f, 0, 0);
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);

	    //正方体右面
	    gl.glNormal3f(1.0f, 0, 0);
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);

	    //正方体上面
	    gl.glNormal3f(0, 1.0f, 0);
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);

	    //正方体底面
	    gl.glNormal3f(0, -1.0f, 0);
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);

	  }
}

上面的类定义了一个以屏幕中心为正方形原点,边长为1的正方体。

4. 渲染正方体
接下来我们在onDrawFrame函数中渲染刚才我们定义的正方体。

MyOpenGLCube myOpenGLCube = new MyOpenGLCube();
	@Override
	public void onDrawFrame(GL10 arg0) {
		arg0.glClear(GL10.GL_COLOR_BUFFER_BIT 
		        | GL10.GL_DEPTH_BUFFER_BIT);

		arg0.glMatrixMode(GL10.GL_MODELVIEW);
		arg0.glLoadIdentity();
		arg0.glTranslatef(0, 0, -3f);

		myOpenGLCube.draw(arg0);
		// TODO Auto-generated method stub
	}

OK,正方体渲染完成后,运行我们的应用,效果图如下:

我们发现运行的效果并不是立方体,而是一个正方形。原因是我们没有旋转立方体的缘故,所以看上去就像一个正方形。加上下面的代码再看一下效果。

@Override
	public void onDrawFrame(GL10 arg0) {
		arg0.glClear(GL10.GL_COLOR_BUFFER_BIT 
		        | GL10.GL_DEPTH_BUFFER_BIT);

		arg0.glMatrixMode(GL10.GL_MODELVIEW);
		arg0.glLoadIdentity();
		arg0.glTranslatef(0, 0, -3f);

		//旋转正方体
		arg0.glRotatef(30f, 0, 1, 0);

		myOpenGLCube.draw(arg0);
		// TODO Auto-generated method stub
	}

运行后效果如下:

终于看到立体效果了。


转自:http://www.5yijia.com/?p=95


目录
相关文章
|
15天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
16天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
16天前
|
开发框架 安全 Android开发
探索安卓系统的新趋势:智能家居应用的蓬勃发展
随着智能家居概念的兴起,安卓系统在智能家居应用领域的应用日益广泛。本文将探讨安卓系统在智能家居应用开发方面的最新趋势和创新,以及其对用户生活的影响。
13 2
|
19天前
|
缓存 监控 Java
构建高效Android应用:从优化用户体验到提升性能
在竞争激烈的移动应用市场中,为用户提供流畅和高效的体验是至关重要的。本文深入探讨了如何通过多种技术手段来优化Android应用的性能,包括UI响应性、内存管理和多线程处理。同时,我们还将讨论如何利用最新的Android框架和工具来诊断和解决性能瓶颈。通过实例分析和最佳实践,读者将能够理解并实施必要的优化策略,以确保他们的应用在保持响应迅速的同时,还能够有效地利用系统资源。
|
20天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
17天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
4天前
|
搜索推荐 开发工具 Android开发
安卓即时应用(Instant Apps)开发指南
【4月更文挑战第14天】Android Instant Apps让用户体验部分应用功能而无需完整下载。开发者需将应用拆分成模块,基于已上线的基础应用构建。使用Android Studio的Instant Apps Feature Library定义模块特性,优化代码与资源以减小模块大小,同步管理即时应用和基础应用的版本。经过测试,可发布至Google Play Console,提升用户便利性,创造新获客机会。
|
5天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
5天前
|
编解码 人工智能 测试技术
安卓适配性策略:确保应用在不同设备上的兼容性
【4月更文挑战第13天】本文探讨了提升安卓应用兼容性的策略,包括理解平台碎片化、设计响应式UI(使用dp单位,考虑横竖屏)、利用Android SDK的兼容工具(支持库、资源限定符)、编写兼容性代码(运行时权限、设备特性检查)以及优化性能以适应低端设备。适配性是安卓开发的关键,通过这些方法可确保应用在多样化设备上提供一致体验。未来,自动化测试和AI将助力应对设备碎片化挑战。
|
11天前
|
移动开发 API Android开发
构建高效Android应用:探究Kotlin协程的优势与实践
【4月更文挑战第7天】 在移动开发领域,性能优化和应用响应性的提升一直是开发者追求的目标。近年来,Kotlin语言因其简洁性和功能性在Android社区中受到青睐,特别是其对协程(Coroutines)的支持,为编写异步代码和处理并发任务提供了一种更加优雅的解决方案。本文将探讨Kotlin协程在Android开发中的应用,揭示其在提高应用性能和简化代码结构方面的潜在优势,并展示如何在实际项目中实现和优化协程。