OpenGL_ES_三角形
程序员文章站
2023-12-24 22:08:45
...
OpenGL ES2.0 绘制三角形
效果
public class Demo2Activity extends AppCompatActivity {
boolean isRenderSet = false;
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//判断是否支持ES2.0
if (!isSupportES()) {
//不支持
Toast.makeText(this, "当前设备不支持OpenGL ES2.0", Toast.LENGTH_SHORT).show();
LogUtil.log_d("=============当前设备不支持2.0==");
return;
}
glSurfaceView = new GLSurfaceView(this);
//必须要设置OpenGL ES的版本 否则无法使用 当然也可以在清单文件中声明
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(new MyRender());
isRenderSet = true;
setContentView(glSurfaceView);
}
/**
* 判断是否支持 Es2.0
*
* @return true 支持2.0
*/
public boolean isSupportES() {
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo deviceConfigurationInfo = activityManager.getDeviceConfigurationInfo();
// return deviceConfigurationInfo.reqGlEsVersion>=0x20000; 这段代码只能在真机上运行不能在模拟器上运行,为了兼容模拟器,应该写如下的代码
return deviceConfigurationInfo.reqGlEsVersion >= 0x20000
|| (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1 && (Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")));
}
/**
* 绘制一个三角形
*/
class MyRender implements GLSurfaceView.Renderer {
//记录当前顶点数据一个是有2个数据组成
private final int VERTEX_COMPONMENT_COUNT = 2;
private final String A_POSITION = "a_Position";
private final String U_COLOR = "u_Color";
//每一个float数所占的字节数量
private final int FLOAT_PER_BYTE = 4;
private final FloatBuffer vertexBuffer;
private int uColorLocation;
public MyRender() {
//绘制三角形
//首先定义三角形的顶点
float[] vertexs = new float[]{
-0.5f, -0.5f,
0.5f, -0.5f,
0f, 0.5f
};
//将float数据 转换为gpu可以读取的本地floatbuffer
vertexBuffer = ByteBuffer.allocateDirect(vertexs.length * FLOAT_PER_BYTE)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexs);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
//设置清屏颜色 1.0 1.0 1.0 白色
GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);
//读取顶点着色器程序代码,
String stringVertex = TextResourceRead.readTextFileFromResource(Demo2Activity.this, R.raw.demo2_vertex);
//读取片段着色器程序
String stringFragment = TextResourceRead.readTextFileFromResource(Demo2Activity.this,R.raw.demo2_fragment);
//获取顶点着色器id
int vertexShaderID = ShaderHelp.compileVertexShader(stringVertex);
///获取片段着色器ID
int fragmentShaderID = ShaderHelp.compileFragmentShader(stringFragment);
//链接顶点着色器和片段着色器程序
int programID = ShaderHelp.linkProgram(vertexShaderID, fragmentShaderID);
//判断链接得到的程序是否有效
if (programID==0){
return;
}
//设置OpenGL ES2.0 使用前面生成的程序
GLES20.glUseProgram(programID);
//获取在着色器程序中设置的各个变量的位置
int aPositionLocation = GLES20.glGetAttribLocation(programID,A_POSITION);
uColorLocation = GLES20.glGetUniformLocation(programID,U_COLOR);
//将顶点数据和订单属性绑定在一起
vertexBuffer.position(0);
GLES20.glVertexAttribPointer(aPositionLocation,VERTEX_COMPONMENT_COUNT,GLES20.GL_FLOAT,false,0,vertexBuffer);
GLES20.glEnableVertexAttribArray(aPositionLocation);
}
@Override
public void onSurfaceChanged(GL10 gl10, int i, int i1) {
}
@Override
public void onDrawFrame(GL10 gl10) {
//给片段着色器设置uniform值
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUniform4f(uColorLocation,1.0f,0f,0f,1.0f);
vertexBuffer.position(0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);
}
}
@Override
protected void onResume() {
super.onResume();
if (isRenderSet){
glSurfaceView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (isRenderSet){
glSurfaceView.onPause();
}
}
}
shaderHelp 类
public class ShaderHelp {
/**
* 编译顶点着色器
* @param shaderCode 着色器代码
* @return
*/
public static int compileVertexShader(String shaderCode){
return compileShader(GLES20.GL_VERTEX_SHADER,shaderCode);
}
/**
* 编译片段着色器
* @param shaderCode 着色器代码
* @return
*/
public static int compileFragmentShader(String shaderCode){
return compileShader(GLES20.GL_FRAGMENT_SHADER,shaderCode);
}
/**
* 编译着色器
* @param type 着色器类型
* @param shaderCode 着色器代码
* @return 成功创建的着色器对象的引用或者0代表着创建或者编译失败
*/
public static int compileShader(int type,String shaderCode){
//根据着色器类型 创建着色器 返回着色器的引用ID
int shaderID = GLES20.glCreateShader(type);
if (shaderID==0){
//0代表着创建失败
LogUtil.log_d("着色器创建失败");
return 0;
}
//如果创建着色器成功的话,将传入的着色器代码传入到创建的着色器中
GLES20.glShaderSource(shaderID,shaderCode);
//编译着色器
GLES20.glCompileShader(shaderID);
//获取编译状态 判断编译结果是否正确
int[] compileStatus = new int[1];
GLES20.glGetShaderiv(shaderID, GLES20.GL_COMPILE_STATUS,compileStatus,0);
//打印编译结果
LogUtil.log_d("编译结果是:shadercode==\n"+shaderCode+"\n"+"结果:"+GLES20.glGetShaderInfoLog(shaderID)+"\n");
//判断编译结果
if (compileStatus[0]==0){
//删除着色器对象
GLES20.glDeleteShader(shaderID);
LogUtil.log_d("编译失败");
return 0;
}
//此时代表着编译成功
return shaderID;
}
/**
* 连接片段着色器和顶点着色器 成为一个程序program
* @param vertexShaderID 顶点的着色器id
* @param fragmentShaderID 片段着色器id
* @return 返回程序id 0代表着程序创建或者连接失败
*/
public static int linkProgram(int vertexShaderID,int fragmentShaderID){
//创建程序
int programID = GLES20.glCreateProgram();
if (programID==0){
LogUtil.log_d("着色器程序创建失败");
return 0;
}
//创建成功
//将顶点着色器和片段着色器连接到程序上
GLES20.glAttachShader(programID,vertexShaderID);
GLES20.glAttachShader(programID,fragmentShaderID);
//链接程序
GLES20.glLinkProgram(programID);
//获取着色器链接程序的结果
int[] linkstatus = new int[1];
GLES20.glGetProgramiv(programID, GLES20.GL_LINK_STATUS,linkstatus,0);
if (linkstatus[0]==0){
//链接失败
LogUtil.log_d("程序链接失败:"+GLES20.glGetProgramInfoLog(programID)+"\n");
return 0;
}
//链接成功
return programID;
}
/**
* 通过顶点着色器代码和片段着色器代码 建立程序
* @param vertexShaderSource 顶点着色器
* @param fragmentShaderSource 片段着色器
* @return 建立代码的id
*/
public static int buildProgram(String vertexShaderSource,String fragmentShaderSource){
int vertexShaderID = compileVertexShader(vertexShaderSource);
int fragmentShaderID = compileFragmentShader(fragmentShaderSource);
int programID;
programID = linkProgram(vertexShaderID,fragmentShaderID);
validateProgram(programID);
return programID;
}
/**
* 验证该程序是否是高效的
* @param programID
* @return
*/
public static boolean validateProgram(int programID){
GLES20.glValidateProgram(programID);
int[] validateStatus = new int[1];
GLES20.glGetProgramiv(programID, GLES20.GL_VALIDATE_STATUS,validateStatus,0);
LogUtil.log_d("程序是否高效的验证结果是:"+validateStatus[0]+"\n返回信息是"+GLES20.glGetProgramInfoLog(programID));
return validateStatus[0]!=0;
}
}
TextResourceRead类
/**
* Created by WangKunKun on 2018/7/16
* 注解:读取资源文件中的着色器
**/
public class TextResourceRead {
public static String readTextFileFromResource(Context context, int resourceID) {
StringBuilder stringBuilder = new StringBuilder();
try {
InputStream inputStream = context.getResources().openRawResource(resourceID);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String nextLine;
while ((nextLine = bufferedReader.readLine()) != null) {
stringBuilder.append(nextLine);
stringBuilder.append("\n");
}
} catch (IOException e) {
throw new RuntimeException("无法打开资源:"+resourceID,e);
} catch (Resources.NotFoundException r) {
throw new RuntimeException("找不到资源:"+resourceID,r);
}
return stringBuilder.toString();
}
}
顶点着色器 demo2_vertex.glsl
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
}
片段着色器 demo2_fragment.glsl
precision mediump float;
uniform vec4 u_Color;
void main() {
gl_FragColor = u_Color;
}