欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

OpenGL ES学习之GLSurfaceView的使用讲解

程序员文章站 2023-04-01 20:12:15
一.glsurfaceview概述 glsurfaceview从android 1.5(api level 3)开始加入,继承自surfaceview,实现了surfaceholder.callba...

一.glsurfaceview概述

glsurfaceview从android 1.5(api level 3)开始加入,继承自surfaceview,实现了surfaceholder.callback2接口,拥有surfaceview的全部特性,也有view所有的功能和属性,特别是处理事件的能力,它主要是在surfaceview的基础上它加入了egl的管理,并自带了一个glthread绘制线程(eglcontext创建gl环境所在线程即为gl线程),绘制的工作直接通过opengl在绘制线程进行,不会阻塞主线程,绘制的结果输出到surfaceview所提供的surface上,这使得glsurfaceview也拥有了opengles所提供的图形处理能力,通过它定义的render接口,使更改具体的render的行为非常灵活性,只需要将实现了渲染函数的renderer的实现类设置给glsurfaceview即可。

glsurfaceview的特性:

1.管理一个surface,这个surface就是一块特殊的内存,能直接排版到android的视图view上。

2.管理一个egl display,它能让opengl把内容渲染到上述的surface上。

3.用户自定义渲染器(render)。

4.让渲染器在独立的线程里运作,和ui线程分离。

5.支持按需渲染(on-demand)和连续渲染(continuous)。

6.可以封装、跟踪并且排查渲染器的问题。

二.glsurfaceview的基本使用

1.创建glsurfaceview

glsurfaceview一般有两种创建方式:(1)一种是在android布局文件中配置;(2)直接在代码中new出来;

以下是第一种方式:xml文件中配置:





 


在上面的代码中,因为glsurfaceview本身就是一个view控件,所以是可以直接在xml中添加该控件,然后就可以直接在activity或者fragment中通过id找到该控件并操作它;

以下是通过new的方法直接创建glsurfaceview的实例:

package com.yh.opengltext01;

import android.app.activity;
import android.app.activitymanager;
import android.content.pm.configurationinfo;
import android.opengl.glsurfaceview;
import android.os.build;
import android.os.bundle;
import android.widget.toast;

public class mainactivity extends activity {

 private glsurfaceview mglsurfaceview;
 private boolean mrendererset = false;

 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);

  mglsurfaceview = new glsurfaceview(this);

  final activitymanager activitymanager = (activitymanager) getsystemservice(activity_service);

  final configurationinfo configurationinfo = activitymanager.getdeviceconfigurationinfo();

  final boolean supportses2 = configurationinfo.reqglesversion >= 0x20000
 ||(build.version.sdk_int >= build.version_codes.ice_cream_sandwich_mr1)
 &&(build.fingerprint.startswith("generic"))
 || build.fingerprint.startswith("unknow")
 || build.model.contains("google_sdk")
 || build.model.contains("emulator")
 || build.model.contains("android sdk built for x86");

  if (supportses2){
mglsurfaceview.seteglcontextclientversion(2);
mglsurfaceview.setrenderer(new simplerenderer(this));
mrendererset = true;
  }else {
toast.maketext(this , "this device does not support opengl es 2.0." ,
  toast.length_short).show();
return;
  }

  setcontentview(mglsurfaceview);
 }

 @override
 protected void onpause() {
  if (mrendererset){
mglsurfaceview.onpause();
  }
  super.onpause();
 }

 @override
 protected void onresume() {
  super.onresume();
  if (mrendererset){
mglsurfaceview.onresume();
  }
 }
}
activity的oncreate方法中首先我们就创建glsurfaceview的实例:
mglsurfaceview = new glsurfaceview(this);
第二步我们判断了当前设备是否支持opengl es2,不支持我们直接retrun,并做相应的提示,后面“||”是为了判断设备是不是模拟器的情况:
final boolean supportses2 = configurationinfo.reqglesversion >= 0x20000
  ||(build.version.sdk_int >= build.version_codes.ice_cream_sandwich_mr1)
  &&(build.fingerprint.startswith("generic"))
  || build.fingerprint.startswith("unknow")
  || build.model.contains("google_sdk")
  || build.model.contains("emulator")
  || build.model.contains("android sdk built for x86");
第三步如果支持,我们为我们glsurfaceview配置一些简单的属性,并为它设置渲染器(render),渲染器我们之后会解释:
mglsurfaceview.seteglcontextclientversion(2);
//设置渲染器
mglsurfaceview.setrenderer(new simplerenderer(this));
第四步,把我们glsurfaceview的生命周期和activity的生命周期绑定:
@override
protected void onpause() {
 if (mrendererset){
  mglsurfaceview.onpause();
 }
 super.onpause();
}

@override
protected void onresume() {
 if (mrendererset){
  mglsurfaceview.onresume();
 }
super.onresume();
}

以上第二步到最后一步在使用id获取glsurfaceview也是需要这样做的;

这样一个简单初始化glsurfaceview的初始化就做好了;

三.glsurfaceview的事件处理

为了处理事件,一般都是继承glsurfaceview类并重载它的事件方法,但是由于glsurfaceview是多线程的,渲染器在独立的渲染线程里,你应该使用java的跨线程机制跟渲染器通讯,glsurfaceview提供的queueevent(runnable)方法就是一种相对简单的操作,queueevent()方法被安全地用于在ui线程和渲染线程之间进行交流通信:

该方法的原型:

/**
 * queue a runnable to be run on the gl rendering thread. this can be used
 * to communicate with the renderer on the rendering thread.
 * must not be called before a renderer has been set.
 * @param r the runnable to be run on the gl rendering thread.
 */
public void queueevent(runnable r) {
 mglthread.queueevent(r);
}

简单的使用:

package com.yh.opengltext01;

import android.content.context;
import android.opengl.glsurfaceview;
import android.util.attributeset;
import android.view.keyevent;
import android.view.motionevent;

public class myglsurfaceview extends glsurfaceview {
 public myglsurfaceview(context context) {
  super(context);
 }

 public myglsurfaceview(context context, attributeset attrs) {
  super(context, attrs);
 }

 @override
 public boolean onkeydown(int keycode, keyevent event) {

  if (keycode == keyevent.keycode_dpad_center) {
queueevent(new runnable() {
 // 这个方法会在渲染线程里被调用
 public void run() {
  //todo 写自己的逻辑
 }
});
return true;
  }
  return super.onkeydown(keycode, event);
 }

 @override
 public boolean ontouchevent(motionevent event) {

  queueevent(new runnable() {
public void run() {
 //todo 做自己的逻辑
}
  });
  return super.ontouchevent(event);
 }
}

如果在ui线程里调用渲染器的方法,因为ui事件和渲染绘制是在不同的线程里,会收到“call to opengl es api with no current context”的警告,典型的案例就是在键盘或触摸事件方法里直接调用opengl es的api。

以上就是openglsurfaceview的简单使用;