文章传送门
OpenGL ES 2.0 for Android教程(二)
OpenGL ES 2.0 for Android教程(三)
OpenGL ES 2.0 for Android教程(四)
OpenGL ES 2.0 for Android教程(五)
OpenGL ES 2.0 for Android教程(六)
OpenGL ES 2.0 for Android教程(七)
本文是一系列的OpenGL ES 2.0 for Android教程。本系列的绝大部分内容机翻(主要是百度翻译)自英文版的《OpenGL ES 2.0 for Android——A Quick-Start Guide》,作者是Kevin Brothaler。这本书的内容非常浅显易懂,适合对OpenGL ES完全没有任何概念的人入门。但是由于这本书是2013年出版的,里面的Android代码示例使用Java编写,因此决定,这一系列的文章构建在翻译机翻书中的内容的基础上,但又不完全照搬,例如,所有的Android代码示例都将采用Kotlin+Compose重新编写。
在Android、苹果的iOS和许多其他移动平台上,开发人员通过名为OpenGL的跨平台应用程序编程界面创建2D和3D图形。OpenGL已经在桌面上使用了一段时间,移动平台使用了一种称为OpenGL ES的特殊嵌入式版本。
OpenGL ES的第一个版本将3D应用到了移动设备上,这非常受开发人员的欢迎,因为它易于学习,并且具有定义良好的功能集。然而,该功能集也很有限,无法跟上最强大的智能手机和平板电脑的最新和最强大功能。
进入OpenGL ES 2.0。大多数旧的API被完全删除,并被新的可编程API取代,这使得添加特效和利用最新设备所提供的功能变得更加容易。这些设备现在可以生产与几年前的控制台相匹敌的图形!然而,为了利用这种能力,我们需要学习2.0附带的新API。2012年8月,Khronos集团最终确定了下一个版本OpenGL ES 3.0的规范,该版本与2.0完全兼容,并通过一些高级功能对其进行了扩展。
那么,在Android上使用OpenGL可以做什么呢?我们可以制作出令人惊叹的实时壁纸,并让数百万用户下载。我们可以创造一个引人注目的3D游戏,它有着生动而惊人的图形。随着硬件成本的下降和云存储的日益扩大,这是一个开始的好时机!
以下是我们将要讨论的内容:
Android 支持OpenGL ES API版本的状况如下:
- OpenGL ES 1.0 和 1.1 能够被Android 1.0及以上版本支持
- OpenGL ES 2.0 能够被Android 2.2及更高版本支持
- OpenGL ES 3.0 能够被Android 4.3及更高版本支持
- OpenGL ES 3.1 能够被Android 5.0及以上版本支持
我们将使用OpenGL来代指OpenGL ES 2.0,这是适用于移动和Web的OpenGL的现代版本。
在本书的大部分内容中,我们将使用GLES20类,它是Android软件开发工具包(SDK)的一部分。因为我们的大多数OpenGL常量和方法都在这个类中,所以我通常会省略类名,直接提到常量或方法。我们将使用静态导入来省略代码中的类名。
请随时访问我(该书作者)维护的OpenGL ES教程博客Learn OpenGL ES。
以下是Khronos集团维护的一些优秀在线资源列表:
我建议把参考卡打印出来,放在手边,这样你可以在需要的时候快速查阅。Android使用EGL(一个本地平台接口)来帮助设置显示,因此您可能还会发现Khronos EGL API注册表很有用。
原书章节花费大量篇幅描述如何配置Android环境,这里省略。
我们先来介绍SurfaceView与它的子类GLSurfaceView,后者能够操纵OpenGL ES,本书的重点。
SurfaceView是一个特殊的View,特殊在于它拥有一层独立的绘图表面,而基础控件中,例如TextView或者Button,它们都将自己的UI绘制在宿主窗口的绘图表面之上,也就是说它们的绘制均在主线程进行。SurfaceView拥有独立于宿主窗口的绘图表面表明它的绘制实际上可以在子线程进行,这非常有利于实现复杂的绘图渲染,例如播放视频。
作为子类的GLSurfaceView封装了OpenGL初始化的细节方面,例如在后台线程上配置显示和渲染。这种渲染是在显示器的一个特殊区域进行的,称为表面(surface);这有时也称为viewport。GLSurfaceView类还可以轻松处理标准的Android活动生命周期,它提供了onResume()和onPause(),方便启动和暂停绘制。
GLSurfaceView的绘制行为由接口GLSurfaceView.Renderer指定,该接口有以下三个方法:
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?)
GLSurfaceView在创建Surface时调用此函数。这会在应用程序第一次运行时发生,也可能在设备唤醒或用户切换回我们的活动时调用。实际上,这意味着在应用程序运行时,可以多次调用此方法。
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int)
GLSurfaceView在创建Surface后以及在大小发生更改时调用此函数,这些变化包括GLSurfaceView的大小或设备屏幕方向的变化。我们应该使用此方法来响应GLSurfaceView容器的改变。
override fun onDrawFrame(gl: GL10?)
GLSurfaceView在绘制一帧内容时调用此方法。我们必须进行一些绘制操作,即使只是清除屏幕。在这个方法返回后,渲染缓冲区将被交换并显示在屏幕上,因此如果我们不绘制任何东西,我们可能会得到糟糕的闪烁效果。
GL10类型的参数是OpenGL ES 1.0 API的残余。如果我们在编写OpenGL ES 1.0渲染器,我们会使用这个参数,但是对于OpenGL ES 2.0,我们在GLES20类上调用静态方法。
GLSurfaceView将在单独的线程上调用渲染器方法。默认情况下,GLSurfaceView将持续渲染,通常以显示器的刷新率进行渲染,但我们也可以将GLSurfaceView配置为仅在请求时渲染,调用GLSurfaceView类的setRenderMode(),传入GLSurfaceView.RENDERMODE_WHEN_DIRTY。我们还可以调用queueEvent()以在后台渲染线程上发布Runnable。
GLSurfaceView实际上创建了自己的窗口,并在视图层次中打了一个“洞”,以便显示底层的OpenGL曲面。对于许多用途来说,这已经足够好了;然而,由于GLSurfaceView是单独窗口的一部分,因此它不像常规View那样具有动画效果或变换效果。
从Android4.0开始,安卓提供了一个TextureView,可以用来渲染OpenGL,而不需要单独的窗口,这意味着TextureView 可以像任何常规View一样进行操作、设置动画和转换。由于TextureView类中没有内置OpenGL初始化,因此使用TextureView的一种方法是执行自己的OpenGL初始化并在TextureView上运行该初始化;另一个方法是获取GLSurfaceView的源代码,并将其改编为TextureView
补充:为什么在绘制时我们需要不断地清除屏幕?
如果我们已经在每一帧上绘制了整个屏幕,那么清除屏幕似乎浪费时间,我们为什么需要这样做?
在软件中呈现所有内容的年代,清除屏幕通常是浪费时间的。开发人员通过假设所有内容都将被重新绘制来进行优化,因此无需擦除前一帧中的内容。他们这样做是为了节省本来会被浪费的处理时间,但这有时会导致著名的“镜子大厅”(hall of mirrors)效应,如在某些游戏中所看到的:由此产生的视觉效果就像是在一个镜子的大厅中,上一帧的部分内容仍留在屏幕中。
这种优化在今天已不再有用。最新的GPU的工作方式有所不同,它们使用特殊的渲染技术,屏幕被清除实际上可以帮助GPU更快地工作。通过让GPU清除屏幕,我们节省了把前一帧的画面复制到这一帧时浪费的时间。由于目前GPU的工作方式,清除屏幕也有助于避免出现闪烁或无法绘制的问题。保留旧内容可能会导致意外的结果。
关于“hall of mirrors”效应的相关资料:
https://en.wikipedia.org/wiki/Noclip_mode
本系列教程示例采用Kotlin 1.6.10以及Compose 1.1.1编写。
根目录下的build.gradle添加:
dependencies {
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10'
}
上述语句是为了保持kotlin版本为1.6.10
在app下面的build.gradle添加:
android {
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion "1.1.1"
}
}
dependencies {
def compose_version = "1.1.1"
implementation "androidx.core:core-ktx:1.7.0"
implementation "androidx.appcompat:appcompat:1.4.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
implementation "com.google.android.material:material:1.5.0"
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.activity:activity-compose:1.4.0"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
testImplementation "junit:junit:4.13.2"
androidTestImplementation "androidx.test.ext:junit:1.1.3"
androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0"
}
在AndroidManifest添加:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
class BaseGLSurfaceView
@JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
): GLSurfaceView(context, attrs) {
init {
setEGLContextClientVersion(2)
setRenderer(SampleRenderer())
}
}
setEGLContextClientVersion()要求创建OpenGL ES 2.0的上下文,将Surface的绘制配置为使用OpenGL ES 2.0。然后我们调用setRenderer()添加渲染器
class SampleRenderer: GLSurfaceView.Renderer {
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
GLES20.glClearColor(1F, 0F, 0F, 1F)
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
}
override fun onDrawFrame(gl: GL10?) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
}
}
首先,onSurfaceCreated()内调用了glClearColor(),参数依次是red、green、blue、alpha。我们将红色设置为最大强度,屏幕将在被清除时变为红色(the screen will become red when cleared)(因为clearColor就是clear事件发生之后应当显示的颜色)。
其次,onSurfaceChanged()内调用了glViewport()。这个方法设置了viewport的大小,这告诉了OpenGL可用于渲染的surface的大小。
最后,在onDrawFrame()中,我们调用glClear(GL_COLOR_BUFFER_BIT)擦除了屏幕上的所有颜色,并使用我们之前调用glClearColor()来定义的颜色填充屏幕。
创建MainActivity.kt并添加以下代码:
class MainActivity : ComponentActivity() {
private var lifecycleState by mutableStateOf(Lifecycle.Event.ON_ANY)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 观察lifecycle状态
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
lifecycleState = Lifecycle.Event.ON_RESUME
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
lifecycleState = Lifecycle.Event.ON_PAUSE
}
})
setContent {
// 在Compose下托管传统视图
AndroidView(
factory = {
BaseGLSurfaceView(context = this)
},
update = {
// lifecycleState更新时被回调
when(lifecycleState) {
Lifecycle.Event.ON_PAUSE -> {
it.onPause()
}
Lifecycle.Event.ON_RESUME -> {
it.onResume()
}
else -> {}
}
}
)
}
}
}
这里的setContent()函数是Compose特有的扩展,接收@Composable内容。但是这次我们不需要使用普通的Compose控件,我们使用特殊的Compose控件AndroidView()在Compose中托管一个传统的View。
AndroidView()的factory参数接收一个创建传统View的lambda,意在指定创建View的方式。update参数则会捕捉对State的使用,并在State更新时自动重新执行update参数传入的lambda。
我们的界面状态lifecycleState由mutableStateOf创建并托管,这个状态保存了Activity是否位于前台的信息,我们使用这个信息来控制BaseGLSurfaceView,在Activity不可见时停止刷新界面以节省绘制运算,接收状态并控制BaseGLSurfaceView的代码位于传入update的lambda参数内。而lifecycleState的数据更新取决于LifecycleObserver。
控制生命周期非常重要,这样我们的GLSurfaceView就可以适当地暂停和恢复背景渲染线程,以及释放和更新OpenGL上下文。
我们现在可以运行代码并看见效果:

