openGL ES2.0 如何绘制一个三角形

一、Android OpenGL ES2.0简介

1、什么是OpenGL

OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D3D矢量图形的跨语言跨平台应用程序编程接口(API)。这个接口由近350个不同的函数调用组成,用来从简单的图形比特绘制复杂的三维景象。而另一种程序接口系统是仅用于Microsoft Windows上的Direct3D。OpenGL常用于CAD虚拟实境、科学可视化程序和电子游戏开发。 ————百度百科

说简单就是:

OpenGL是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。

OpenGL在不同的平台上有不同的实现,但是它定义好了专业的程序接口,不同的平台都是遵照该接口来进行实现的,思想完全相同,方法名也是一致的,所以使用时也基本一致,只需要根据不同的语言环境稍有不同而已。

2、什么是OpenGL ES

OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。

OpenGL ES相对于OpenGL来说,减少了许多不是必须的方法和数据类型,去掉了不必须的功能,对代价大的功能做了限制,比OpenGL更为轻量。在OpenGL ES的世界里,没有四边形、多边形,无论多复杂的图形都是由点、线和三角形组成的,也去除了glBegin/glEnd等方法

3、OpenGL ES可以做什么

OpenGL ES是手机、PDA和游戏主机等嵌入式设备三维(二维也包括)图形处理的API,当然是用来在嵌入式设备上的图形处理了,OpenGL ES 强大的渲染能力使其成为我们在嵌入式设备上进行图形处理的优良选择。我们经常使用的场景有:
1.图片处理。比如图片色调转换、美颜等。
2.摄像头预览效果处理。比如美颜相机、恶搞相机等。
3.视频处理。摄像头预览效果处理可以,这个自然也不在话下了。
4.3D游戏。比如神庙逃亡、都市赛车等。

4.OpenGL ES 2.0中基本概念
4.1着色器

OpenGL ES 2.0中最重要的一个概念就是关于着色器:顶点着色器和片元着色器。

着色器(Shader)是在GPU上运行的小程序。从名称可以看出,可通过处理它们来处理顶点。此程序使用OpenGL ES SL语言来编写。它是一个描述顶点或像素特性的简单程序。

.顶点着色器

其功能是把每个顶点在虚拟空间中的三维坐标变换为可以在屏幕上显示的二维坐标,并带有用于z-buffer的深度信息。顶点着色器可以操作的属性有:位置、颜色、纹理坐标,但是不能创建新的顶点。

.片元着色器

片元着色器计算每个像素的颜色和其它属性。它通过应用光照值、凹凸贴图,阴影,镜面高光,半透明等处理来计算像素的颜色并输出。它也可改变像素的深度(z-buffering)或在多个渲染目标被激活的状态下输出多种颜色。

着色器语言(Shading Language)是一种高级的图形编程语言,仅适合于GPU编程,其源自应用广泛的C语言。对于顶点着色器和片元着色器的开发都需要用到着色器语言进行开发。它是面向过程的而非面向对象。具体可参照相关资料。因此,对于绘制不同的图形时,所编写的着色器语言不同,这个需要大家参照相关例子学习。

4.2坐标

OpenGL ES 采用的是右手坐标,即向右为X正轴方向,向左为X负轴方向,向上为Y轴正轴方向,向下为Y轴负轴方向,屏幕面垂直向上为Z轴正轴方向,垂直向下为Z轴负轴方向。下图是对比右手和左手坐标系。



由于实际的绘制是3D图形,投影到屏幕中显示的是2D效果,因此这里需要转换就是3D到2D图形的转换。如下图所示,实际运行是采用选取屏幕中心为原点,原点到屏幕边缘的长度为单位1,由于屏幕中心点到边缘的长度不同(屏幕一般都是长方形,而不是正方形),即:屏幕到宽的距离相对较小,因此从原点到(1,0,0)的距离和到(0,1,0)的距离在屏幕上展示的并不相同。



在实际运行设置坐标时,就会出现一定的图形变换,例如绘制一个等边三角形,在实际投射到屏幕中时,显示的却是等边三角形,这个就是上面提到的屏幕中心点到屏幕边缘的长度是单位长度,在实际投射时,屏幕到宽和高的比例不同,出现如下图所示的展示效果。
4.3 其他

除了上面提到的着色器和坐标外,还包括投影、光照和纹理映射等。

