OpenGl-ES2.0 For Android 读书笔记(二)

一、开始

现在我们要做的内容是让我们的桌面看起来更真实一些,我们基本上来说有两个事情要做,一个是让桌面的颜色不要那么的单调,一个就是需要适配屏幕的比例。
最终我们完成的效果如下图:

效果图.png

二、让桌面有变化的颜色

好的,现在就让我们学习如何让桌面的颜色有变化,我们看到我们最终完成的效果图其实是四边比较暗,中间比较亮,同时我们也知道,在上篇文章中,我们是用两个三角形去绘制的,所以这种效果是达不到的,这个时候我们就可以去学一个新东西了,叫做TRIANGLE FAN,它的绘制原理可以看下图:

triangle_fan.png

就是定义一个中心点,然后其他不论定义多少点,都是按照图中的顺序去绘制三角形的,按照这张图我们就可以解决四边暗,中间亮的问题了。
我们需要把三角型定义的那块数据修改下

// Triangle Fan
0,     0,
-0.5f, -0.5f,
0.5f, -0.5f,
0.5f,  0.5f,
-0.5f, -0.5f,

然后绘制的方法也需要修改下,如下:

glDrawArrays(GL_TRIANGLE_FAN, 0, 6);

接下来就要解决我们的重点问题了,如何让颜色产生变化呢?
OpenGL提供了一个叫做Smooth Shading东西去做这件事,他让我们可以平稳的改变线和三角形的颜色,原文是这样说的:

OpenGL gives us a way to smoothly blend the colors at each vertex across a line or across the surface of a triangle.

要让颜色变化,就需要告诉OpenGL要用什么颜色去绘制,所以我们的数据需要修改成这个样子:

private final float[] mData = new float[]{
            // Order of coordinates: X, Y, R, G, B

            // Triangle Fan
            0f,    0f,   1f,   1f,   1f,
            -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
            0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
            0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
            -0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
            -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,

            // 线
            -0.5f, 0f, 1f, 0f, 0f,
            0.5f, 0f, 1f, 0f, 0f,
            
            // 点
            0f, -0.25f, 0f, 0f, 1f,
            0f,  0.25f, 1f, 0f, 0f
    };

前面两个参数还是点的坐标,后面三个参数是表示RGB颜色的,然后大家可能对一个三角形的颜色是怎么根据三个点的颜色来变化的不太清楚,现在解释下就清楚了,看下图:

颜色计算.png

其实三角形内的每个点的颜色都是根据三个点的颜色,然后乘以比例得到的,大家如果想了解的话,可以自己去看书,或者查资料。
现在我们定义了颜色的数据,我们要让OpenGL去使用我们定义的颜色数据,我们先修改下simple_vertex_shader.glsl的代码:

attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;

void main() {
    gl_Position = a_Position;
    gl_PointSize = 10.0;

    v_Color = a_Color;
}

我们定义了一个attribute叫做a_Color,这个不用解释了,大家还没见过varying,书上对varying是这样解释的:

A varying is a special type of variable that blends the values given to it and sends these values to the fragment shader.

就是一种特殊的变量混合给到他的值然后传递给fragment shader进行绘制,在这里就是混合三个顶点的颜色值,然后计算出该点的颜色,传递给fragment shader进行绘制,我们已经计算出来颜色了,接下来就是在fragment shader中使用它了,修改simple_fragment_shader.glsl代码如下:

precision mediump float;

varying vec4 v_Color;

void main() {
    gl_FragColor = v_Color;
}

这样我们的OpenGL就可以用计算出来的颜色去绘制每个点了,u_Color已经没用了,注意删掉相关代码。
接下来我们就需要修改我们的java代码了,首先我们添加这些定义:

