返回
OpenGLES 3.0 主线第二集:绘制面与图片贴图,为所欲为
Android
2023-10-10 19:08:13
用 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
值。
- A:修改片段着色器中的
- Q:如何让面透明?
- A:将
fragColor.a
设置为一个值介于 0(完全透明)和 1(完全不透明)之间。
- A:将
- Q:如何旋转面?
- A:在顶点着色器中使用模型矩阵将顶点位置进行变换。
- Q:如何绘制更复杂的形状?
- A:通过使用多个面和三角形拼凑起来。
- Q:如何提高性能?
- A:使用索引缓冲区、顶点数组对象和纹理过滤等优化技术。