androidopengl贴图
A. 如何使用Android中的OpenGL ES媒体效果
设置OpenGL ES环境
创建GLSurfaceView
为了显示OpenGL的图形,你需要使用GLSurfaceView类,就像其他任何的View子类意义,你可以将它添加到你的Activity或Fragment之上,通过在布局xml文件中定义或者在代码中创建实例。
在本次的教程中,我们使用GLSurfaceView作为唯一的View在我们的Activity中,因此,为了简便,我们在代码中创建GLSurfaceView的实例并将其传入setContentView中,这样它将会填充你的整个手机屏幕。Activity中的onCreate方法如下:
<code class="hljs" java="">protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView view = new GLSurfaceView(this); setContentView(view);}</code>
因为媒体效果的框架仅仅支持OpenGL ES2.0及以上的版本,所以在setEGLContextClientVersion 方法中传入2;
<code avrasm="" class="hljs">view.setEGLContextClientVersion(2);</code>
为了确保GLSurfaceView仅仅在必要的时候进行渲染,我们在setRenderMode 方法中进行设置:
<code avrasm="" class="hljs">view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);</code>
创建Renderer
Renderer负责渲染GLSurfaceView中的内容。
创建类实现接口GLSurfaceView.Renderer,在这里我们打算将这个类命名为EffectsRenderer,添加构造函数并覆写接口中的抽象方法,如下:
<code class="hljs" java="">public class EffectsRenderer implements GLSurfaceView.Renderer { public EffectsRenderer(Context context){ super(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } @Override public void onDrawFrame(GL10 gl) { }}</code>
回到Activity中调用setRenderer方法,让GLSurfaceView使用我们创建的Renderer:
<code class="hljs" cs="">view.setRenderer(new EffectsRenderer(this));</code>
编写Manifest文件
如果你想要发布你的App到谷歌商店,在AndroidManifest.xml文件中添加如下语句:
<code class="hljs" xml=""><uses-feature android:glesversion="0x00020000" android:required="true"></uses-feature></code>
这会确保你的app只能被安装在支持OpenGL ES2.0的设备之上。现在OpenGL环境准备完毕。
创建一个OpenGL平面
定义顶点
GLSurfaceView是不能直接显示一张照片的,照片首先应该被转化为纹理,应用在OpenGL square之上。在本次教程中,我将创建一个2D平面,并且具有4个顶点。为了简单,我将使用一个长方形,现在,创建一个新的类Square,用它来代表形状。
<code class="hljs" cs="">public class Square {}</code>
默认的OpenGL系统的坐标系中的原点是在中心,因此4个角的坐标可以表示为:
左下角: (-1, -1) 右下角:(1, -1) 右上角:(1, 1) 左上角:(-1, 1)
我们使用OpenGL绘制的所有的物体都应该是由三角形决定的,为了画一个方形,我们需要两个具有一条公共边的三角形,那意味着这些三角形的坐标应该是:
triangle 1: (-1, -1), (1, -1), 和 (-1, 1) triangle 2: (1, -1), (-1, 1), 和 (1, 1)
创建一个float数组来代表这些顶点:
<code class="hljs" cpp="">private float vertices[] = { -1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f,};</code>
为了在square上定位纹理,需要确定纹理的顶点坐标,创建另一个数组来表示纹理顶点的坐标:
<code class="hljs" cpp="">private float textureVertices[] = { 0f,1f, 1f,1f, 0f,0f, 1f,0f};</code>
创建缓冲区
这些坐标数组应该被转变为缓冲字符(byte buffer)在OpenGL可以使用之前,接下来进行定义:
<code class="hljs" cs="">private FloatBuffer verticesBuffer;private FloatBuffer textureBuffer;</code>
在initializeBuffers方法中去初始化这些缓冲区:使用ByteBuffer.allocateDirect来创建缓冲区,因为float是4个字节,那么我们需要的byte数组的长度应该为float的4倍。
下面使用ByteBuffer.nativeOrder方法来定义在底层的本地平台上的byte的顺序。使用asFloatBuffer方法将ByteBuffer转化为FloatBuffer,在FloatBuffer被创建后,我们调用put方法来将float数组放入缓冲区,最后,调用position方法来保证我们是由缓冲区的开头进行读取。
<code avrasm="" class="hljs">private void initializeBuffers(){ ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4); buff.order(ByteOrder.nativeOrder()); verticesBuffer = buff.asFloatBuffer(); verticesBuffer.put(vertices); verticesBuffer.position(0); buff = ByteBuffer.allocateDirect(textureVertices.length * 4); buff.order(ByteOrder.nativeOrder()); textureBuffer = buff.asFloatBuffer(); textureBuffer.put(textureVertices); textureBuffer.position(0);}</code>
创建着色器
着色器只不过是简单的运行在GPU中的每个单独的顶点的C程序,在本次教程中,我们使用两种着色器:顶点着色器和片段着色器。
顶点着色器的代码:
<code class="hljs" glsl="">attribute vec4 aPosition; attribute vec2 aTexPosition; varying vec2 vTexPosition; void main() { gl_Position = aPosition; vTexPosition = aTexPosition; };</code>
片段着色器的代码
<code class="hljs" glsl="">precision mediump float; uniform. sampler2D uTexture; varying vec2 vTexPosition; void main() { gl_FragColor = texture2D(uTexture, vTexPosition); };</code>
如果你了解OpenGL,那么这段代码对你来说是熟悉的,如果你不能理解这段代码,你可以参考OpenGL documentation。
B. android opengl es给多个矩形上纹理
诶呀,你这种用法大错特错了呀!
texImage2D 不能乱用呀 , 他是把资源导入GL用的,有点像玩游戏时的Loading.你应该在你的程序初始化时
先glGentexture 生成多个纹理句柄...然后BindTexture ,再把你需要的图片依次输入...这时GL已经拥有了你全部的图片资源 ,然后在绘制的时候,
用到哪张纹理 就先Bind 这个纹理,然后DrawArray ,再Bind 再DrawArray/DrawElement..
哪有你这样每次draw 都要texImage2D 的? 这不要慢死了...
推荐你去power vr的网站下载Opengles的pc端 SDK ,里面好多demo
C. Android OpenGL ES(四)-为平面图添加滤镜
上一章加载图片的过程,在这里就不做赘述。
之前我们通过YUV数据格式的处理知道,只要保留Y的数据,就是灰度的图片。但是OpenGL中处理的是RGB格式的数据,我们要如何去取得灰度图呢?
我们可以通过公式,计算出新的RGB值,就是灰度的图片了。
我们的目标已经确定。下面我们需要将片段着色器上的每个像素的RGB值,通过上面的公式计算,装换成我们的灰度值。
根据上面的思路,我们需要去改片元着色器。 texture_fragment_shader.glsl
对比之前的,需要是有如下的修改点:
按照之前的想法,我们需要将我们的公式中的系数传递进入,就可以完成我们的操作了。基于之前的认识,我们知道传递我们的属性 uniform 给OpenGL的都是通过创建数组,绑定属性,这一套流程。
与上面的黑白色的处理相似,冷色调的处理就是单一增加蓝色通道的值,暖色调的处理可以增加红绿通道的值。
不管是冷色还是暖色。每个像素的颜色都和我们传入的色值相加,产生偏置之后的颜色。同时还要确保颜色的值合法。如果超过最大,或者小于最小,就用极限值表示。
还是之前的套路。
红黄通道增加的结果
蓝色通道增加的结果
图片模糊处理相对上面的色调处理稍微复杂一点,通常图片模糊处理是采集周边多个点,
然后利用这些点的色彩和这个点自身的色彩进行计算,得到一个新的色彩值作为目标色彩。
模糊处理有很多算法,类似高斯模糊、径向模糊等等。
最常用的还是高斯模糊。先看一下高斯模糊的原理。
使用正态分布作为权重分配模式,对周围像素取平均值的方式,就是高斯模糊。
在图形上,正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。
计算平均值的时候,我们只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。
上面的正态分布是一维的,图像都是二维的,所以我们需要二维的正态分布。
二维高斯函数:
有了这个函数 ,就可以计算每个点的权重了。
为了计算权重矩阵,需要设定σ的值。假定σ=1.5,则 模糊半径为1 的权重矩阵,权重之和等于1,得到最终的权重矩阵。
对所有点重复这个过程,就得到了高斯模糊后的图像。如果原图是彩色图片,可以对RGB三个通道分别做高斯模糊。
如果一个点处于边界,周边没有足够的点,怎么办?
一个变通方法,就是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵。
上面着色器。我们是计算好了卷积核,直接在 shader 内写死应用的。
这一小节的内容耗时比较长。其实就是利用OpenGL的shader对图像进行简单的滤镜处理。
从这节我们学习到
下一章,会回到Android的内容。将OpenGl和Camera结合在一起。通过OpenGl来显示一个预览的画面。
D. 为什么使用 android opengl
准备 为了开始本次的教程,你必须具备: 1.一款支持Android开发的IDE,如果你没有的话,可以在Android Developer website下载最新版本的Android studio。 2.一款运行Android4.0之上Android手机,并且GPU支持OpenGL ES2.0 3.对OpenGL的基本知识了解 设置OpenGL ES环境 创建GLSurfaceView 为了显示OpenGL的图形,你需要使用GLSurfaceView类,就像其他任何的View子类意义,你可以将它添加到你的Activity或Fragment之上,通过在布局xml文件中定义或者在代码中创建实例。 在本次的教程中,我们使用GLSurfaceView作为唯一的View在我们的Activity中,因此,为了简便,我们在代码中创建 GLSurfaceView的实例并将其传入setContentView中,这样它将会填充你的整个手机屏幕。Activity中的onCreate方 法如下: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView view = new GLSurfaceView(this); setContentView(view); }123456123456 因为媒体效果的框架仅仅支持OpenGL ES2.0及以上的版本,所以在setEGLContextClientVersion 方法中传入2; view.setEGLContextClientVersion(2);11 为了确保GLSurfaceView仅仅在必要的时候进行渲染,我们在setRenderMode 方法中进行设置: view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);11 创建Renderer Renderer负责渲染GLSurfaceView中的内容。 创建类实现接口GLSurfaceView.Renderer,在这里我们打算将这个类命名为EffectsRenderer,添加构造函数并覆写接口中的抽象方法,如下: public class EffectsRenderer implements GLSurfaceView.Renderer { public EffectsRenderer(Context context){ super(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } @Override public void onDrawFrame(GL10 gl) { } } 回到Activity中调用setRenderer方法,让GLSurfaceView使用我们创建的Renderer: view.setRenderer(new EffectsRenderer(this));11 编写Manifest文件 如果你想要发布你的App到谷歌商店,在AndroidManifest.xml文件中添加如下语句: <uses-feature android:glEsVersion="0x00020000" android:required="true" />11 这会确保你的app只能被安装在支持OpenGL ES2.0的设备之上。现在OpenGL环境准备完毕。 创建一个OpenGL平面 定义顶点 GLSurfaceView是不能直接显示一张照片的,照片首先应该被转化为纹理,应用在OpenGL square之上。在本次教程中,我将创建一个2D平面,并且具有4个顶点。为了简单,我将使用一个长方形,现在,创建一个新的类Square,用它来代表形状。 public class Square { }123123 默认的OpenGL系统的坐标系中的原点是在中心,因此4个角的坐标可以表示为: 左下角: (-1, -1) 右下角:(1, -1) 右上角:(1, 1) 左上角:(-1, 1) 我们使用OpenGL绘制的所有的物体都应该是由三角形决定的,为了画一个方形,我们需要两个具有一条公共边的三角形,那意味着这些三角形的坐标应该是: triangle 1: (-1, -1), (1, -1), 和 (-1, 1) triangle 2: (1, -1), (-1, 1), 和 (1, 1) 创建一个float数组来代表这些顶点: private float vertices[] = { -1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f, };123456123456
E. android opengl es中,我画好了一个立方体,在oncreate中贴好了纹理,在后面我想更换纹理,怎么做啊
新建一个纹理,在绘制的时候使用新的纹理就可以了
F. android 中OpenGL的glBindTexture方法,第二个参数 纹理名称是什么意思
我也是菜鸟啊 ,我的设计还没开始呢 ,下面这段话希望能对你有帮助,网上一个教程上看到的 前面已经提到过,载入一幅纹理所需要的时间是比较多的。因此应该尽量减少载入纹理的次数。如果只有一幅纹理,则应该在第一次绘制前就载入它,以后就不需要再次载入了。这点与glDrawPixels函数很不相同。每次使用glDrawPixels函数,都需要把像素数据重新载入一次,因此用 glDrawPixels函数来反复绘制图象的效率是较低的(如果只绘制一次,则不会有此问题),使用纹理来反复绘制图象是可取的做法。 但是,在每次绘制时要使用两幅或更多幅的纹理时,这个办法就行不通了。你可能会编写下面的代码: glTexImage2D( /* ... */ ); // 载入第一幅纹理 // 使用第一幅纹理 glTexImage2D( /* ... */ ); // 载入第二幅纹理 // 使用第二幅纹理 // 当纹理的数量增加时,这段代码会变得更加复杂。 在绘制动画时,由于每秒钟需要将画面绘制数十次,因此如果使用上面的代码,就会反复载入纹理,这对计算机是非常大的负担,以目前的个人计算机配置来说,根本就无法让动画能够流畅的运行。因此,需要有一种机制,能够在不同的纹理之间进行快速的切换。 纹理对象正是这样一种机制。我们可以把每一幅纹理(包括纹理的像素数据、纹理大小等信息,也包括了前面所讲的纹理参数)放到一个纹理对象中,通过创建多个纹理对象来达到同时保存多幅纹理的目的。这样一来,在第一次使用纹理前,把所有的纹理都载入,然后在绘制时只需要指明究竟使用哪一个纹理对象就可以了。 使用纹理对象和使用显示列表有相似之处:使用一个正整数来作为纹理对象的编号。在使用前,可以调用glGenTextures来分配纹理对象。该函数有两种比较常见的用法: GLuint texture_ID; glGenTextures(1, &texture_ID); // 分配一个纹理对象的编号 或者: GLuint texture_ID_list[5]; glGenTextures(5, texture_ID_list); // 分配5个纹理对象的编号 零是一个特殊的纹理对象编号,表示“默认的纹理对象”,在分配正确的情况下,glGenTextures不会分配这个编号。与glGenTextures对应的是glDeleteTextures,用于销毁一个纹理对象。 在分配了纹理对象编号后,使用glBindTexture函数来指定“当前所使用的纹理对象”。然后就可以使用glTexImage*系列函数来指定纹理像素、使用glTexParameter*系列函数来指定纹理参数、使用glTexCoord*系列函数来指定纹理坐标了。如果不使用 glBindTexture函数,那么glTexImage*、glTexParameter*、glTexCoord*系列函数默认在一个编号为0的纹理对象上进行操作。glBindTexture函数有两个参数,第一个参数是需要使用纹理的目标,因为我们现在只学习二维纹理,所以指定为 GL_TEXTURE_2D,第二个参数是所使用的纹理的编号。 使用多个纹理对象,就可以使OpenGL同时保存多个纹理。在使用时只需要调用glBindTexture函数,在不同纹理之间进行切换,而不需要反复载入纹理,因此动画的绘制速度会有非常明显的提升。典型的代码如下所示: // 在程序开始时:分配好纹理编号,并载入纹理 glGenTextures( /* ... */ ); glBindTexture(GL_TEXTURE_2D, texture_ID_1); // 载入第一幅纹理 glBindTexture(GL_TEXTURE_2D, texture_ID_2); // 载入第二幅纹理 // 在绘制时,切换并使用纹理,不需要再进行载入 glBindTexture(GL_TEXTURE_2D, texture_ID_1); // 指定第一幅纹理 // 使用第一幅纹理 glBindTexture(GL_TEXTURE_2D, texture_ID_2); // 指定第二幅纹理 // 使用第二幅纹理 提示:纹理对象是从OpenGL 1.1版开始才有的,最旧版本的OpenGL 1.0并没有处理纹理对象的功能。不过,我想各位的机器不会是比OpenGL 1.1更低的版本(Windows 95就自带了OpenGL 1.1版本,遗憾的是,Microsoft对OpenGL的支持并不积极,Windows XP也还采用1.1版本。据说Vista使用的是OpenGL 1.4版。当然了,如果安装显卡驱动的话,现在的主流显卡一般都附带了适用于该显卡的OpenGL 1.4版或更高版本),所以这个问题也就不算是问题了。
G. 如何使用Android中的OpenGL ES媒体效果
Android的媒体效果框架允许开发者可以很容易的应用多种令人印象深刻的视觉效果到照片或视频之上。作为这个媒体效果的框架,它使用GPU来处
理图片处理的过程,它仅仅接收OpenGL的纹理(texture)作为输入。在本次教程中,你将会学习到如何使用OpenGL
ES2.0将图片资源转化为纹理,以及如何使用框架为图片应用不同的处理效果。
准备
为了开始本次的教程,你必须具备:
1.一款支持Android开发的IDE,如果你没有的话,可以在Android Developer website下载最新版本的Android studio。
2.一款运行Android4.0之上Android手机,并且GPU支持OpenGL ES2.0
3.对OpenGL的基本知识了解
设置OpenGL ES环境
创建GLSurfaceView
为了显示OpenGL的图形,你需要使用GLSurfaceView类,就像其他任何的View子类意义,你可以将它添加到你的Activity或Fragment之上,通过在布局xml文件中定义或者在代码中创建实例。
在本次的教程中,我们使用GLSurfaceView作为唯一的View在我们的Activity中,因此,为了简便,我们在代码中创建
GLSurfaceView的实例并将其传入setContentView中,这样它将会填充你的整个手机屏幕。Activity中的onCreate方
法如下:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView view = new GLSurfaceView(this);
setContentView(view);
}
因为媒体效果的框架仅仅支持OpenGL ES2.0及以上的版本,所以在setEGLContextClientVersion 方法中传入2;
view.setEGLContextClientVersion(2);
为了确保GLSurfaceView仅仅在必要的时候进行渲染,我们在setRenderMode 方法中进行设置:
view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
创建Renderer
Renderer负责渲染GLSurfaceView中的内容。
创建类实现接口GLSurfaceView.Renderer,在这里我们打算将这个类命名为EffectsRenderer,添加构造函数并覆写接口中的抽象方法,如下:
public class EffectsRenderer implements GLSurfaceView.Renderer {
public EffectsRenderer(Context context){
super();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
}
@Override
public void onDrawFrame(GL10 gl) {
}
}
回到Activity中调用setRenderer方法,让GLSurfaceView使用我们创建的Renderer:
view.setRenderer(new EffectsRenderer(this));
编写Manifest文件
如果你想要发布你的App到谷歌商店,在AndroidManifest.xml文件中添加如下语句:
这会确保你的app只能被安装在支持OpenGL ES2.0的设备之上。现在OpenGL环境准备完毕。
创建一个OpenGL平面
定义顶点
GLSurfaceView是不能直接显示一张照片的,照片首先应该被转化为纹理,应用在OpenGL square之上。在本次教程中,我将创建一个2D平面,并且具有4个顶点。为了简单,我将使用一个长方形,现在,创建一个新的类Square,用它来代表形状。
public class Square {
}
默认的OpenGL系统的坐标系中的原点是在中心,因此4个角的坐标可以表示为:
左下角: (-1, -1) 右下角:(1, -1) 右上角:(1, 1) 左上角:(-1, 1)
我们使用OpenGL绘制的所有的物体都应该是由三角形决定的,为了画一个方形,我们需要两个具有一条公共边的三角形,那意味着这些三角形的坐标应该是:
triangle 1: (-1, -1), (1, -1), 和 (-1, 1) triangle 2: (1, -1), (-1, 1), 和 (1, 1)
创建一个float数组来代表这些顶点:
private float vertices[] = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f,
};
为了在square上定位纹理,需要确定纹理的顶点坐标,创建另一个数组来表示纹理顶点的坐标:private float textureVertices[] = {
0f,1f,
1f,1f,
0f,0f,
1f,0f
};
H. android 用png图像做opengl纹理时出现黑边怎么解决
诶呀,你这种用法大错特错了呀!texImage2D不能乱用呀,他是把资源导入GL用的,有点像玩游戏时的Loading.你应该在你的程序初始化时先glGentexture生成多个纹理句柄然后BindTexture,再把你需要的图片依次输入这时GL已经拥有了你全部的图片资源,然后在绘制的时候,用到哪张纹理就先Bind这个纹理,然后DrawArray,再Bind再DrawArray/DrawElement..哪有你这样每次draw都要texImage2D的?这不要慢死了推荐你去powervr的网站下载Opengles的pc端SDK,里面好多demo