Android OpenGL的简单使用(9):纹理

Posted by alonealice on 2020-12-29

纹理

纹理(texture) 在游戏制作里面指贴图,计算机图形学中的纹理既包括通常意义上物体表面的纹理即使物体表面呈现凹凸不平的沟纹,同时也包括在物体的光滑表面上的彩色图案。

添加纹理

添加纹理分为以下几个步骤

  1. 打开纹理开关
  2. 创建纹理
  3. 绑定纹理
  4. 设置纹理参数
  5. 生成纹理
  6. 设置纹理顶点数据

打开纹理

1
2
3
4
5
// 启动纹理坐标数据
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

//打开纹理
gl.glEnable(GL10.GL_TEXTURE_2D);

创建纹理

先要创建纹理名称数组

1
2
//纹理名称数组
int [] textureids = new int[1];

然后

1
2
 //创建纹理
gl.glGenTextures(1, textureids, 0);

传入3个参数

1
2
3
4
5
void glGenTextures(
int n, //数量
int[] textures, //纹理名称数组
int offset //偏移量
);

绑定纹理

前一个参数固定,后一个传入数组元素

1
2
//绑定纹理  
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureids[0]);

设置纹理参数

1.有两个参数需要设置下,当纹理比被渲染区域大或者小时,要设置纹理放大或者缩小情况下,OpenG纹理过滤模式

1
2
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,  GL10.GL_NEAREST);  
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);

有以下几种

1
2
3
4
5
6
7
8
9
10
11
- GL_NEAREST————最近邻过滤

- GL_NEAREST_MIPMAP_NEAREST————使用MIP贴图的最近邻过滤

- GL_NEAREST_MIPMAP_LINEAR————使用MIP贴图级别之间插值的最近邻过滤

- GL_LINEAR————双线性过滤

- GL_LINEAR_MIPMAP_NEAREST————使用MIP贴图的双线性过滤

- GL_LINEAR_MIPMAP_LINEAR————三线性过滤(使用MIP贴图级别之间插值的双线性过滤)
1
2
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);

2.在使用纹理的时候,有时候会出现超过纹理边界的问题,GL_TEXTURE_WRAP系列参数用来设置当这些超出边界时应该怎样处理。

1
2
- GL_TEXTURE_WRAP_S————S方向(X方向)
- GL_TEXTURE_WRAP_T————T方向(Y方向)

第三个参数有以下几种

1
2
3
4
5
6
7
- GL_REPEAT————重复边界的纹理

- GL_CLAMP————opengl就在一个2X2的加权纹理单元数组中使用取自边框的纹理单元。这时候的边框如果没有设置的话,应该就是原纹理的边界的像素值

- GL_CLAMP_TO_EDGE————边框始终被忽略。位于纹理边缘或者靠近纹理边缘的纹理单元将用于纹理计算,但不使用纹理边框上的纹理单元

- GL_CLAMP_TO_BORDER————如果纹理坐标位于范围[0,1]之外,那么只用边框纹理单元(如果没有边框,则使用常量边框颜色,我想常量边框颜色就是黑色)用于纹理

生成纹理

创建bitmap

1
bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bg2);

生成纹理

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

后三个参数含义如下

1
2
3
- level———— 提供多种分辨率的纹理. 如纹理只有一种分辨率,level 则设置为0.
- bitmap————Bitmap对象
- border————边框,设置为0

设置纹理顶点

1
2
3
4
5
6
7
8
9
10
float texCoords[] =  {

0.0f, 1.0f,

1.0f, 1.0f,

0.0f, 0.0f,

1.0f, 0.0f,
};

这里要注意纹理坐标和OpenGL ES中坐标不一样,它的原点位于左下角

完整demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
class GlRender implements GLSurfaceView.Renderer {

Bitmap bitmap;

public GlRender() {
buffer = Util.getFloatBuffer(texCoords);
vertBuffer = Util.getFloatBuffer(mArray);
indexbuffer = Util.getShortBuffer(indices);
bitmap = BitmapFactory.decodeResource(OpenGlTextureActivity.this.getResources(),
R.drawable.bg1);
}

//索引数组
private short[] indices = {
0, 1, 2,
0, 2, 3
};

//顶点数组
float texCoords[] = {

0.0f, 1.0f,

1.0f, 1.0f,

0.0f, 0.0f,

1.0f, 0.0f,
};


FloatBuffer buffer;

FloatBuffer vertBuffer;

ShortBuffer indexbuffer;

//顶点数组
private float[] mArray = {
-0.5f, -0.5f, 0f,
-0.5f, 0.5f, 0f,
0.5f, 0.5f, 0f,
1f, 0f, 0f,
1f, -1f, 0f
};

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0f, 0, 0f, 0f);
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
}

@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

// 启用顶点座标数据
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

// 启动纹理坐标数据
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

//打开纹理
gl.glEnable(GL10.GL_TEXTURE_2D);

//纹理名称数组
int[] textureids = new int[1];

//创建纹理
gl.glGenTextures(1, textureids, 0);

//绑定纹理
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureids[0]);

gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);

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);


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

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertBuffer);
// 设置纹理顶点数据
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, buffer);

//绘制
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexbuffer);

//禁止顶点数组
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

gl.glDisable(GL10.GL_TEXTURE_2D);

//关闭纹理坐标数据
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}

注意,surfaceView 不能 设置为EGLS20,否则无法显示。

1
surfaceView.setEGLContextClientVersion(2);