`
melord
  • 浏览: 145461 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

OpenGL ES教程VI之纹理贴图(原文对照)

阅读更多

OpenGL ES Tutorial for Android – Part VI – Textures

December 30th, 2010 by Per-Erik BergmanAndroid, Embedded, Java

Last tutorial we worked a bit more on meshes and we have also talked about adding colors to our mesh. The most common way of adding colors to your mesh is to add a texture. There is a couple of different steps involved with adding a texture to the mesh I will try to go through them all and explain the basics about them.

上一教程我们生成了一些模型,而且我们已经知道如何给模型着色。但最常用的着色方式还是添加纹理。给模型添加纹理有几个不同的操作步骤。下面我将一一展开。

Loading bitmaps

First step would be to get a bitmap to generate a texture from. You can get hold of a bitmap in many different ways from downloading, generating or simply just load one from the resources. I'm going with the simplest one for this example witch is loading from the resources.

第一步,我们需要得到贴图的图片,这有许多方式。你可以下载,生成,或是简单地从资源中加载,我使用了最后一种:从一个资源文件中加载。

Bitmap bitmap = BitmapFactory.decodeResource(contect.getResources(),

                                             R.drawable.icon);

One other thing about textures is that some hardware requires that the height and width are in the power of 2 (1, 2, 4, 8, 16, 32, 64...). If you run a texture with a size of 30x30pixels on a hardware that don’t support it you will just get a white square (unless you change the default color).

需要注意的是,在某些硬件上,贴图需要的图片尺寸必须是2n次方(1,2,4,8,16,32…)。如果你的图片是30X30的话,而且硬件不支持的话,那么你只能看到一个白色的方框(除非,你更改了默认颜色)

Generating a texture

After we have loaded the bitmap we need to tell OpenGL to actually create the texture.

图片加载之后,就可以告诉OpenGL 来产生纹理了。

First thing we need to do is to let OpenGL generate some texture id's that we will use as handles to the textures later on. In this example we will only have one texture.

首先要做的是让OpenGL产生纹理ID,这些ID将在后面用到。例子中我们只有一个纹理。

// Create an int array with the number of textures we want,

// in this case 1.

int[] textures = new int[1];

// Tell OpenGL to generate textures.

gl.glGenTextures(1, textures, 0);

With the same parameters you can delete the textures:

// Delete a texture.

gl.glDeleteTextures(1, textures, 0)

Now when the texture id's are generated we need to just like everything else tell OpenGL what to work with. With textures we use the command glBindTexture:

ID产生之后,我们需要将这些ID使用glBindTexture方式进行绑定

gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

From this point all commands we call on regarding textures will be applied on to your texture with the generated id.

那么在此之后,我们后面将使用产生的ID来调用纹理

glTexParameter

There is a couple of parameters we need to set on the texture, the first one is to tell OpenGL what to do if the texture need to be shrunk or magnified to match the rendered image.

在纹理映射,我们需要设置几个参数,第一个是告诉OpenGL在渲染图片时,怎么缩小或放大以适合大小。
If the texture is smaller it needs to be magnified that is done with the magnification function:

如果贴图小的话,那我们需要使用放大函数进行放大操作。

// Scale up if the texture if smaller.

gl.glTexParameterf(GL10.GL_TEXTURE_2D,

                   GL10.GL_TEXTURE_MAG_FILTER,

                   GL10.GL_LINEAR);

And how to scale if the texture needs to be scaled down using the minification function.

类似,在贴图过多时,使用压缩函数进行缩小。

// scale linearly when image smalled than texture

gl.glTexParameterf(GL10.GL_TEXTURE_2D,

                   GL10.GL_TEXTURE_MIN_FILTER,

                   GL10.GL_LINEAR);

You need to pass an argument to these functions. I'm only going to show you two of them the rest you can investigate your self

请看上面的函数,你可以自己研究一下,该给它传递什么参数。

If you want a crisp and clean rendering like this image you need to use the GL10.GL_NEAREST parameter.

如果你想要清晰的渲染效果,你可以使用GL10.GL_NEAREST

 

If you rather want a blurred image you should use the GL10.GL_LINEAR parameter.

如果你喜欢模糊一点,应该使用GL10.GL_LINEAR

UV Mapping

We will also need to tell OpenGL how to map this image onto the mesh this is done in two steps, fist we need to assign UV coordinates

下面我们需要告诉OpenGL怎样将图片映射到模型上,有两个步骤。首先我们指定一个UV坐标

UV mapping is the way we map the pixels on the bitmap to the vertices in our mesh. The UV coordinates are 0,0 in the upper left and 1,1 is the bottom right, like the left image below. The right image below illustrates how our plane is built. To get the texture mapped correctly we need to map the lower left part of the texture (0,1) to the lower left vertex (0) in our plane and we need to map the the bottom right (1,1) in the texture to the bottom right (1) to the bottom right in our plane and... you get the idea.

我们使用UV映射将图片的每一像素映射到模型的顶点上。UV坐标中,左上角为0,0,右下角为1,1,请看下图的左半部分。右半部分是我们要创建的平面。为保证映射正确,我们将纹理左下角映射到左下角顶点0,右下角映射到顶点1…依此类推。

注:在OpenGL教程里讲道,图片左下角为00坐标。不过我们这里是AndroidOpenGL ES。或许Android在接口封装上,有些许改动吧。

 

We put this mapping into a float array like this:

纹理坐标数组的定义如下:

float textureCoordinates[] = {0.0f, 1.0f,

                              1.0f, 1.0f,

                              0.0f, 0.0f,

                              1.0f, 0.0f };

 

If we instead used 0.5 instead of 1.0 like this:

float textureCoordinates[] = {0.0f, 0.5f,

                              0.5f, 0.5f,

                              0.0f, 0.0f,

                              0.5f, 0.0f };

 


The texture will be mapped so the plane will have the upper left part of it.

那么将映射图片的左上角到平面中

Back to the glTexParameterf, if we go the other way and uses values higher then 1.0 like this:

请回想一下glTexParameterf函数。如果我们将1.0放大到2.0

float textureCoordinates[] = {0.0f, 2.0f,

                              2.0f, 2.0f,

                              0.0f, 0.0f,

                              2.0f, 0.0f };

We actually tell OpenGL to use part of the texture that does not exist so we need to tell OpenGL what to do with the part that does not exist.

那么超过图片的位置,OpenGL该如何处理呢?这正是下面我们讨论的。

We use the glTexParameterf function to tell OpenGL what to do with the texture. By default OpenGL uses something called GL_REPEAT.

我们使用glTexParameterf函数来告诉OpenGL该如何进行贴图,默认使用的参数项为GL_REPEAT

GL_REPEAT means that OpenGL should repeat the texture beyond 1.0.

GL_REPEAT意味着OpenGL应该重复纹理超过1.0的部分
GL_CLAMP_TO_EDGE means that OpenGL only will draw the image once and after that just repeat the last pixel line the rest of the image.

GL_CLAMP_TO_EDGE表示OpenGL只画图片一次,剩下的部分将使用图片最后一行像素重复

Since we are working with a 2D texture so we need to tell OpenGL what to do in two directions: GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T.

对于一个2D纹理,我们还需要告诉它们的方向。

Below you see a chart with the 4 combinations of GL_REPEAT and GL_CLAMP_TO_EDGE.

下面请看它们的四种组合(第三种组合对应的图片错了。)

WRAP_S: GL_REPEAT
WRAP_T: GL_REPEAT
WRAP_S: GL_REPEAT
WRAP_T: GL_CLAMP_TO_EDGE
WRAP_S: GL_REPEAT
WRAP_T: GL_CLAMP_TO_EDGE
WRAP_S: GL_CLAMP_TO_EDGE
WRAP_T: GL_CLAMP_TO_EDGE

This is how we use the glTexParameterf function:

gl.glTexParameterf(GL10.GL_TEXTURE_2D,

                   GL10.GL_TEXTURE_WRAP_S,

                   GL10.GL_REPEAT);

gl.glTexParameterf(GL10.GL_TEXTURE_2D,

                   GL10.GL_TEXTURE_WRAP_T,

                   GL10.GL_REPEAT);

The last thing we need to do is to bind the bitmap we loaded to the texture id we created.

GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

Using the texture

To be able to use the texture we need just like with everything else create a byte buffer with the UV coordinates:

对于UV坐标,我们同样使用字节缓冲

FloatBuffer byteBuf = ByteBuffer.allocateDirect(texture.length * 4);

byteBuf.order(ByteOrder.nativeOrder());

textureBuffer = byteBuf.asFloatBuffer();

textureBuffer.put(textureCoordinates);

textureBuffer.position(0);

Rendering

// Telling OpenGL to enable textures.

gl.glEnable(GL10.GL_TEXTURE_2D);

// Tell OpenGL where our texture is located.

gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

// Tell OpenGL to enable the use of UV coordinates.

gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

// Telling OpenGL where our UV coordinates are.

gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

 

// ... here goes the rendering of the mesh ...

 

// Disable the use of UV coordinates.

gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

// Disable the use of textures.

gl.glDisable(GL10.GL_TEXTURE_2D);

Putting it all together

I'm using a modified version of the code from the previous tutorial. The different is mostly that I renamed some variables and functions and added more comments and all code is now under Apache License. To make the code easier to understand I removed the previous plane and added a new easier one called SimplePlane.

Updating the Mesh class

The first thing we need to do is to update the Mesh class (se.jayway.opengl.tutorial.mesh.Mesh). We need to add the functionality to load and render a texture.

We need to be able to set and store the UV coordinates.

// Our UV texture buffer.

private FloatBuffer mTextureBuffer;

 

/**

 * Set the texture coordinates.

 *

 * @param textureCoords

 */

protected void setTextureCoordinates(float[] textureCoords) {

        // float is 4 bytes, therefore we multiply the number if

        // vertices with 4.

        ByteBuffer byteBuf = ByteBuffer.allocateDirect(

                                           textureCoords.length * 4);

        byteBuf.order(ByteOrder.nativeOrder());

        mTextureBuffer = byteBuf.asFloatBuffer();

        mTextureBuffer.put(textureCoords);

        mTextureBuffer.position(0);

}

 

We also need to add functions to set the bitmap and create the texture.

// Our texture id.

private int mTextureId = -1;

 

// The bitmap we want to load as a texture.

private Bitmap mBitmap;

 

/**

 * Set the bitmap to load into a texture.

 *

 * @param bitmap

 */

public void loadBitmap(Bitmap bitmap) {

        this.mBitmap = bitmap;

        mShouldLoadTexture = true;

}

 

/**

 * Loads the texture.

 *

 * @param gl

 */

private void loadGLTexture(GL10 gl) {

        // Generate one texture pointer...

        int[] textures = new int[1];

        gl.glGenTextures(1, textures, 0);

        mTextureId = textures[0];

 

        // ...and bind it to our array

        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);

 

        // Create Nearest Filtered Texture

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,

                       GL10.GL_LINEAR);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,

                       GL10.GL_LINEAR);

 

        // Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,

                       GL10.GL_CLAMP_TO_EDGE);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,

                       GL10.GL_REPEAT);

 

        // Use the Android GLUtils to specify a two-dimensional texture image

        // from our bitmap

        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);

}

 

And finally we need to add the call to the texture loading and to actually tell OpenGL to render with this texture. I removed some code so the page would not be so long but you will find the code complete in the attached zip file.

// Indicates if we need to load the texture.

private boolean mShouldLoadTexture = false;

 

/**

 * Render the mesh.

 *

 * @param gl

 *            the OpenGL context to render to.

 */

public void draw(GL10 gl) {

        ...

 

        // Smooth color

        if (mColorBuffer != null) {

               // Enable the color array buffer to be used during rendering.

               gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

               gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);

        }

 

        if (mShouldLoadTexture) {

               loadGLTexture(gl);

               mShouldLoadTexture = false;

        }

        if (mTextureId != -1 && mTextureBuffer != null) {

               gl.glEnable(GL10.GL_TEXTURE_2D);

               // Enable the texture state

               gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

 

               // Point to our buffers

               gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);

               gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);

        }

 

        gl.glTranslatef(x, y, z);

 

        ...

 

        // Point out the where the color buffer is.

        gl.glDrawElements(GL10.GL_TRIANGLES, mNumOfIndices,

                       GL10.GL_UNSIGNED_SHORT, mIndicesBuffer);

 

        ...

 

        if (mTextureId != -1 && mTextureBuffer != null) {

               gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        }

 

        ...

 

}

Creating the SimplePlane class

We also need to create the SimplePlane.java. The code is pretty simple and self-explaining if you have read my previous tutorials. The new element is the textureCoordinates variable.

 

package se.jayway.opengl.tutorial.mesh;

 

/**

 * SimplePlane is a setup class for Mesh that creates a plane mesh.

 *

 * @author Per-Erik Bergman (per-erik.bergman@jayway.com)

 *

 */

public class SimplePlane extends Mesh {

        /**

         * Create a plane with a default with and height of 1 unit.

         */

        public SimplePlane() {

               this(1, 1);

        }

 

        /**

         * Create a plane.

         *

         * @param width

         *            the width of the plane.

         * @param height

         *            the height of the plane.

         */

        public SimplePlane(float width, float height) {

               // Mapping coordinates for the vertices

               float textureCoordinates[] = { 0.0f, 2.0f, //

                               2.0f, 2.0f, //

                               0.0f, 0.0f, //

                               2.0f, 0.0f, //

               };

 

               short[] indices = new short[] { 0, 1, 2, 1, 3, 2 };

 

                float[] vertices = new float[] { -0.5f, -0.5f, 0.0f,

                                                  0.5f, -0.5f, 0.0f,

                                                 -0.5f,  0.5f, 0.0f,

                                                  0.5f, 0.5f, 0.0f };

 

               setIndices(indices);

               setVertices(vertices);

               setTextureCoordinates(textureCoordinates);

        }

}

 

References

The info used in this tutorial is collected from:
Android Developers
OpenGL ES 1.1 Reference Pages

You can download the source for this tutorial here: Tutorial_Part_VI
You can also checkout the code from:
code.google.com

Previous tutorial: OpenGL ES Tutorial for Android – Part V – More on Meshes

Per-Erik Bergman
Consultant at
Jayway

 

 

分享到:
评论

相关推荐

    OpenglES 1.0 纹理贴图

    纹理贴图是OpenGL ES中的一个重要概念,它允许我们为几何体表面添加复杂的视觉效果,如图像或颜色图案。在本篇中,我们将深入探讨OpenGL ES 1.0中的纹理贴图技术。 首先,理解纹理的基本概念至关重要。纹理可以看作...

    Android应用源码OpenGL 3D立方体多纹理贴图-IT计算机-毕业设计.zip

    在这个名为“Android应用源码OpenGL 3D立方体多纹理贴图”的项目中,开发者将展示如何在Android应用中利用OpenGL ES实现3D立方体,并进行多纹理贴图。 首先,理解OpenGL ES的基本概念至关重要。OpenGL ES提供了一组...

    【OpenGL ES】纹理贴图

    本教程将深入探讨如何在OpenGL ES环境中实现纹理贴图,特别是在Android平台上。 一、纹理贴图基础 纹理贴图是3D图形学中的一个重要概念,它允许我们在3D模型表面添加丰富的视觉细节。纹理就像真实物体表面的图案或...

    opengl实现对地球纹理贴图

    opengl实现纹理贴图,以地球为例子,但是实现得有点粗糙,地球上出现了一条裂缝

    OPENGL_TEXTURE.zip_OPENGL 纹理_Opengl纹理_opengl 贴图_opengl贴图_贴图

    本篇文章将深入探讨OpenGL中的纹理以及如何在OpenGL中实现纹理贴图,特别关注BMP格式的图像。 首先,我们需要了解OpenGL纹理的基本概念。纹理是由像素数据组成的二维数组,这些数据可以是颜色、透明度或其他图像...

    安卓app开发项目-OpenGL 3D立方体多纹理贴图(源码).zip

    安卓app开发项目-OpenGL 3D立方体多纹理贴图(源码).zip安卓app开发项目-OpenGL 3D立方体多纹理贴图(源码).zip安卓app开发项目-OpenGL 3D立方体多纹理贴图(源码).zip安卓app开发项目-OpenGL 3D立方体多纹理贴图(源码)...

    OpenGL 3D立方体多纹理贴图.rar

    OpenGL 3D立方体多纹理贴图.rar

    OpenGL.rar_OPENGL 纹理_opengl_opengl 纹理贴图_opengl纹理贴图_镂空效果

    本资源包主要关注的是OpenGL中的纹理贴图技术及其如何实现镂空效果,这在游戏开发、可视化应用和图形设计等领域至关重要。 纹理贴图是OpenGL中用于增强图形表面真实感的关键技术。它允许我们将二维图像(纹理)应用...

    Android平台 使用OpenGLES3.0实现纹理纹理、颜色混合

    在Android平台,使用OpenGLES3.0实现纹理纹理、颜色混合代码实现举例。 具体案例文章讲解请见: https://xiaxl.blog.csdn.net/article/details/121634894

    5、OpenGL ES - 渲染图片纹理(一).ppt

    OpenGL ES - 渲染图片纹理,学习openg es 2.0技术,opengl es 基础知识

    opengl纹理贴图源码

    本教程将深入探讨如何使用VA(Vertex Array)模式实现纹理贴图。 纹理贴图是指将2D图像(纹理)映射到3D模型表面,通过这种方式增加模型的视觉信息。在OpenGL中,纹理可以是任何形式的二维数据,如JPEG、PNG等格式...

    Android平台OpenGLES生成使用Mipmap纹理

    该案例代码为Android 平台OpenGL ES实现举例,有两个作用: ...2、使用 OpenGLES 生成与使用Mipmap纹理,构建远处模糊,近处清晰的效果。 具体案例文章讲解请见: https://xiaxl.blog.csdn.net/article/details/8873106

    OpenGL加载Obj模型和纹理贴图

    基于Qt+OpenGL 实现的3D模型obj文件加载以及纹理贴图,未使用第三方库,根据obj文件的格式,逐行解析并读取,加载到顶点缓冲区中,适合学习OBJ模型加载的同学参考。

    Android OpenGL 3D 立方体多纹理贴图源码

    这个"Android OpenGL 3D 立方体多纹理贴图源码"是一个很好的学习资源,它涵盖了多个关键的OpenGL ES编程概念。 首先,3D立方体的渲染是OpenGL ES的基本应用之一,它展示了如何构建基本的几何形状。在3D空间中,一个...

    基于OpenGL的三维物体纹理贴图研究

    ### 基于OpenGL的三维物体纹理贴图研究 #### 1. 引言 在三维图形绘制领域,为了能够真实地再现复杂场景,仅依靠基本的几何形状往往是不够的。现实世界的物体表面通常具有丰富的纹理特征,这些纹理特征极大地增加了...

    OpenGL纹理贴图简单例子.zip_OPENGL 纹理_opengl纹理贴图_opengl贴图_纹理贴图_贴图

    纹理贴图是OpenGL中的核心概念之一,它涉及到几个关键步骤和概念: 1. **纹理对象**:在OpenGL中,纹理是独立的数据对象,它们存储了图像数据。你可以创建一个纹理对象,然后将其绑定到一个特定的纹理目标(如GL_...

    Android代码-OpenGL3D立方体多纹理贴图源码.zip

    这个源码示例将帮助开发者理解如何在Android环境中使用OpenGL ES进行3D图形渲染,特别是如何实现多纹理贴图,为更复杂的游戏或应用开发打下基础。通过学习和分析这个项目,可以提升对3D图形编程的理解和实践能力。

    android opengl es 圆锥纹理贴图

    圆锥纹理贴图是OpenGL ES中的一种技术,用于在三维模型上应用纹理,使得图像更具真实感。这个教程或代码示例可能是为了帮助开发者理解如何在Android平台上使用OpenGL ES为圆锥形几何体添加纹理。 在OpenGL ES中,...

    android opengl-ES 魔方 纹理贴图

    在这个项目中,"android opengl-ES 魔方 纹理贴图"的主题涉及到在Android设备上使用OpenGL-ES来创建一个旋转的三维魔方,并且为每个面应用纹理贴图,同时实现手势识别功能来操控魔方的转动。 首先,我们来看一下...

    OpenGLES demo - 12. 材质贴图 Texture Mapping

    在iOS应用中,我们可以结合SceneKit、Metal或其他图形框架来使用OpenGLES进行材质贴图,但本教程更专注于直接使用OpenGLES API的原始实现。通过熟练掌握这些步骤,你可以为3D模型创建出逼真的纹理效果,从而提升游戏...

Global site tag (gtag.js) - Google Analytics