private static final String A_COLOR = "a_Color";
private static final int COLOR_COMPONENT_COUNT = 3;
private static final int STRIDE = (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * BYTE_PRE_FLOAT;

private int mAColorLocation;

第一行和最后一行看过上篇文章的人应该都知道是干嘛用的了,COLOR_COMPONENT_COUNT表示的是颜色参数的个数,RGB三个值,然后最后STRIDE上篇文章有提到,这里解释下,原文是这样说的:

Did you notice that we added a special constant, called STRIDE? As we now have both a position and a color attribute in the same data array, OpenGL can no longer assume that the next position follows immediately after the previous position. Once OpenGL has read the position for a vertex, it will have to skip over the color for the current vertex if it wants to read the position for the next vertex. We’ll use the stride to tell OpenGL how many bytes are between each position so that it knows how far it has to skip.

意思就是当我们的数据有两种属性的时候,我们需要这个值去告诉OpenGL取其中一种属性的时候,需要跳过多少值。
然后我们需要获取a_Color的位置信息:

mAColorLocation = glGetAttribLocation(mProgram , A_COLOR);

然后修改告诉OpenGL如何取值的那块代码需要修改成下面的样子:

mVertexData.position(0);
glVertexAttribPointer(mAPositionLocation , POSITION_COMPONENT_COUNT, GL_FLOAT , false , STRIDE , mVertexData);
glEnableVertexAttribArray(mAPositionLocation);

mVertexData.position(POSITION_COMPONENT_COUNT);
glVertexAttribPointer(mAColorLocation , COLOR_COMPONENT_COUNT , GL_FLOAT , false , STRIDE , mVertexData);
glEnableVertexAttribArray(mAColorLocation);

然后运行就可以看到效果了,运行之后你会发现我们好像已经完成了效果图的效果了,但是你可以试着旋转屏幕看看,会出现什么情况,你会发现,桌面变窄了,为了防止这种情况的发生,我们就需要对屏幕比例进行适配,就是接下来我们要学习的内容。

三、适配屏幕的比例

原文是这样说的:

To adjust the coordinate space so that we can take screen orientation into account, we need to stop working directly in normalized device coordinates and start working in a virtual coordinate space.

正常的设备坐标系是不考虑屏幕比例的,所以会导致上面的情况发生。所以我们需要在虚拟坐标系中绘制。所以我们要找到一个办法把虚拟坐标系中的点转换成正常的设备坐标系的点的坐标,要做到这点,我们就需要正投影了,用正投影需要用到矩阵的知识,书中有讲解,大家可以自己看书,也可以查资料,看这个只是了解一个方法的实现原理,在这里就不详细讲述了,只告诉大家怎么去用这个方法好了。
我们需要用到的方法是在android.opengl包下的

orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)

具体的参数解释在原文中这这样的:

Paste_Image.png

具体每个值代表什么看注释应该了解一些了,我们在使用中再去深入了解,用这个矩阵我们就可以获得虚拟坐标系中的点在正常的设备坐标系中的点的坐标了,然后我们现在就要去使用这个矩阵了,先修改simple_vertex_shader.glsl中的代码如下:

uniform mat4 u_Matrix;

attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;

void main() {

    v_Color = a_Color;

    gl_Position = u_Matrix * a_Position;
    gl_PointSize = 10.0;
}

我们定义了一个矩阵u_Matrix,mat4表示我们定义的变量是一个4×4的矩阵,OpenGL部分的代码修改完了,然后我们就需要在Java代码中为u_Matrix赋值了,首先我们在Renderer中做如下定义:

private static final String U_MATRIX = "u_Matrix";
private int mUMatrixLocation;
private float[] mProjectionMatrix = new float[16];

mProjectionMatrix是定义来储存投影矩阵的,然后我们需要去获取u_Matrix的位置:

mUMatrixLocation = glGetUniformLocation(mProgram , U_MATRIX);

然后在onSurfaceChanged()方法中添加如下代码:

final float aspectRatio = width > height ?
                (float)width / (float) height : (float) height/ (float) width;
if (width > height){
      //横屏
      orthoM(mProjectionMatrix , 0 , -aspectRatio , aspectRatio , -1 , 1 , -1 , 1);
}else {
      //竖屏
      orthoM(mProjectionMatrix , 0 , -1 , 1 , -aspectRatio , aspectRatio , -1 , 1);
}

这样我们就计算除了正投影矩阵,并赋值给了mProjectionMatrix。
最后我们在onDrawFrame()中绘制之前加上如下代码:

glUniformMatrix4fv(mUMatrixLocation , 1 , false , mProjectionMatrix , 0);

运行下就能看到效果了,这下旋转的时候就没有什么变化了,但是有没有觉得不太好看,我们调整下我们的数据,就会好了,调整数据成下面的样子:

private final float[] mData = new float[]{
            // Order of coordinates: X, Y, R, G, B

            // Triangle Fan
            0f,    0f,   1f,   1f,   1f,
            -0.5f, -0.8f, 0.7f, 0.7f, 0.7f,
            0.5f, -0.8f, 0.7f, 0.7f, 0.7f,
            0.5f,  0.8f, 0.7f, 0.7f, 0.7f,
            -0.5f,  0.8f, 0.7f, 0.7f, 0.7f,
            -0.5f, -0.8f, 0.7f, 0.7f, 0.7f,

            //线
            -0.5f, 0f, 1f, 0f, 0f,
            0.5f, 0f, 1f, 0f, 0f,
            
            //点
            0f, -0.4f, 0f, 0f, 1f,
            0f,  0.4f, 1f, 0f, 0f
    };

最后再运行一遍,是不是感觉好多了。

项目代码在这里:https://github.com/KevinKmoo/AirHockeyWithVaryColor

能力有限,自己读书的学习所得,有错误请指导,轻虐!
转载请注明出处。----by kmoo

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

推荐阅读更多精彩内容