1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主
1.1.1 YARN的介绍 为克服Hadoop1.0中HDFS和MapReduce存在的各种问题⽽提出的,针对Hadoop1.0中的MapReduce在扩展性和多框架⽀持⽅⾯的不⾜,提出了全新的资源管理框架YARN. ApacheYARN(YetanotherResourceNegotiator的缩写)是Hadoop集群的资源管理系统,负责为计算程序提供服务器计算资源,相当于⼀个分布式的操作系统平台,⽽MapReduce等计算程序则相当于运⾏于操作系统之上的应⽤程序。 YARN被引⼊Hadoop2,最初是为了改善MapReduce的实现,但是因为具有⾜够的通⽤性,同样可以⽀持其他的分布式计算模
我是Ruby新手,并被要求在我们的新项目中使用它。我们还被要求使用Padrino(Sinatra)作为后端/框架。我们被要求使用Rspec进行测试。我一直在寻找可以指导在Padrino上使用RspecforRuby的教程。我得到的主要是引用RoR。但是,我需要RubyonPadrino。请在任何入门/指南/引用/讨论等方面指导我。如有不妥之处请指正。可能是我没有针对我的问题搜索正确的词/短语组合。我正在使用Ruby1.9.3和Padrinov.0.10.6。注意:我还提到了SOquestion,但它没有帮助。 最佳答案 我没用过Pa
文章目录1.任务背景2.任务目标3.相关知识点4.任务实操4.1安装配置JDK4.2启动FISCOBCOS4.3下载解压WeBASE-Front4.4拷贝sdk证书文件4.5启动节点4.6访问节点4.7检查运行状态5.任务总结1.任务背景FISCOBCOS其实是有控制台管理工具,用来对区块链系统进行各种管理操作。但是对于初学者来说,还是可视化界面更友好,本节就来介绍WeBASE管理平台,这是一款微众银行开源的自研区块链中间件平台,可以降低区块链使用的门槛,大幅提高区块链应用的开发效率。微众银行是腾讯牵头设立的民营银行,在国内民营银行里还是比较出名的。微众银行参与FISCOBCOS生态建设,一定
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:FlashMessagesinPartials(Rails3)我正在做MichaelHartl的Railstutorial和listing7.26将flash消息添加到应用程序布局:...">...这很好用。但是,我试图通过在我的部分文件夹中创建一个_flash.html.erb来清理这段代码...">-->...并且比使用......在我的应用程序布局中,我的所有Rspec测试开始失败,每个测试都显示以下消息:Failure/Error:before{visitsignup_path}ActionView:
我正在使用SublimeText2,同时遵循MichaelHartl的RubyonRails教程。可以在http://ruby.railstutorial.org/book/ruby-on-rails-tutorial找到我所指的教程的具体部分。(ctrl+F“list5.26”)。我能够创建规范/支持文件。但是,在尝试创建spec/support/utilities.rb文件时,我收到消息“无法保存~/rails_projects/sample_app/spec/support/utilities.rb”。有人知道为什么会这样吗?SublimeText论坛上有人似乎遇到了完全相同的问
目录一、安装包链接二、安装详细步骤1.安装Wireshark和WinPcap2.安装OracleVMVirtualBox3.安装ensp三、安装后注册四、启动路由器出现40错误怎么解决一、安装包链接二、安装详细步骤链接:https://pan.baidu.com/s/1QbUUYMOMIV2oeIKHWP1SpA?pwd=xftx提取码:xftx1.安装Wireshark和WinPcap找到Wireshark安装包所在文件夹,双击它,按照以下步骤安装。2.安装OracleVMVirtualBox找到OracleVMVirtualBox安装包所在文件夹,双击它,按照以下步骤安装。注:可自定义安装
【适用平台】私有云 说明:完成私有云部分是需要两台虚拟机的,分别为controller、compute两个节点,但我们只需配置一台,然后克隆就方便多啦!需要用到的映射文件:关于vm的安装我就不介绍的,毕竟挺简单的,下面让我们看看基于私有云模块中,虚拟机的搭建吧。1、创建新的虚拟机,这里一般我会选择自定义,毕竟后面的配置都要根据私有云相关来进行搭建,会比较复杂。(如果是基础的可以选择典型,典型的满足一般虚拟机的配置) 2、选择稍后安装操作系统会比较方便后续的选择,这里你也可以自己选择自己的映像文件(但不建议) 3、我们是基于Linux下操作的,所以选择Linux客户机操作系统,版本选择自己
听说PostgreSQL的可以用Ruby写存储过程但我一直没能找到更多关于它的信息,教人们如何实际去做。有人可以为此推荐好的资源。谢谢 最佳答案 显然,您需要安装PL/Ruby。之后,你可以写:CREATEFUNCTIONruby_max(int4,int4)RETURNSint4AS'ifargs[0].to_i>args[1].to_ireturnargs[0]elsereturnargs[1]end'LANGUAGE'plruby';查看其GitHubrepository安装说明。