Android GLES32:创建108×192彩色正方形网格顶点缓冲区求助
我来给你一个完整的可参考示例,涵盖从着色器编写到最终绘制彩色网格的全流程,完全基于GLES32实现,满足你的108×192网格、位置+颜色顶点、VSync无混合的需求:
完整GLES32彩色网格实现示例
1. 编写GLSL着色器
首先需要顶点着色器处理顶点的位置和颜色数据,片段着色器负责输出最终颜色:
顶点着色器
#version 320 es layout(location = 0) in vec2 aPosition; layout(location = 1) in vec3 aColor; out vec3 vColor; void main() { gl_Position = vec4(aPosition, 0.0, 1.0); vColor = aColor; }
片段着色器
#version 320 es precision mediump float; in vec3 vColor; out vec4 fragColor; void main() { fragColor = vec4(vColor, 1.0); }
2. 生成顶点数据(位置+颜色)
我们的网格是108行×192列的正方形,每个正方形由2个三角形(6个顶点)组成,每个顶点包含2个位置分量(x,y)和3个颜色分量(r,g,b)。这里让颜色根据行列渐变,方便直观区分网格:
// 网格尺寸 private static final int GRID_ROWS = 108; private static final int GRID_COLS = 192; // 每个顶点的分量数:2(位置)+3(颜色)=5 private static final int VERTEX_COMPONENTS = 5; // 每个正方形需要6个顶点(2个三角形) private static final int VERTICES_PER_SQUARE = 6; private float[] generateGridVertices() { float[] vertices = new float[GRID_ROWS * GRID_COLS * VERTICES_PER_SQUARE * VERTEX_COMPONENTS]; // 归一化设备坐标范围:x从-1到1,y从-1到1 float cellWidth = 2.0f / GRID_COLS; float cellHeight = 2.0f / GRID_ROWS; int index = 0; for (int row = 0; row < GRID_ROWS; row++) { for (int col = 0; col < GRID_COLS; col++) { // 计算当前单元格的四个顶点位置(归一化坐标) float x1 = -1.0f + col * cellWidth; float y1 = 1.0f - row * cellHeight; float x2 = x1 + cellWidth; float y2 = y1 - cellHeight; // 生成当前单元格的渐变颜色 float r = (float) col / GRID_COLS; float g = (float) row / GRID_ROWS; float b = 0.5f + 0.5f * (float) Math.sin((row + col) * 0.1f); // 第一个三角形:(x1,y1) -> (x2,y1) -> (x1,y2) vertices[index++] = x1; vertices[index++] = y1; vertices[index++] = r; vertices[index++] = g; vertices[index++] = b; vertices[index++] = x2; vertices[index++] = y1; vertices[index++] = r; vertices[index++] = g; vertices[index++] = b; vertices[index++] = x1; vertices[index++] = y2; vertices[index++] = r; vertices[index++] = g; vertices[index++] = b; // 第二个三角形:(x2,y1) -> (x2,y2) -> (x1,y2) vertices[index++] = x2; vertices[index++] = y1; vertices[index++] = r; vertices[index++] = g; vertices[index++] = b; vertices[index++] = x2; vertices[index++] = y2; vertices[index++] = r; vertices[index++] = g; vertices[index++] = b; vertices[index++] = x1; vertices[index++] = y2; vertices[index++] = r; vertices[index++] = g; vertices[index++] = b; } } return vertices; }
3. 创建顶点缓冲区与顶点数组对象(VAO)
GLES32强制要求使用VAO管理顶点属性配置,避免重复设置:
private int vaoId; private int vboId; private int programId; private void setupBuffers() { // 1. 编译链接着色器程序(这里假设你有工具类ShaderUtils处理编译逻辑) programId = ShaderUtils.createProgram(vertexShaderSource, fragmentShaderSource); // 2. 创建VAO和VBO int[] vao = new int[1]; GLES32.glGenVertexArrays(1, vao, 0); vaoId = vao[0]; int[] vbo = new int[1]; GLES32.glGenBuffers(1, vbo, 0); vboId = vbo[0]; // 3. 绑定VAO,后续配置会存入VAO GLES32.glBindVertexArray(vaoId); // 4. 绑定VBO并上传顶点数据 GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, vboId); float[] vertices = generateGridVertices(); ByteBuffer buffer = ByteBuffer.allocateDirect(vertices.length * 4) .order(ByteOrder.nativeOrder()); buffer.asFloatBuffer().put(vertices); buffer.position(0); GLES32.glBufferData(GLES32.GL_ARRAY_BUFFER, buffer.capacity(), buffer, GLES32.GL_STATIC_DRAW); // 5. 设置位置属性指针(location=0) int stride = VERTEX_COMPONENTS * 4; // 每个顶点的字节数:5*4=20 GLES32.glVertexAttribPointer(0, 2, GLES32.GL_FLOAT, false, stride, 0); GLES32.glEnableVertexAttribArray(0); // 6. 设置颜色属性指针(location=1) int colorOffset = 2 * 4; // 位置占2个float,偏移8字节 GLES32.glVertexAttribPointer(1, 3, GLES32.GL_FLOAT, false, stride, colorOffset); GLES32.glEnableVertexAttribArray(1); // 7. 解绑VAO和VBO(规范操作) GLES32.glBindVertexArray(0); GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, 0); }
4. 绘制流程(含VSync与无混合设置)
开启VSync
在EGL配置阶段设置垂直同步,确保帧率与显示器刷新率一致:
// 假设已获取EGLDisplay、EGLConfig和窗口Surface EGLSurface surface = eglCreateSurface(display, config, windowSurface, null); EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, attribList); eglMakeCurrent(display, surface, surface, context); // 开启VSync:交换间隔设为1(每帧等待垂直同步信号) eglSwapInterval(display, 1);
绘制逻辑
public void onDrawFrame() { // 清除颜色缓冲区 GLES32.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); GLES32.glClear(GLES32.GL_COLOR_BUFFER_BIT); // 显式关闭混合(满足无混合需求) GLES32.glDisable(GLES32.GL_BLEND); // 使用着色器程序 GLES32.glUseProgram(programId); // 绑定VAO GLES32.glBindVertexArray(vaoId); // 绘制所有顶点:总顶点数=108*192*6 int totalVertices = GRID_ROWS * GRID_COLS * VERTICES_PER_SQUARE; GLES32.glDrawArrays(GLES32.GL_TRIANGLES, 0, totalVertices); // 解绑VAO GLES32.glBindVertexArray(0); // 交换缓冲区(VSync在此生效) eglSwapBuffers(display, surface); }
关键注意事项
- 顶点数据格式必须与着色器声明严格匹配,否则会出现渲染错乱;
- GLES32必须使用VAO,不能像旧版本那样直接设置顶点属性;
- 归一化坐标(-1到1)无需手动适配屏幕分辨率,GLES会自动映射到屏幕;
- 显式关闭混合确保不会因其他代码开启混合影响效果。
内容的提问来源于stack exchange,提问作者Alex2452
相关产品推荐
相关产品推荐

