返回

OpenGLES 3.0 主线第二集:绘制面与图片贴图,为所欲为

Android

用 OpenGL ES 绘制和贴图 3D 面

引言

在 3D 图形的世界中, 是构建复杂物体和场景的基础元素。作为一名初学者,学习如何使用 OpenGL ES 绘制和贴图面将为你打开一扇通往视觉盛宴的大门。让我们一起踏上这趟旅程,掌握这门必不可少的技能。

绘制一个平面

想象一下一块正方形的纸,它由四个角和四条边组成。在 OpenGL ES 中,我们用三角形来构建面,而正方形恰好由两个三角形组成。

顶点数据 定义了三角形的角(也称为顶点),而顶点索引 则定义了连接这些顶点的顺序,从而形成了三角形。

// 顶点数据(单位正方形)
GLfloat vertices[] = {
    -0.5f, -0.5f, 0.0f, // 左下
     0.5f, -0.5f, 0.0f, // 右下
     0.5f,  0.5f, 0.0f, // 右上
    -0.5f,  0.5f, 0.0f  // 左上
};

// 顶点索引(组成两个三角形)
GLuint indices[] = {
    0, 1, 2,
    0, 2, 3
};

着色器 赋予物体颜色和纹理。顶点着色器 处理每个顶点,而片段着色器 处理每个像素。

顶点着色器:

#version 300 es
in vec3 vPosition; // 顶点位置
void main() {
    gl_Position = vec4(vPosition, 1.0); // 设置顶点位置
}

片段着色器:

#version 300 es
precision mediump float; // 精度设置
out vec4 fragColor; // 输出片段颜色

void main() {
    fragColor = vec4(1.0, 0.0, 0.0, 1.0); // 设置为红色
}

将数据加载到 GPU 是让 OpenGL ES 知道我们想要绘制什么。

1. 顶点缓冲区:

GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

2. 顶点索引缓冲区:

GLuint elementBuffer;
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

3. 启用顶点属性:

glEnableVertexAttribArray(0); // 启用顶点位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // 设置顶点位置属性

4. 连接着色器:

GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
glUseProgram(program);

添加图片贴图

贴图就像为我们的平面添加一张图片。我们需要一张纹理图像、纹理参数以及片段着色器的更新:

片段着色器:

#version 300 es
precision mediump float;
out vec4 fragColor;

uniform sampler2D uTexture; // 纹理采样器

void main() {
    vec2 uv = vec2(gl_TexCoord[0].x, 1.0 - gl_TexCoord[0].y); // 纹理坐标
    vec4 color = texture(uTexture, uv); // 采样纹理
    fragColor = color;
}

加载纹理:

GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

int width, height;
unsigned char* data = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
SOIL_free_image_data(data);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

启用纹理:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

设置纹理采样器:

GLint samplerLoc = glGetUniformLocation(program, "uTexture");
glUniform1i(samplerLoc, 0);

结论

恭喜!你现在已经掌握了 OpenGL ES 中绘制和贴图面的基础知识。这些技能为探索 3D 图形世界的无限可能打开了大门。

常见问题解答

  • Q:如何更改面的颜色?
    • A:修改片段着色器中的 fragColor 值。
  • Q:如何让面透明?
    • A:将 fragColor.a 设置为一个值介于 0(完全透明)和 1(完全不透明)之间。
  • Q:如何旋转面?
    • A:在顶点着色器中使用模型矩阵将顶点位置进行变换。
  • Q:如何绘制更复杂的形状?
    • A:通过使用多个面和三角形拼凑起来。
  • Q:如何提高性能?
    • A:使用索引缓冲区、顶点数组对象和纹理过滤等优化技术。