本文主要是介绍Android Open GL ES - 绘制三角形,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
初始化GLSurfaceView
接下来我们将尝试使用OpenGLES绘制一个三角形,首先创建一个Android Studio Project,OpenGLESTriangles
接下来我们来学习初始化Open GL ES
,MainActivity.java
内部代码如下:
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);}
在Android 4.0以前我们进行Open GL
渲染主要依赖于GLSurfaceView
这个类,GLSurfaceView
实际上创建了一个自持的独立窗体,在View
层开放一个接口用于展示OpenGL Surface
中的内容,因此它不像普通View
一样对旋转,动画等支持的那么良好。在Android 4.0后添加了TextureView
用于展示OpenGL Surface
,这个View
并不像GLSurfaceView
一样需要创建一个单独的窗体,这里我们先学习使用GLSurfaceView
。
在MainActivity.java
中添加如下代码,用于声明GLSurfaceView
对象以及记录当前设置是否支持Open GLES2.0
:
private GLSurfaceView mGLSurfaceView;private boolean mRendererSet = false;
随后我们需要判断当前设置是否支持Open GL ES 2.0
,如果支持,就初始化GLSurfaceView
,如果不支持,就弹出Toast
告知用户,具体代码如下:
/*** help to judge whether device support open gl es version 2.0* @param context* @return true:support 2.0 version,false:do not support 2.0 version*/public static boolean isSupportOpenGLES2(Context context) {ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();return configurationInfo.reqGlEsVersion >= 0x20000 || (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1 && (Build.FINGERPRINT.startsWith(FINGERPRINT_GENERIC) || Build.FINGERPRINT.startsWith(FINGERPRINT_UNKNOWN) || Build.MODEL.contains(MODEL_GOOGLE)|| Build.MODEL.contains(MODEL_EMULATOR) || Build.MODEL.contains(MODEL_SDK)));}
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mGLSurfaceView = new GLSurfaceView(this);if (DeviceInfor.isSupportOpenGLES2(this)){mGLSurfaceView.setEGLContextClientVersion(2);mGLSurfaceView.setRenderer(new TriangleRenderer(this));mRendererSet = true;}else {Toast.makeText(this, "This Device does not support open gl es 2.0 version!", Toast.LENGTH_SHORT).show();return;}setContentView(mGLSurfaceView);}
由于GLSurfaceView
是连接Open GL ES
和Android View
之间的桥梁,所以它和Android
组件一样,拥有完整的生命周期函数,在初始化后需要管理它的生命周期,代码如下:
@Overrideprotected void onPause() {super.onPause();if (mRendererSet){mGLSurfaceView.onPause();}}@Overrideprotected void onResume() {super.onResume();if (mRendererSet){mGLSurfaceView.onResume();}}
在完成基本的GLSurfaceView
创建后,我们来了解一些关于Open Gl ES
的基础知识。
Open Gl ES
基础
1.在Open Gl ES
中只支持三种基本图形,点,线和三角形,所有复杂图形均由这三者绘制而成。
2.在Open Gl ES
中绘制图形依赖于渲染器(Renderer
),在渲染器中完成图形渲染。在渲染器中使用着色器对图形的每一个位置进行着色,在Open Gl ES
中有两类着色器,顶点着色器(VertexShader
)和片段着色器(FragmentShader
),在渲染器中通过加载,编译着色器,链接程序来完成图形渲染。
按照上文所说我们接下来定义三角形的顶点信息,以及着色器文件。
三角形与着色器(Shader)
接下来为我们的项目添加渲染器(Renderer
),代码如下:
public class TriangleRenderer implements Renderer {public static final String TAG = "TriangleRenderer";private Context mContext;public TriangleRenderer(Context context) {mContext = context;}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {}@Overridepublic void onDrawFrame(GL10 gl) {}
}
在Open Gl ES中,其使用的是世界坐标系(即绝对坐标系),附图如下:
在该坐标系中,坐标原点位于屏幕中心,XYZ三轴符合右手法则,我们定义三角形的顶点信息如下(PS:不考虑Z轴):
float[] vertexTrangles = {-1.0f, -1.0f,1.0f, -1.0f,0f, 1.0f};
定义存储三角形的Buffer
信息如下:
private static final int BYTES_PER_FLOAT = 4;//每个Float占四个字节
private FloatBuffer vertexData;//存储顶点数据的Buffer
private static final int POSITION_COMPONENT_COUNT = 2;//代表点坐标的个数
将上述代码写入渲染器中,在渲染器的构造函数中为三角形顶点初始化缓存大小,代码如下:
vertexData = ByteBuffer.allocateDirect(vertexTrangles.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();vertexData.put(vertexTrangles);
随后编写Open Gl ES
着色器文件,在res目录下新建raw文件夹,并新建simple_vertex_shader.glsl
文件,内容如下:
attribute vec4 a_Position;
#定义一个点的位置信息
void main(){gl_Position = a_Position;
}
新建simple_fragement_shader.glsl
文件,内容如下:
#数据类型
precision mediump float;
#片段着色器中的色值
uniform vec4 u_Color;void main(){gl_FragColor = u_Color;
}
加载编译Shader
,链接程序
从资源文件中读取glsl
文件转化成String
,工具函数如下:
/*** read glsl file from resource* @param context* @param resourceId example R.raw.vertex_shader* @return*/public static String readTextFileFromResource(Context context,int resourceId){StringBuilder body = new StringBuilder();try {InputStream inputStream = context.getResources().openRawResource(resourceId);InputStreamReader inputStreamReader = new InputStreamReader(inputStream);BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String nextLine;while ((nextLine = bufferedReader.readLine()) != null){body.append(nextLine);body.append('\n');}} catch (IOException e) {e.printStackTrace();}return body.toString();}
编译着色器文件,代码如下:
public static int compileVertexShader(String shaderCode) {return compileShader(GL_VERTEX_SHADER, shaderCode);}public static int compileFragmentShader(String shaderCode) {return compileShader(GL_FRAGMENT_SHADER, shaderCode);}private static int compileShader(int type, String shaderCode) {int shaderObjectId = glCreateShader(type);if (shaderObjectId == 0) {return 0;}glShaderSource(shaderObjectId, shaderCode);glCompileShader(shaderObjectId);final int[] compileStatus = new int[1];glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);if (compileStatus[0] == 0) {glDeleteShader(shaderObjectId);return 0;}return shaderObjectId;}
随后我们在渲染器中完成程序的构建使用,核心代码如下:
@Overridepublic void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {gl10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//加载Shader fileString vertexShaderSource = TextResourceReader.readTextFileFromResource(mContext, R.raw.simple_vertex_shader);String fragmentShaderSource = TextResourceReader.readTextFileFromResource(mContext, R.raw.simple_fragment_shader);//编译Shaderint vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource);int fragmentShader = ShaderHelper.compileFragmentShader(fragmentShaderSource);//链接程序mProgramId = ShaderHelper.linkProgram(vertexShader, fragmentShader);//验证程序ShaderHelper.validateProgram(mProgramId);//使用程序glUseProgram(mProgramId);//查找颜色片元位置uColorLocation = glGetUniformLocation(mProgramId, U_COLOR);//查找顶点片元位置aPositionLocation = glGetAttribLocation(mProgramId, A_POSITION);//重置数据集位置vertexData.position(0);//读取顶点信息并渲染glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0,vertexData);glEnableVertexAttribArray(aPositionLocation);}
以上代码中的链接程序函数源码如下:
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {int programId = glCreateProgram();if (programId == 0) {return 0;}//完成着色器和程序之间的绑定glAttachShader(programId, vertexShaderId);glAttachShader(programId, fragmentShaderId);//链接程序glLinkProgram(programId);final int[] linkStatus = new int[1];glGetProgramiv(programId, GL_LINK_STATUS, linkStatus, 0);if (linkStatus[0] == 0) {glDeleteProgram(programId);return 0;}return programId;}public static boolean validateProgram(int programId) {glValidateProgram(programId);final int[] validateStatus = new int[1];glGetProgramiv(programId, GL_VALIDATE_STATUS, validateStatus, 0);return validateStatus[0] != 0;}
绘制三角形
修改渲染器中代码如下:
@Overridepublic void onSurfaceChanged(GL10 gl10, int i, int i1) {gl10.glViewport(0, 0, i, i1);}@Overridepublic void onDrawFrame(GL10 gl10) {gl10.glClear(gl10.GL_COLOR_BUFFER_BIT);//传入片元颜色值,可以通过改变最后四个参数值参看片元渲染后的颜色变化glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);//绘制三角形glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);}
运行截图如下:
最新文章更新在微信公众号上,欢迎关注获取详情:
完整代码Github地址这里写链接内容
这篇关于Android Open GL ES - 绘制三角形的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!