如何向GLSL中传入多个纹理

如何向GLSL中传入多个纹理,第1张

设置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) { superonCreate(savedInstanceState); GLSurfaceView view = new GLSurfaceView(this); setContentView(view);}</code>

因为媒体效果的框架仅仅支持OpenGL ES20及以上的版本,所以在setEGLContextClientVersion 方法中传入2;

<code avrasm="" class="hljs">viewsetEGLContextClientVersion(2);</code>

为了确保GLSurfaceView仅仅在必要的时候进行渲染,我们在setRenderMode 方法中进行设置:

<code avrasm="" class="hljs">viewsetRenderMode(GLSurfaceViewRENDERMODE_WHEN_DIRTY);</code>

创建Renderer

Renderer负责渲染GLSurfaceView中的内容。

创建类实现接口GLSurfaceViewRenderer,在这里我们打算将这个类命名为EffectsRenderer,添加构造函数并覆写接口中的抽象方法,如下:

<code class="hljs" java="">public class EffectsRenderer implements GLSurfaceViewRenderer { 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="">viewsetRenderer(new EffectsRenderer(this));</code>

编写Manifest文件

如果你想要发布你的App到谷歌商店,在AndroidManifestxml文件中添加如下语句:

<code class="hljs" xml=""><uses-feature android:glesversion="0x00020000" android:required="true"></uses-feature></code>

这会确保你的app只能被安装在支持OpenGL ES20的设备之上。现在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方法中去初始化这些缓冲区:使用ByteBufferallocateDirect来创建缓冲区,因为float是4个字节,那么我们需要的byte数组的长度应该为float的4倍。

下面使用ByteBuffernativeOrder方法来定义在底层的本地平台上的byte的顺序。使用asFloatBuffer方法将ByteBuffer转化为FloatBuffer,在FloatBuffer被创建后,我们调用put方法来将float数组放入缓冲区,最后,调用position方法来保证我们是由缓冲区的开头进行读取。

<code avrasm="" class="hljs">private void initializeBuffers(){ ByteBuffer buff = ByteBufferallocateDirect(verticeslength 4); bufforder(ByteOrdernativeOrder()); verticesBuffer = buffasFloatBuffer(); verticesBufferput(vertices); verticesBufferposition(0); buff = ByteBufferallocateDirect(textureVerticeslength 4); bufforder(ByteOrdernativeOrder()); textureBuffer = buffasFloatBuffer(); textureBufferput(textureVertices); textureBufferposition(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。

OpenGLES是一个让人崩溃的东西。在Andorid手机上做3D还就得用它。把我记的一些笔记分享在这里吧:

Android OpenGL ES简介 20011-6-3

Android系统使用OpenGL的标准接口来支持3D图形功能,android 3D图形系统也分为java框架和本地代码两部分。

本地代码主要实现的OpenGL接口的库,在Java框架层,javaxmicroeditionkhronosopengles是java标准的OpenGL包,

androidopengl包提供了OpenGL系统和Android GUI系统之间的联系。

Android的本地代码位于frameworks/base/opengl下,

JNI代码位于frameworks/base/core/com_google_android_gles_jni_GLImplcpp和frameworks/base/core/com_google_android_gles_jni_EGLImplcpp,

java类位于opengl/java/javax/microedition/khronos下

本地测试代码位于frameworks/base/opengl/tests。包括angeles、fillrate等14个测试代码,这些代码都可以通过终端进行本地调用测试(模拟器中使用adb shell)。

OpenGL ES 1x

固定管线 *** 作,支持glVertexPointer()等函数,不支持GLSL。头文件在ndk的GLES目录下,库文件是libGLESv1_CMso。

OpenGL ES 2x

可编程管线 *** 作,不兼容1x,不支持固定管线 *** 作,例如glVertexPointer()等函数。支持GLSL(还必须用这个来编程)。头文件在ndk的GLES2目录下,库文件是libGLESv2so。

OpenGL ES学习 2011-6-30

OpenGL定义了自己的数据类型。应该坚持使用这些OpenGL的数据类型,从而保证可移植性和效率。

OpenGL ES 目前不支持64位数据类型。

OpenGL ES 只支持三边形。

OpenGL ES 只支持gl开头的函数,glu库都不支持。

OpenGL ES 从 OpenGL中删除的功能:

1 glBegin/glEnd

2 glArrayElement

3 显示列表

4 求值器

5 索引色模式

6 自定义裁剪平面

7 glRect

8 图像处理(这个一般显卡也没有,FireGL/Quadro显卡有)

9 反馈缓冲

10 选择缓冲

11 累积缓冲

12 边界标志

13 glPolygonMode

14 GL_QUADS,GL_QUAD_STRIP,GL_POLYGON

15 glPushAttrib,glPopAttrib,glPushClientAttrib,glPopClientAttrib

16 TEXTURE_1D、TEXTURE_3D、TEXTURE_RECT、TEXTURE_CUBE_MAP

17 GL_COMBINE

18 自动纹理坐标生成

19 纹理边界

20 GL_CLAMP、GL_CLAMP_TO_BORDER

21 消失纹理代表

22 纹理LOD限定

23 纹理偏好限定

24 纹理自动压缩、解压缩

25 glDrawPixels,glPixelTransfer,glPixelZoom

26 glReadBuffer,glDrawBuffer,glCopyPixels

OpenGL ES 20 2011-10-9

20和11不兼容。

- 20使用的头文件是ndk的include目录下的GLES2目录,有gl2h,gl2exth,gl2platformh,而11使用的是GLES目录。

- 20使用的库文件是ndk的lib目录下的libGLESv2so,而11使用的是libGLESv1_CMso。

- 20中取消了很多11函数,例如glMatrixModel和glLoadIdentity等。

OpenGL着色语言(GLSL――OpenGL Shading Language)

- 使用20,必须学此语言。因为很多11的函数都被取消了。

san-angeles NDK OpenGL ES 11的例子程序 2012-3-8

San Angeles,查维基百科,是一个虚构的未来概念城市,位于南加州。常在**中出现,来源自Los Angeles和San Diego

该程序的演示效果是,观察一个宏伟的城市,地面是镜面有建筑倒影,城市中有飞船飞过。前后有5、6个观察点,而且镜头在每个观察点不停的移动。

这个例子,用NDK(C++)调用OpenGL ES 11来绘制了San Angeles这个城市。基本上全部使用了NDK,Java程序只有1个。

用vc2005演示一下,目的通过跟踪代码了解一些细节。方法是:

- 将jni下所有的h文件,以及democ,app-win32c复制出来,放在一个专门的目录下,然后改造成用OpenGL的而不是ES的。(或者干脆删除大段的绘制代码,保证编译通过)

首先分析Java代码

- DemoActivityjava,这是唯一的Java文件,它主要需要下列4个jni的接口:

- private static native void nativeInit(); // 初始化

- private static native void nativeResize(int w, int h);

- private static native void nativeRender(); // 绘制1帧

- private static native void nativeDone();

其次分析C++代码 app-androidc

- 首先,调用了importGLInit(),动态导入OpenGL的库。

- 其次,调用了 appInit(),在内存中建立了平台无关的3D对象集合。建立方法是用一个数组,用类似画圆拔高的方式产生诸多三角形。

- 然后,在每个时钟周期中调用appRender(),细节是:

- prepareFrame(width, height); // 准备OpenGL ES绘制框架。其实就是清空颜色和深度缓冲,重置投影和模型矩阵。

- camTrack(); // 算好在当前时钟周期,镜头的位置、朝向及焦距等。然后调用gluLookAt来实现。

- configureLightAndMaterial(); // 设置光源和材质

- drawModels(-1); // 先绘制倒影(其实就是将所有模型z轴倒过来画)

- 第一个循环,是画精致的物体

- 第二个循环,是画运动的物体

- drawGroundPlane(); // 再绘制镜子一般的地面。在绘制前取消光照,打开混合,然后绘制。绘制后还原状态。

- drawModels(1); // 再绘制所有模型

- drawFadeQuad(); // 最后绘制淡出框,用融合的方式画一个遮住整个视口的2D框,融合系数和时间相关。

以上就是关于如何向GLSL中传入多个纹理全部的内容,包括:如何向GLSL中传入多个纹理、Android opengl es 2.0怎么学习、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9671464.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-30
下一篇 2023-04-30

发表评论

登录后才能评论

评论列表(0条)

保存