OpenGL 中的Texture(纹理)

来源:互联网 发布:微信开发框架 php 编辑:程序博客网 时间:2024/04/29 01:10

OpenGL 中的Texture(纹理)

翻译自 Android课程3:基础纹理 英语好的小伙伴可以直接去这个网站学习OpenGL ES2

纹理介绍

纹理映射技术是构建一个真实3D世界最重要的方式。没有纹理映射的话,所以的东西都是光滑的渐变,看起来像人造的,像是90年代的控制台游戏

首先大量使用了纹理技术的游戏,比如Doom和Duke Nukem 3D,通过添加的视觉影响能极大的增强了游戏的真实性。

纹理坐标系

在OpenGL中,纹理坐标系使用(s,t)来代替(x,y)坐标,代表纹理上的点,最终映射到几何形上。另外需要注意的是纹理坐标系和其他的OpenGL坐标系一样,t(y)轴指向上,因此位置越高值越大。

Texture坐标系

纹理映射

在这课中注意看2D纹理(GL_TEXTURE_2D)。OpenGL ES 也提供了其他的纹理模型让你做不同和专业的效果。

顶点着色器

从之前博客中的顶点着色器,增加一些修改:

attribute vec2 a_TexCoordinate;...varying vec2 v_TexCoordinate;...//将纹理坐标信息传递给片段着色器v_TexCoordinate = a_TexCoordinate;

在顶点着色器中我们添加了一个新的attribute类型2维向量来携带纹理的坐标信息作为输入数据。这会是基于每个顶点的,就像是位置,颜色,法线数据一样。我们还添加了一个新的varying型的变量来将数据传递进片段着色器中,通过三角形表面线性插入。

片段着色器

uniform sampler2D u_Texture;...varing vec2 v_TexCoordinate;..diffuse = diffuse * (1.0/(1.0+(0.1.*distance)));...diffuse = diffuse + 0.3;gl_FragColor = (c_Color*diffuse*texture2D(u_Texture,v_TexCoordinate));

我们添加了一个新的uniform类型 sampler2D代表了实际的纹理数据(),v_TexCoordinate从顶点着色器中获取到了纹理坐标数据,之后我们调用texture2D(texture,textureCoordinate)来读出纹理在当前坐标处的值。获取到了这个值后将它与其它项相乘就得到了最后的输出颜色。这种方式添加的纹理会有时在整个环境中较暗,所以可以将环境光上调一些来减少光的衰减。

从一个图像中加载纹理

 public static int loadTexture(Bitmap bitmap){        int[] textureHandle = new int[1];        //由OpenGL ES生成一个纹理句柄并存放到textureHandle中        GLES20.glGenTextures(1,textureHandle,0);        if(textureHandle[0]!=0){            //将纹理绑定到OpenGL上            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureHandle[0]);            // Set filtering            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);            // Recycle the bitmap, since its data has been loaded into OpenGL.            bitmap.recycle();        }        if (textureHandle[0] == 0)        {            throw new RuntimeException("Error loading texture.");        }        return textureHandle[0];    }

传入一个Bitmap对象并将其加载到OpenGL中

定义纹理坐标

我们知道纹理坐标系左下是(0,0),而右上是(1,1),而我们的之前定义一个矩形是

-1,1,

-1,-1,

1,1,

-1,-1,

1,-1,

1,1

这样的顺序定义的,
我们的纹理坐标应该是怎么样的呢:

0f,0f,

0f,1f,

1f,0f,

0f,1f,

1f,1f,

1f,0f.

这个坐标的对应顺序可以自己在纸上画一下来增强理解.
(我个人理解和这个文章的作者不一样,在Android上,纹理坐标系好像是和Android的2d坐标系相同,Android的2D坐标系是y轴向下为正,x轴向右为正,坐标原点为左上,以左上角为(0,0),所以将纹理映射到OpenGL坐标系中就是上面这样)

使用纹理

在GLES20.glUseProgram之后添加下面的代码:

//纹理坐标句柄mTextureHandle = GLES20.glGetAttribLocation(Program,"a_TexCoordinate");//纹理采样器句柄mTextureCoordHandle = GLES20.glGetUniformLocation(Program,"u_Texture");//将纹理坐标传递进着色器程序mTriangleTexture.position(0);GLES20.glVertexAttribPointer(mTextureHandle,2 ,GLES20.GL_FLOAT,false,0,mTriangleTexture);GLES20.glEnableVertexAttribArray(mTextureHandle);//激活第一个纹理单元GLES20.glActiveTexture(GLES20.GL_TEXTURE0);//绑定纹理到指定的纹理通道,GL_TEXTURE_2D在着色器中就会使用simpler2D。GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureDataHandle);//只使用一个纹理的话给Simpler2D传0就可以GLES20.glUniform1i(mTextureCoordHandle,0);
原创粉丝点击