android GLSurfaceView渲染模式

2023-12-22 10:08

本文主要是介绍android GLSurfaceView渲染模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

GLSurfaceView的渲染模式。


OpenGl ES关于渲染方式有以下两种:RENDERMODE_CONTINUOUSLY和RENDERMODE_WHEN_DIRTY。

默认渲染方式为RENDERMODE_CONTINUOUSLY,当设置为RENDERMODE_CONTINUOUSLY时渲染器会不停地渲染场景,当设置为RENDERMODE_WHEN_DIRTY时只有在创建和调用requestRender()时才会刷新。

一般设置为RENDERMODE_WHEN_DIRTY方式,这样不会让CPU一直处于高速运转状态,提高手机电池使用时间和软件整体性能。


接着简单写一个OpenGL ES程序。

1.在Manifest中添加声明
  为了使用OpenGL ES 2.0 API,需要添加如下声明:

<uses-feature android:glEsVersion="0x00020000" android:required="true" />
 

  OpenGL ES 2.0 requires Android 2.2 (API Level 8) or higher,所以需要确认系统版本。

 

2.创建Activity
  在Activity的布局中,需要加入GLSurfaceView来放置绘制的图形。

  一个最简单的版本如下:


public class OpenGLES20 extends Activity {

    private GLSurfaceView mGLView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        mGLView = new MyGLSurfaceView(this);
        setContentView(mGLView);
    }
}

 

3.创建GLSurfaceView
  GLSurfaceView是一个特殊的组件,你可以在其中绘制OpenGL ES图形。

  你需要扩展这个类,在它的构造方法中设置渲染器:


class MyGLSurfaceView extends GLSurfaceView {

    public MyGLSurfaceView(Context context){
        super(context);

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(new MyRenderer());
    }
}

 如果使用OpenGL ES 2.0,还需要加一句声明:

// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
 

  还有一个可选的设置是,把渲染模式改为 GLSurfaceView.RENDERMODE_WHEN_DIRTY ,这样仅在你的数据有变化时重新进行渲染。

// Render the view only when there is a change in the drawing data
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
 

  除非你调用requestRender(),这个设置会阻止帧被重画,有些情况下这样效率更高。

 

4.建立一个Renderer类
  Renderer类(渲染器类),即 GLSurfaceView.Renderer的实现类,它控制了与它相关联的 GLSurfaceView 上绘制什么。

  其中有三个主要的回调方法:

onSurfaceCreated() - Called once to set up the view's OpenGL ES environment.
onDrawFrame() - Called for each redraw of the view.
onSurfaceChanged() - Called if the geometry of the view changes, for example when the device's screen orientation changes.


  

  一个简单的实现例子:


public class MyGL20Renderer implements GLSurfaceView.Renderer {

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        // Set the background frame color
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    }

    public void onDrawFrame(GL10 unused) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }
}

 

 

程序例子
  一个简单的程序例子,并没有绘制什么,只是设置了背景色,为了展示方便,GLSurfaceView类和渲染器类都作为Acitivity的内部类写出。

  首先在Manifest中加上声明:

 

Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloopengles"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <!-- Tell the system this app requires OpenGL ES 2.0. -->
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".HelloOpenGLESActivity"
            android:label="@string/title_activity_hello_open_gles" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

Activity

package com.example.helloopengles;

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

import android.app.Activity;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;

public class HelloOpenGLESActivity extends Activity
{
    private GLSurfaceView mGLView;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        mGLView = new MyGLSurfaceView(this);
        setContentView(mGLView);

    }

    class MyGLSurfaceView extends GLSurfaceView
    {

        public MyGLSurfaceView(Context context)
        {
            super(context);

            try
            {
                // Create an OpenGL ES 2.0 context
                setEGLContextClientVersion(2);

                // Set the Renderer for drawing on the GLSurfaceView
                setRenderer(new MyRenderer());

                // Render the view only when there is a change in the drawing
                // data
                setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

                // 注意上面语句的顺序,反了可能会出错

            }
            catch (Exception e)
            {
                e.printStackTrace();

            }

        }
    }

    public class MyRenderer implements GLSurfaceView.Renderer
    {

        public void onSurfaceCreated(GL10 unused, EGLConfig config)
        {
            // Set the background frame color
            GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        }

        public void onDrawFrame(GL10 unused)
        {
            // Redraw background color
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        }

        public void onSurfaceChanged(GL10 unused, int width, int height)
        {
            GLES20.glViewport(0, 0, width, height);
        }
    }

}

 

