【OpenGL ES】绘制三角形
1 前言
1.1 设置顶点属性
顶点有位置、颜色等属性,可以通过 glVertexAttribPointer 设置顶点的属性。
void glVertexAttribPointer(
int index, //顶点属性的索引值,如:位置属性索引为0,颜色属性索引为1
int size, //每个顶点在待设置属性下的数组大小,如:位置用三维坐标表示,则size为3;颜色用argb表示,则size为4
int type, //顶点属性的数据类型,如:GLES30.GL_FLOAT
boolean normalized, //当被访问时,固定点数据值是否应该被归一化
int stride, //连续顶点属性之间的偏移量,0表示紧密排列在一起的
Buffer pointer //顶点属性序列
)
1.2 绘制图元
OpenGL ES 绘制图形主要有 glDrawArrays 和 glDrawElements 2个接口。
1)glDrawArrays
void glDrawArrays(
int mode, //渲染的图元类型
int first, //渲染的起始索引
int count //渲染的顶点数
)
图元类型(mode)主要有:
- GL_POINTS:绘制顶点
- GL_LINES:绘制线段,如顶点序列:1234,绘制线段:12、34
- GL_LINE_STRIP:绘制线带,如顶点序列:1234,绘制线带:12、23、34
- GL_LINE_LOOP:绘制线圈,如顶点序列:1234,绘制线带:12、23、34、41
- GL_TRIANGLES:绘制三角形:如顶点序列:123456,绘制三角形:123、456
- GL_TRIANGLE_STRIP:绘制三角形带:如顶点序列:12345,绘制三角形:123、234、345
- GL_TRIANGLE_FAN:绘制三角形扇:如顶点序列:12345,绘制三角形:123、134、145
2)glDrawElements
void glDrawElements(
int mode, //渲染的图元类型
int count, //渲染的顶点数
int type, //渲染的顶点序列的数据类型
Buffer indices //渲染的顶点序列
)
mode 同 glDrawArrays;indices 必须是 Buffer 类型,如:ByteBuffer;type 为 indices 对应的 OpenGL 的数据类型,如:GLES30.GL_UNSIGNED_BYTE。
本文将以绘制三角形的案例介绍图元的绘制,项目目录如下:
2 案例
MainActivity.java
package com.zhyan8.triangle;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGlSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGlSurfaceView = new MyGLSurfaceView(this);
setContentView(mGlSurfaceView);
mGlSurfaceView.setRenderer(new MyRender(this));
}
@Override
protected void onResume() {
super.onResume();
mGlSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mGlSurfaceView.onPause();
}
}
MyGLSurfaceView.java
package com.zhyan8.triangle;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
public class MyGLSurfaceView extends GLSurfaceView {
public MyGLSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(3);
}
public MyGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setEGLContextClientVersion(3);
}
}
MyRender.java
package com.zhyan8.triangle;
import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRender implements GLSurfaceView.Renderer {
private FloatBuffer vertexBuffer;
private GLUtils mGLUtils;
public MyRender(Context context) {
mGLUtils = new GLUtils(context);
getFloatBuffer();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
//设置背景颜色
GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f);
//编译着色器
final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader);
final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader);
//链接程序片段
int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId);
GLES30.glUseProgram(programId);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//设置视图窗口
GLES30.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
//将颜色缓冲区设置为预设的颜色
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glLineWidth(5);
//启用顶点的数组句柄
GLES30.glEnableVertexAttribArray(0);
//准备坐标数据
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
// GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3); //绘制三角形的三个顶点
// GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 3); //绘制三角形的三条边
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3); //绘制三角形的内部
//禁止顶点数组句柄
GLES30.glDisableVertexAttribArray(0);
}
private void getFloatBuffer() {
float[] vertex = new float[] {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
vertexBuffer = mGLUtils.getFloatBuffer(vertex);
}
}
GLUtils.java
package com.zhyan8.triangle;
import android.content.Context;
import android.opengl.GLES30;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class GLUtils {
private Context mContext;
public GLUtils(Context context) {
mContext = context;
}
public FloatBuffer getFloatBuffer(float[] floatArr) {
FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
fb.put(floatArr);
fb.position(0);
return fb;
}
//通过代码片段编译着色器
public int compileShader(int type, String shaderCode){
int shader = GLES30.glCreateShader(type);
GLES30.glShaderSource(shader, shaderCode);
GLES30.glCompileShader(shader);
return shader;
}
//通过外部资源编译着色器
public int compileShader(int type, int shaderId){
String shaderCode = readShaderFromResource(shaderId);
return compileShader(type, shaderCode);
}
//链接到着色器
public int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
//将顶点着色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//将片元着色器加入到程序
GLES30.glAttachShader(programId, fragmentShaderId);
//链接着色器程序
GLES30.glLinkProgram(programId);
return programId;
}
//从shader文件读出字符串
private String readShaderFromResource(int shaderId) {
InputStream is = mContext.getResources().openRawResource(shaderId);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
}
vertex_shader.glsl
#version 300 es
layout (location = 0) in vec4 vPosition;
void main() {
gl_Position = vPosition;
gl_PointSize = 20.0; //顶点大小(GL_POINTS模式下才会生效)
}
顶点着色器的作用:进行矩阵变换位置、根据光照公式计算顶点颜⾊、⽣成 / 变换纹理坐标,并且把位置和纹理坐标发送到片元着色器。
顶点着色器中,如果没有指定默认精度,则 int 和 float 的默认精度都为 highp。
fragment_shader.glsl
#version 300 es
precision mediump float; //声明float型变量的精度为mediump
out vec4 fragColor;
void main() {
fragColor = vec4(0.2, 1.0, 1.0, 1.0); //顶点、边线、内部填充颜色
}
片元着色器的作用:处理经光栅化阶段生成的每个片元,计算每个像素的颜色和透明度。
在片元着色器中,浮点值没有默认的精度值,每个着色器必须声明一个默认的 float 精度。
运行结果:
1)GL_POINTS 模式
2)GL_LINE_LOOP 模式
3)GL_TRIANGLES 模式
声明:本文转自【OpenGL ES】绘制三角形
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~