转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/61615215
OpenGL是在图形图像中,非常优秀的渲染库,文中Demo下载地址:https://github.com/hejunlin2013/OpenGL31,看下今天的Agenda:
OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。
OpenGL™ 是行业领域中最为广泛接纳的 2D/3D 图形 API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。OpenGL™ 是独立于视窗操作系统或其它操作系统的,亦是网络透明的。在包含CAD、内容创作、能源、娱乐、游戏开发、制造业、制药业及虚拟现实等行业领域中,OpenGL™ 帮助程序员实现在 PC、工作站、超级计算机等硬件设备上的高性能、极具冲击力的高视觉表现力图形处理软件的开发。
OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与Visual C++紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性;OpenGL使用简便,效率高。它具有七大功能:
OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
Android包括支持高性能2d和3d图形与开放图形库(OpenGL®),具体来说,OpenGL ES API。OpenGL是一个跨平台图形API,用于指定一个标准为3 d图形处理硬件的软件接口。OpenGL ES的味道OpenGL规范用于嵌入式设备。Android支持OpenGL ES API的几个版本:
Android支持OpenGL通过其框架API和本地开发工具包(NDK)。
在Android框架有两个基本类,让你创建和操作图形与OpenGL ES API:GLSurfaceView GLSurfaceView.Renderer。
GLSurfaceView
public void setRenderer(GLSurfaceView.Renderer renderer)
GLSurfaceView.Renderer
这个接口定义了在GLSurfaceView绘制图形时所需的方法。既然是接口,那么就必须有一个实现该接口的类。然后使用GLSurfaceView.setRenderer(这里接收那个具体实类)方法,把这个实现类set到GLSurfaceView上。
GLSurfaceView.Renderer接口需要实现以下方法:
AndroidManifest.xml中加入:
For OpenGL ES 2.0:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
For OpenGL ES 3.0:
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
For OpenGL ES 3.1:
<uses-feature android:glEsVersion="0x00030001" android:required="true" />
OpenGL是假定一个正方形,统一系统坐标,默认情况下,它是将这些看起来在非正方形的屏幕上,看起来像正方形。
默认的OpenGL坐标系(左)映射到一个典型的Android设备屏幕(右)。
上面的图显示了(左边)一个OpenGL的统一坐标系统,和如何将这些坐标映射到(右边)一个典型的横向设备屏幕。为了解决这个问题,我们可以应用OpenGL正确的比例下通过投影模式和相机视图坐标转换你的图形对象。
为了应用投影和相机视图,我们创建一个投影矩阵和一个相机视图矩阵并将它们应用于OpenGL渲染管道中。投影矩阵重新计算你的图形的坐标,使他们正确地映射到Android设备的屏幕。相机视图矩阵创建一个转换,它将从一个特定的位置显示对象。
投影(Projection)和OpenGL ES 1.0相机视图( Camera View )
投影矩阵——创建一个投影矩阵使用设备屏幕以重新计算对象的几何坐标所以他们用正确的比例。下面的示例代码演示了如何修改onSurfaceChanged GLSurfaceView()方法。渲染器实现来创建一个基于屏幕的长宽比和投影矩阵应用于OpenGL渲染环境。
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
// make adjustments for screen ratio
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode
gl.glLoadIdentity(); // reset the matrix to its default state
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection matrix
}
相机变换矩阵——一旦你使用投影矩阵调整坐标系统,我们还必须添加一个相机视图。下面的示例代码显示了如何修改onDrawFrame GLSurfaceView()方法。渲染器实现应用模型视图,并使用GLU.gluLookAt()实用程序来创建一个模拟摄像机观察变换位置。
public void onDrawFrame(GL10 gl) {
...
// Set GL_MODELVIEW transformation mode
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // reset the matrix to its default state
// When using GL_MODELVIEW, you must set the camera view
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
...
}
投影和OpenGL ES 2.0和更高版本的相机视图
ES 2.0和3.0 api,应用投影和相机视图首先要添加一个矩阵图形的顶点着色器(Shader)对象成员。添加了这个矩阵成员,我们可以生成和应用投影和相机观察矩阵对象。
顶点着色器添加矩阵——为视图创建一个变量投影矩阵,包括乘数着色器的位置。在下面的例子中顶点着色器代码,包括uMVPMatrix成员允许您应用投影和相机观测矩阵的坐标对象。
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of objects that use this vertex shader.
"uniform mat4 uMVPMatrix; \n" +
"attribute vec4 vPosition; \n" +
"void main(){ \n" +
// The matrix must be included as part of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition; \n" +
"} \n";
访问着色矩阵之后,创建一个钩在你的顶点着色器应用投影和相机视图中,您可以访问该变量应用投影和相机观测矩阵。下面的代码演示如何修改onSurfaceCreated GLSurfaceView()方法。渲染器实现访问上面的顶点着色器中定义的矩阵变量。
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
...
}
创建投影和相机观察矩阵——生成投影矩阵和查看应用的图形对象。下面的示例代码显示了如何修改onSurfaceCreated()和onSurfaceChanged GLSurfaceView()方法。渲染器实现创建相机视图矩阵和投影矩阵基于设备的屏幕宽高比。
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...
// Create a camera view matrix
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// create a projection matrix from device screen geometry
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
应用投影和相机观察矩阵——应用投影和相机视图的转换,将矩阵的相乘,然后设置在顶点着色器中。下面的代码显示了如何修改onDrawFrame GLSurfaceView()方法。渲染器实现结合投影矩阵和相机视图中创建上面的代码,然后把它应用到由OpenGL渲染的图形对象。
public void onDrawFrame(GL10 unused) {
...
// Combine the projection and camera view matrices
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
// Apply the combined projection and camera view transformations
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Draw objects
...
}
在OpenGL,一个形状是一个表面由三个或更多的点在三维空间中定义的。一组三个或更多三维点(称为顶点在OpenGL)有正面和背面。你怎么知道哪面是正面和背面?答案是 winding,或者简单的说,你定义点的方向。
在这个例子中,三角形的点是通过一定的顺序定义的,以致它们是通过逆时针方向绘制的。这些坐标定义的顺序就是环绕方向。默认情况下,在OpenGL中,我们正对的方向是逆时针画的方向。上图所示的三角形定义,我们看到就是正面,另一边是背面。
为什么我们要知道,我们面对的是不是正面?原因是:在处理OpenGL的常用特性时,有一个叫Face culling的环境因素,Face culling是OpenGL中一个可以参考的环境,它可以让你在渲染到pipeline的过程中忽略背面(不计算或绘制),节省时间,内存和处理周期。
// enable face culling feature
gl.glEnable(GL10.GL_CULL_FACE);
// specify which faces to not draw
gl.glCullFace(GL10.GL_BACK);
如果我们尝试使用Face culling特性,但又不知道它的形状是正面和背面,我们的OpenGL图形看起来有点怪,或者有时根本不显示。所以,总是定义我们的OpenGL图形的坐标逆时针顺序。
效果图:
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。