GLSurfaceView的绘制过程要点

1,GLSurfaceview的渲染模式RenderMode

在onAttachedToWindow后就启动了一个无线循环的子线程,该子线程完成了整个绘制流程,并系统默认是负责不断刷新重绘,刷新的帧率是16FPS。从这里也可以看出来,GLSurfaceView系统默认是60ms就重绘一次,这样的耗性能的重绘操作一定是要用在那种有持续动画的效果才有意义。

当然,你也可以通过设置setRenderMode去设置主动刷新:

 
/**
 * Set the rendering mode. When renderMode is
 * RENDERMODE_CONTINUOUSLY, the renderer is called
 * repeatedly to re-render the scene. When renderMode
 * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface
 * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY.
 *
* Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance * by allowing the GPU and CPU to idle when the view does not need to be updated. *

* This method can only be called after {@link #setRenderer(Renderer)} * * @param renderMode one of the RENDERMODE_X constants * @see #RENDERMODE_CONTINUOUSLY * @see #RENDERMODE_WHEN_DIRTY */ public void setRenderMode(int renderMode) { mGLThread.setRenderMode(renderMode); }

注解中提到:系统默认mode==RENDERMODE_CONTINUOUSLY,这样系统会自动重绘;mode==RENDERMODE_WHEN_DIRTY时,只有surfaceCreate的时候会绘制一次,然后就需要通过requestRender()方法主动请求重绘。同时也提到,如果你的界面不需要频繁的刷新最好是设置成RENDERMODE_WHEN_DIRTY,这样可以降低CPU和GPU的活动,可以省电。

 

 

2,事件处理

 

为了处理事件,一般都是继承GLSurfaceView类并重载它的事件方法。但是由于GLSurfaceView是多线程操作,所以需要一些特殊的处理。由于渲染器在独立的渲染线程里,你应该使用Java的跨线程机制跟渲染器通讯。queueEvent(Runnable)方法就是一种相对简单的操作。


class MyGLSurfaceView extends GLSurfaceView { 
    private MyRenderer mMyRenderer; 
   
        public void start() { 
            mMyRenderer = ...; 
            setRenderer(mMyRenderer); 
        } 
   
   
        public boolean onKeyDown(int keyCode, KeyEvent event) { 
   
            if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { 
                queueEvent(new Runnable() { 
                    // 这个方法会在渲染线程里被调用 
                         public void run() { 
                             mMyRenderer.handleDpadCenter(); 
                         }}); 
                     return true; 
                 } 
   
                 return super.onKeyDown(keyCode, event); 
            } 
      } 
}
 

调用queueEvent就是给队列中添加runnable

public void queueEvent(Runnable r) {
 
    synchronized(sGLThreadManager) {
        mEventQueue.add(r);
        sGLThreadManager.notifyAll();
    }
 
}

在guardenRun()中有如下代码:

 


               if (! mEventQueue.isEmpty()) {
                    event = mEventQueue.remove(0);
                    break;
                }
                 
                ...
                 
                if (event != null) {
                    event.run();
                    event = null;
                    continue;
                }
 

这篇关于android GLSurfaceView渲染模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/523562

相关文章

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

SpringBoot如何通过Map实现策略模式

《SpringBoot如何通过Map实现策略模式》策略模式是一种行为设计模式,它允许在运行时选择算法的行为,在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式,这... 目录前言底层机制解析Spring的集合类型自动装配@Resource注解的行为实现原理使用直接使用M

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D

Android如何获取当前CPU频率和占用率

《Android如何获取当前CPU频率和占用率》最近在优化App的性能,需要获取当前CPU视频频率和占用率,所以本文小编就来和大家总结一下如何在Android中获取当前CPU频率和占用率吧... 最近在优化 App 的性能,需要获取当前 CPU视频频率和占用率,通过查询资料,大致思路如下:目前没有标准的