1.投影:OpenGL ES中有两种投影方式:正交投影和透视投影。正交投影,物体不会随距离观测点的位置而大小发生变化。而透视投影,距离观测点越远,物体越小,距离观测点越近,物体越大。
2.光照:在屏幕中很难直接的显示3D场景的效果,因为曲面相对平面更具有光照效果,因此在实际的绘制中,需要加入光照元素:环境光、镜面光和散射光。
3.纹理映射:现实世界中的物体往往是绚丽多彩的,要模拟现实世界的绚丽多彩,绘制出更加真实、酷炫的3D物体,就需要用到纹理映射了。纹理映射是将2D的纹理映射到3D场景中的立体物体上。

4.4 OpenGL ES 2.0运行过程

读取顶点数据——执行顶点着色器——组装图元——光栅化图元——执行片元着色器——写入帧缓冲区——显示到屏幕上。

1.OpenGL作为本地库直接运行在硬件上,没有虚拟机,也没有垃圾回收或者内存压缩。在Java层定义图像的数据需要能被OpenGL存取,因此,需要把内存从Java堆复制到本地堆。

2.顶点着色器是针对每个顶点都会执行的程序,是确定每个顶点的位置。同理,片元着色器是针对每个片元都会执行的程序,确定每个片元的颜色。
3.着色器需要进行编译,然后链接到OpenGL程序中。一个OpenGL的程序就是把一个顶点着色器和一个片段着色器链接在一起变成单个对象。

二、绘制一个简单三角形的步骤

1.manifest声明OpenGL ES2.0
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<!--0x00020000表示版本号-->
2.构造GLSufaceView.Render对象

Renderer类提供三个回调方法供Android系统调用,用来计算在GLSurfaceView中绘制什么以及如何绘制。
onSurfaceCreated():仅调用一次,用于设置view的OpenGL ES环境(初始化)
onDrawFrame():每次重绘view时调用,我们自定义的绘制主要是在该方法中实现
onSurfaceChanged():当view的几何形状发生变化时调用,比如设备屏幕方向改变时

public class TriggerRender implements GLSurfaceView.Renderer {
    float triangleCoords[] = {
            0.5f, 0.5f, 0.0f, // top
            -0.5f, -0.5f, 0.0f, // bottom left
            0.5f, -0.5f, 0.0f  // bottom right
    };
    float color[] = {1.0f, 0f, 0f, 1.0f}; //red
    private FloatBuffer vertexBuffer;
    private final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";
    private int mProgram;
    private int mPositionHandle;
    private int mColorHandle;
    static final int COORDS_PER_VERTEX = 3;
    //顶点个数
    private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
    //顶点之间的偏移量
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        //将背景设置为灰色
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        //将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
        vertexBuffer = BufferUtil.fBuffer(triangleCoords);

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        //创建一个空的OpenGLES程序
        mProgram = GLES20.glCreateProgram();
        //将顶点着色器加入到程序
        GLES20.glAttachShader(mProgram, vertexShader);
        //将片元着色器加入到程序中
        GLES20.glAttachShader(mProgram, fragmentShader);
        //连接到着色器程序
        GLES20.glLinkProgram(mProgram);
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        //将程序加入到OpenGLES2.0环境(加载
        // )
        GLES20.glUseProgram(mProgram);

        //获取顶点着色器的vPosition成员句柄
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        //启用三角形顶点的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);
        //获取片元着色器的vColor成员的句柄
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        //设置绘制三角形的颜色
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        //绘制三角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
        //禁止顶点数组的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
    public int loadShader(int type, String shaderCode) {
        //根据type创建顶点着色器或者片元着色器
        int shader = GLES20.glCreateShader(type);
        //将资源加入到着色器中,并编译
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }
}
3.构造GLSurfaceView对象
public class MyGLSurfaceView extends GLSurfaceView {
    private final  TriggerRender mRender;
    public MyGLSurfaceView(Context context) {
        super(context);
        setEGLContextClientVersion(2);
        mRender = new TriggerRender();
        setRenderer(mRender);
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }
}
4、将Activity的ContentView设为GLSurfaceView
public class MainActivity extends AppCompatActivity {
    private MyGLSurfaceView mGLSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mGLSurfaceView = new MyGLSurfaceView(this);
        setContentView(mGLSurfaceView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGLSurfaceView.onPause();
    }
}
5.运行结果
结果
6.总结

1.看上图就知道了,本来是画等边直角三角形,结果两直角边一场一短;
2.在使用 GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f)设置背景色的时候没成功;


本文内容转自 原文,感谢大佬的轮子!
下一篇文章说下怎么画等边多边形,圆,着色等……

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容