接着上一篇文章的内容,本文主要分析如何将纹理映射到多边形和物体上,会包含几种纹理映射的方式。
准备好了纹理下面我们分析如何进行映射,将纹理数据映射到具体的物体上去。纹理坐标如下图所示。
假设图中的正方向就是我们要将纹理映射上去的物体(地面),那么我们需要按照图中的表示,为每个顶点指定一个纹理坐标,也称之为UV坐标,它的横向为s轴,纵向围t轴,如下图所示。关于st和uv坐标可以参考一些3D图形学相关知识。
那么下面我们就按照图中的指示来为地面创建一个纹理坐标数组和缓冲区,代码如下:
byte[] tcs = {0,0, 1,0, 0,1, 1,1};
tcsBuf = ByteBuffer.allocateDirect(tcs.length);
tcsBuf.put(tcs).rewind();
准备好纹理的uv坐标之后,下面是最后一步,如何绘制该物体及纹理。代码如下:
public void draw()
{
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glVertexPointer(3, GL10.GL_BYTE, 0, vertsBuf); // use floor verts
gl.glTexCoordPointer(2, GL10.GL_BYTE, 0, tcsBuf); // use tex coords
gl.glEnable(GL10.GL_TEXTURE_2D);
setTexture();
gl.glNormal3f( 0, 1.0f, 0); // facing up
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisable(GL10.GL_TEXTURE_2D); // switch off texturing
} // end of draw()
private void setTexture()
{
gl.glBindTexture(GL10.GL_TEXTURE_2D, texNames[0]); // use the tex name
// specify the texture for the currently bound tex name
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGB, imWidth, imHeight, 0,
GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, texBuf);
// set the minification/magnification techniques
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
} // end of setTexture()
其中大部分代码我们已经接触过,标注为红色的是需要我们解释的,glEnableClientState函数就是允许我们设置纹理坐标数组,而函数glTexCoordPointer就是将前面准备的纹理坐标缓冲区告诉Opengl,这样在绘制图形时,Opengl会自动的对纹理进行处理,并展现出来。
运行结果如下图所示。
图中的地面就是我们绘制的一个四边形,然后给映射了一个地面的纹理贴图上去形成的。这里我们是直接将一整张图给映射上去了,那么我们是否可以只映射图像的一部分呢?答案是肯定的,我们只需要改动UV坐标即可。UV坐标对应如下图所示。
这样应该很好理解,相当于我们只是映射了图像上的0.25到0.75之间的部分(整个图像的宽度和高度为1),即图像的中间部分。当然你同样可以更改这个坐标,来调整自己需要映射的部分,这在实际的游戏开发过程中是经常使用的,尤其是一些2D游戏的开发,会将很多小的图片放置到一个大的图片之上,做成一个图片集,就可以通过这种方式来确定需要映射图片集中的哪一个小的图块。按照上图的指示,我们将代码需要改成float类型的数据即可,如下所示。
float[] tcs = {0.25f,0.25f,0.75f,0.25f,0.25f,0.75f,0.75f,0.75f};
tcsBuf = ByteBuffer.allocateDirect(tcs.length*4).asFloatBuffer();
tcsBuf.put(tcs).rewind();
/////
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, tcsBuf);
运行效果如下图所示。
和第一个效果图相比很明显的纹理只去了图像的中间一部分,上面的两种方式都是将纹理映射到一个四边形上,但是在Opengl ES中最基本的应该是三角形,我们是否可以将纹理映射到三角形上呢,同样可以,对于三角形的纹理示意图如下所示。
就这样,同样的步骤适合于几何体中任何三角形,而且你甚至可以通过非常规方式的映射来扭曲纹理,产生各种特殊的效果。总而言之,纹理上的任何一点都可以映射到多边形的任何一点。或者换而言之,你可以对任何地点(u,v)使用任何(s,t)而OpenGL ES则为你进行映射。