对大脑状态的一点认识

人类是一个高智能的动物,他有一个全宇宙最复杂的东西 “大脑”。可能会有人反对,好吧,宇宙很大,充满了未知,说它全地球最复杂的东西总不会错吧?

人的大脑约有100亿~140亿个神经元,大概有银河系的星星那么多。这些脑细胞互相之间产生联系那是错综复杂呀。

有些是被大家熟知的

在一天的不同时间里,大脑的功能状态是不同的,这样就有一个怎样选择最佳时间用脑学习的问题。人的大脑每天有四个记忆高峰期。 第一个是早晨起床后:大脑在睡眠过程中并没有停止工作,而是在对头一天输入的信息进行编码整理。早晨醒后没有新的信息干扰,这时记东西会印象清晰。第二个高峰期是在上午8点到10点:这时精力上升到旺盛期,处理识记效率高,记忆量增大。第三个高峰期是在下午6到8点:这是一天中记忆最佳期。 第四个是临睡前1小时左右:这时识记材料后就入睡,不再有新信息输入,所以没有相互抑制的影响。另外研究者还发现上午8点大脑具有严谨周密的思考能力,下午2点思考能力最敏捷,但推理能力则在白天12小时内递减。根据这些测试,我们在早晨最好安排些严谨周密的工作,下午做一些需要快速完成的工作,晚上则做些需要加深记忆的工作。

另一个被大家熟悉的是情绪影响大脑的状态,比如人在情绪激动的时候容易大脑空白,没法思考,人在愉悦高兴的时候,大脑会超常发挥,在紧张的时候又会被压抑。

还有更神奇一点的,大脑的状态还会被我们的行为状态所改变,最早了解到它是从一本书里,是在高中的时候,他说,当我们不高兴的时候,我们可以做出高兴时候的动作,甚至只是想象高兴时的自己的行为状态,都是起作用的。我信以为真,当时的确鼓励我一阵子,比如,当我感觉战斗力不强了,我就会想想自己是孙悟空,然后来个一飞冲天的姿势,想象自己冲破云霄,然后就真的来劲了。

然而最近,我发现了一个更加不可思议的事情,那就是大脑它是一个状态机,我们的做一些事情,大脑可能会内部可能会进行一定的重组,从而适应这些事情。比如在工作了三年后,我感觉我的大脑已经更加的依赖于左脑。在比如,可能又几天话很多,喜欢跟人聊天,这时候,我的语言组织能力可能会提高,但是就不适合写代码了。我试着想说明白,这种状态的转换,有的是长时间做某些事情实现的。而有的可能是几天的。其实还有个更明显的栗子,当我们连续看上几个恐怖片时,我们就会进入一种状态,在这种状态里,我们会各种思考恐怖的事情。前面提到的重组,还是挺合理的,当我们关注某件事时,相关的神经元就会连接。

好吧,我的写作的神经元没有成功连接,重组出一个适合写作的文章,写的真烂,但是我已经进入了一种不怕写的烂的状态。[哭笑不得]


has-selection
每天写文章前,会画个马里奥,这样可以让心静下来,进入写作状态。
我想说这图太搞笑了。

坚持的伟大

坚持的伟大,取这个名字我只是想表现的积极一点,因为我想说的是“长久坚持一向活动的困难”,它困难,所以我就不做了吗?不是,它足够困难,能够坚持做下去就是伟大。

这个问题我最近想到了两次,大家可能都知道,长久的坚持做一件事情很难,但是具体的其中的原因呢,可能大家没有考虑过,可能觉得没用,也可能觉得那都是借口,可是,我还是想找找其中的原因。

首先让我考虑到这个问题的是在背单词的过程中,我最近在用“扇贝”背单词,第一天好像是四十个,第二天是一百个,我被吓住了,感觉一百个很多,但是我却完成了,并且几乎一天不落的坚持了2周,就每天早上通勤的时间,但是,最近的几天,我用一天的时间都完不成,为什么,有两个原因,一个原因是感觉吃力了,生词变多了,另一个原因是我个人的原因,通勤的过程中就没有付出那些时间来背单词,以不知道干什么了。第二个原因可能也是因为第一个原因,因为背的吃力,感觉没快感,所以会厌烦,也就进行不下去了。

我从这个背单词没有坚持下去的事情,进一步思考,坚持,对于某些事情是一个积累筛选的过程。还是拿扇贝背单词举例,即使它每天分的新单词的量其中词汇的难易程度相同,但是,复习的单词难度会越来越难,而且,还有个机制,就是我可以标记一些简单的单词不在复习,这就会导致每天的单词总的难度,是越来越大的,耗得时间也会增加,进而就是我现在的结果,不过对策倒是很简单,每天的单词量就是了。坚持最重要。

其实这是一个节奏调整的过程。比如跑步,坚持长距离的跑步,我们对自己说,只是坚持一直迈开脚步,往前跑。但是在跑的过程中,我们的体力是消耗,我们的身体能量是在消耗的,所以坚持下去的难度会越来越大。我们要调整自己的速度,呼吸,步伐来让我们坚持跑下去。当我们达到一个临界点,我们的坚持会很轻松。

所以,或许,我们需要调整,和为了坚持而坚持。

重新认识了仰卧起坐

周末很齐大爷逛奥森,我看他肚子大笑话他,然后得意的说自己天天做仰卧起坐,没肚子。他说,仰卧起坐伤身体,对颈椎不好。我十分不屑,感觉毛病特多,接口更多。但是我还是相信他不会瞎说的,可能夸大,就从百度查了查,又从知乎查了查,于是,我感觉惭愧不已,真的是重新认识了仰卧起坐。
知乎上,有人总结了五个错误,我全中。

  • 第一个,双手抱头做仰卧起坐,我以前就一直视这为标准动作的,虽然也见一些视频上,双手放耳边或者放胸前,却没有考虑过为什么,原来这才是标准动作,脖子就不应该受力,容易拉伤颈椎,难怪我有次做完脖子疼。估计齐大爷就是看的这文章,就记住了这一点😂
  • 第二个,借腰用力,这点我也是深有感触,甚至我以为仰卧起坐不就是练腰的吗?好吧,仰卧起坐是练腹肌的。腰部应该贴近地面,而我做的时候老是直着腰,练完总腰疼。
  • 第三个,双腿伸直。哎,我还以甚至为自豪,但实际上,双腿应该屈膝。
  • 第四个是腿部固定,这个就真的是反常识了,虽然我平时都不固定,但原因是我们有人来给我按,而且我也以不固定脚为更有难度。
  • 第五个胸部贴近腿部,这个但不是什么大错,文章说没必要动作幅度这么大,而且这么大会有除腹肌意外的其他很多肌肉参与进来,腹肌参与反而少了。

这五个错误,我是都犯了,不过,想来,深层原因是对仰卧起坐的理解。我认为仰卧起坐就是练腰腹的。而这篇文章是说仰卧起坐只是练腹部的。不过说实话,我在做仰卧起坐的时候总是会用上全身的力气,所以才会肩膀到脖子处的肌肉疼,背疼,腰疼,我一直觉得,这没什么,这都是正常,现在我得持怀疑的态度了。
让我们科学健身,科学生活,科学工作——口号总得有的。

粘知了

今天又跟齐大爷去奥森逛圈去了,周末走走散散心挺好,不过占时间有点多,一下午,整整一下午。
当然,如果能为我的写作找点素材,那这事很值得的。
听到知了叫,齐大爷问小时候抓过知了没,我说没抓过,粘过,于是想起小时候粘知了的事儿。感觉还挺自豪,因为我觉得粘知了这是很有技术含量,对一个小学生来说。
粘知了,在于这个粘,你要知道,要想去抓树上的知了,用手的话,还是很难的,因为树上的很高呀,要想爬上去,太费劲了,而且等你爬上去它会趴在那不跑的吗?不会,它会吱一声,撒着尿飞跑的。这时候,你可以想一想,一只手抱着树,一只手抹抹脸,还闻一闻,有多么的狼狈啊!
所以,不知道从哪里我们学来了一个技术,就是粘知了,而关键是用什么粘,你想想吧,知了虽然那么小,但是力气可不小,拥有洪荒之里呀,你听它整天没命的知了知了就知道了。所以一般的粘性是不够的,我们当时用什么呢?面筋。应该是叫这个名称,真的是特别黏。
关键技术在做这个面筋上,怎么做?听我仔细说来。首先,先和一个面团子,要和得有点劲了,就是有点黏了,像蒸馒头包饺子的面那样,这时候能去粘知了吗?当然不行,粘性根本不够,不信你试试。
接下来才是关键,把和好的面团子,在水里洗,没听错,就是洗,不过这洗是需要技术的,不然很可能就洗没了,要来回的捏弄,最终,鹌鹑蛋大的一块面会被洗成花生豆那么大,粘度可是惊人的。
我们当年就用这技术逮了不少知了,然后喂猫了👽

技术文章略难写

一周即将过去
一篇文章未出
顿感心力憔悴
感慨技术文章真难写

我上周日就打算写一篇关于 java 的 nio 包下的 ByteBuffer 的文章,一周过去了,还没有写出来。实际上,在上次博客停更的时候就想写了,然而就这样拖到了现在,只在 Workflowy 上整理了部分知识点,文章却无法进行。
一开始,我想能大体全面的将主题讲清楚,因为我看阮一峰的博客,经常会有某个概念的全面描述,比如最近的一个介绍的 koa, 一个基于 node 的 web 开发框架,讲了一下特点,讲了一下基本的用法。感觉挺好。
我咋做的这么痛苦呢?
总结两点:

  1. 我根本对 ByteBuffer 不了解,甚至不知道它的正确的用法。
  2. 我又没有时间,专心的坐下来,一点一点深入

这可能有找理由的嫌疑,不过,我想说这只是分析原因,好吧,我必须给出解决方案,才不会感觉找理由:

  1. 周末必须出一篇技术文章,因为周末没时间的理由不成立。
  2. 工作日也是可以出一篇技术文章的,每天一点点,但是周末要找好技术点,并定好框架
  3. 其实这周又犯了一个低级错误,就是拿着没写出来的技术文章不肯写一写其他的,很正常的拖延套路。

周末见

ByteBuffer for OpenGL

我们在学习OpenGL时,用到了 ByteBuffer 往 OpenGL 传递数据,虽然这里用法很简单,但是ByteBuffer的用法还是很有意思的,所以打算好好研究一下它。但是限于篇幅,我们打算分几部分来说一说。
如果你只是学习OpenGL时感觉到困惑,那看这一篇就够了,如果你也同我一样对它产生兴趣,那就愉快的研究一下它吧。

nio 是什么

ByteBuffer 是 Java 自带 nio 包中的类,nio 包 是(new io)的意思,表示与之前的 io 不同。

nio 主要有三个核心概念: Buffer, Channel, Selector

与原来的 IO 相比,nio 包主要有一下几点不同:

  1. 面向缓冲,相比于原先的 IO 的流处理方式, 能够一下读一大块数据,并可以进行一个一个正题的操作。
  2. 非阻塞式,一个线程在进行读写操作时,还可以做其他事情。
  3. 一个线程,同时处理多个 IO,这整得益于前一个特性。

ByteBuffer 就是那个缓存,通过它,我们可以对需要读写的一块数据进行操作,这里的操作就是读写某一部分数据。
OpenGL 只使用了 nio 中的 Buffer。

OpenGL 中的栗子

我们在 OpenGL 的学习中,有几处用到了 Buffer,而实际上,真正算用到的地方,只有下面这一处,就是存储顶点数据的这个地方:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static final float[] VERTEX = {
0, 0f, 0.0f,
0.5f, 0f, 0f,
0.5f, 0.5f, 0f,

-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0f,
};
private FloatBuffer mVertexBuffer;

。。。

mVertexBuffer = ByteBuffer.allocateDirect(VERTEX.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(VERTEX);
mVertexBuffer.position(0);

自问自答

自问

我们以问题的形式来了解一下它。

  1. 为什么使用 ByteBuffer 分配对象,最后却变成了 FloatBuffer?
  2. 链式调用,我知道,可为什么断开了?

自答

  1. 第一个问题,原因就在 asFloatBuffer(),它将 ByteBuffer 变成了 FloatBuffer。可是为什么, 我臆测一下,我们分配的是一个 ByteBuffer 底层数据是byte,效率更高。但是 Byte 数据当做做 Float数据使用,每个数据的占的空间大小都不同,首先面临的一个问题就是大端,小端的问题,而这个问题使用 .order(ByteOrder.nativeOrder()) 解决了。在将它转变成 FloatBuffer 后, 最后才放入了 float 数组。

  2. 第二个问题的答案,其实了解链式调用了很简单,链式调用的原理是,在调用一个方法后,在执行完相应的操作后,将自己的对象返回了。这么说来上面的栗子的链式调用很不规范,因为它这个链在调用过程中类型都变了。而 position 之所以单独调用,是因为它返回的 Buffer 类型,而我们想要的是 FloatBuffer, 仅此而已。你可能会说,做个强制转型不就可以了———的确是,哈

总的来说,上面的语句的意思是 分配一个 ByteBuffer 对象,然后设置它为按照本地的顺序读写,然后把它编程 FloatBuffer,于是可以把 Float 数组的数据放进去。最后,最后把 position 设置为0。  

而之所以要设置 position, 着牵扯到 Buffer 的使用方法,它有个指针,指示当前的读写位置,而我们在调用 put 的时候,就是在对 Buffer 进行写操作,所以我们要对它初始化成0。而对于 Buffer 更深入的了解,请听下集分解。

我回来了

Hello,大家好,我回来了,不要害怕,我不是灰太狼,我是金国梁。
本来我想把题目叫做“有一个开始”的,但是发现竟然有一个了,可想而知,这“开始”是有多么多。

回顾总结

博客停止的原因

博客在4月份停止了,这次的原因,与之前的写着写着就不了了之相比,原因到很明确,不过还是很难启齿的。但是本着实事求是的态度,我还是将它公之于众,希望读者能从中悟出半点真知灼见。
事情是这样的,有一天,我写好了我的一片博客,但是是在写《OpenGL登堂入室之路》系列文章, 我在本地写好,并在本地使用 Jekyll 构建成功测试好,就 push 到 GitHub 了。然而,等我去 jinguoliang.gitHub.io 查看时,却没有更新,我以为是更新不及时,于是就等了一段时间,然而依然没有,我以为是 GitHub 服务器有问题,结果第二天,第三天,依然没有,然后就不了了之,哇,还是“不了了之”。

问题的解决过程

前段时间,小吴在自己服务器搭建了一个博客。我厚颜无耻的也要了一个窝,准备大干一场,可是为什么呢?我有我的博客,这里有我的历史,我可以继续书写它。
所以,我又回来,发现依然没更新,去 google 搜索“GitHub pages not 我在输入前面三个单词时,google 提示”GitHub pages not working”, 我一搜,发现了 Troubleshooting GitHub Pages builds, 在里面发现了查看 Pages 构建日志的方法,原来是我的 Pages 自从那次就没有编译过,我作为一个程序员,竟然没想到,的确是够难启齿的了。

总结

这个问题虽然难以启齿,但是还是有好的一面,就是我进步了。之前遇到问题,只是重复去试,根本没有想要解决问题,觉得在本地测试没问题,在 GitHub 上也应该没问题,如果有问题,那是它的问题,我也没办法。而现在,我学到一招,“如果我们在一个系统中,工作的不好,很有可能是我们的姿势不正确,没有利用好系统”。有了这种思想,我才有可能去 google 搜索,才能有效的解决问题。

计划

前面提到小吴建了个博客,他不仅建了个博客,而且坚持每天写作,说来有很难启齿,当时好像是我叫他来一块坚持写作的,结果,他坚持下来,一天不落,而我,三天大于两天晒网。不过说实话,我还是挺高兴的,因为这样也能一周两三篇呢,比起之前老重新开始,岂不是进步很大。
好,不扯淡了,我还是想坚持每天写作的,但是没有把它放到足够的重要地位,现在我的作息开始变好,早上的作息已经很完美了,这要归功于《Fabulous》,一款作息养成的 APP。现在正在开始调整晚上的,还是挺难的,虽然之前已经把睡眠时间卡死在最晚12点,然而,还是好难。
在接下来的日子里,我会尝试开始我的习作,暂定为晚上下班路上到睡觉前,总能有1个小时。一个小时其实真的不够。
我有,还应该进行全平台的发布,这是个问题,因为我是绝对不能忍受一个地方一个地方的发布的,所以需要一个脚本。
事情总是很多,而我们只能一步一步的走,而且还要蛋定从容的走,这没什么不好,至少不会寂寞,寂寞…


但行好事,莫问前程

整理生活 整理人生

从老长时间之前就下决心要整理房间,然而拖呀拖,几个月过去了,不过幸好,总算开始了,我先把自己的我是,厕所整理了一下,哇,感觉特别有成就感,心里也轻松了一点点。真的,就是这么神奇,就是感觉心里舒服了一些,虽然还有很多需要整理,但是至少一个好的开始就这样出现了。

先说说我的情况吧,对于整理有多么不懂,多么喜欢乱扔东西。

我的乱扔东西是从我老妈那继承来的,哎呀,这里我就批斗我自己就可以了,哈哈。实际上在很久之前就对整理有所关注,而且曾经还看过一本书《怦然心动的人生整理魔法》,写的真好,我当时收益匪浅。然而,并没有持续多久,我就忘掉了那些方法,现在都想不起都讲了什么了。(我得声明一下,那本书对我是有挺大的影响的,甚至比《代码大全》对我的影响都大,书中的一些精神溶解在了我的价值观之中,比如 “之所以乱,是因为有太多的没用的东西,而要整理,第一步就是扔掉没用的东西”)

我是有想整洁的想法的,但是为什么还是总弄乱,放乱东西呢?我对整理也思考过很多次,我试着总结一下我自己的原因:

  1. 尽管知道没用的东西要扔,但是却不能下定决心,这是从小养成的习惯,过日子的人,总舍不得扔,一些可能将来会用到的东西,或者,一些可能价格很贵的东西。
  2. 好像还有点收集癖,我非常相信我妈是有这个病,而我轻微有
  3. 乱放东西,这一点实际上是最严重的问题,尽管东西没有多余的,也会弄乱房间,我自我观察反思后,发现,有时候,大脑就是不会把注意力放在把东西物归原位,一般是在有很多事,有压力的时候,这时候,总会不经意的,自己甚至都不知道,随便找个地方,随手放下了。或者,注意到了,但是迫于压力,会跟自己说,暂时放着,然而就是因为暂时的乱放,久了,就乱的不行了。

整理房间跟整理代码,极为相似,反正,我在编程上悟出好多整理房间上的道理,比如以上的第三条,就是在编程工作中得出的结论。

好像混淆了整理,跟不乱放两个概念。整理是乱了,让乱变成不乱;而另一个概念应该叫保持整洁。笑来老师说了,概念要清晰。想想也是,这是两个概念,两个过程,分别有不同的方法和问题。

还好没放弃,所以借着这个良好的开始,都三本本书,重新学习整理术,先把房间整理干净,再把手机整理干净,最后心灵也跟着干净了

当一切都在该在的地方时,整个心灵都清净了。

推荐书

  1. 《怦然心动的人生整理魔法》
  2. 《断舍离》
  3. 《极简生活:简而美的活着》

我找了这三本书,第一本已经看过了,鉴于它对我的触动很大,所以需要再重读一遍,当然,它本身也是需要重读的书,还要记笔记,我也要借着这个机会实践一下深度阅读,记笔记。

OpenGL登堂入室之路5-画三个三角形

看到题目,你可能急了:“画三个三角形?这套路有完没完了?一个,两个,……”,我向大家保证,这套路就到这了,下一篇已经起好了名字:“完全控制颜色”

OpenGL 绘制图像时,并不是像我们自己素描一样,想画什么图形就画什么图形,OpenGL 里有图元的概念,带“元”的表示基本的,OpenGL里的复杂的图形,比如那些复杂的怪兽的模型,都是用一个个图元拼凑起来的。
OpenGL里的图元有:点,线,三角形,四边形,多边形。

我们学的是OpenGL ES,之前说过,它是阉割版的OpenGL, 阉割了哪呢?别想歪了,就是缩减了图元的种类:

  1. 点(GL_POINTS)
  2. 线 (GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES)
  3. 三角形 (GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES)

四边形跟多边形在OpenGL ES没有,因为三角形就可以组成 2D 和 3D 的任意图形了。

GL_POINTS 我们最开始就已经见识了,而且还发行,那个点竟然不是个圆点,而是一个方点,仔细想想,其实也没那么神奇,谁说方点不是点了呢?关键是它足够小,否则,像我们那样给他设置那么大的size,根本不像点。看这里

绘制线有三种方式:

  1. GL_LINES 绘制离散的线段
  2. GL_LINE_STRIP 绘制链接的线
  3. GL_LINE_LOOP 绘制闭环的线

动手去试试吧,你一定会惊讶这些概念原来这么容易理解,简单到不用学,动手作实验就能知道它们的区别。
(温馨提示:别忘把颜色着色器里的颜色修改成固定的颜色,更容易看效果)

绘制三角形也有三种方式:

  1. GL_TRIANGLES 绘制离散的三角形
  2. GL_TRIANGLE_STRIP
  3. GL_TRIANGLE_FAN

GL_TRIANGLES 同GL_LINES,动手试试吧。。。

要讲明白后两种方式,需要知道图形的正反面,而我们要的是有反馈的实验,要想能观察出效果,还需要贴图,牵扯的知识就多了,所以这里先提一提,挖个坑,以后把它填实。

代码嘛还是有的


参考:
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glDrawElements.xml

OpenGL登堂入室之路4-画三个点

我们画了一个点,两个点,接着画三个点,有些小伙伴可能想到要画三角形了,的确如此,而且是带颜色的三角形。

本文知识点:

  1. 画三角形
  2. 给每个点设置不同的颜色
  3. 初步了解GLSL,连个变量的两种修饰符

在开始之前,希望小伙伴,自己加上第三个点,我相信你能做到的。

好了吗?好,按找题目所表达的,今天完成任务了,小伙伴出去玩吧,哈哈

但是我们要画三角形呀,三角形呀

好,告诉你,只要修改一个地方,我觉的你也能猜到,不过我偏偏告诉你,就不给你留自己思考的时间。如下:

1
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 3);  

or

1
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 3);  

or:

1
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);

它们都是告诉OpenGL绘制三角形,只不过绘制方式有区别,具体什么区别,我们会在下一篇绘制多个三角形的时候研究,因为一个的时候看不出来。(一不小心下一预告就出来了)

画三角形,轻松愉快就完成了,三角赢得颜色是cyan,这个颜色我挺喜欢,最近才知道它原来是有,绿色和蓝色混合成的,而绿色和蓝色我都很喜欢,这叫什么呢?我们接下来要将给三个点设置不同的颜色了,在颜色着色器代码里,还记得吗?

1
2
3
4
private static final String FRAGMENT_SHADER = "precision mediump float;\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(1,0,1,1);\n"
+ "}";

在这里,vec4(1,0,1,1) 是一个四维向量,分别为argb, 着色器是对每个点都作相同的处理的程序,所以就不能分别给每个点设置不同的颜色了,那怎么办呢?
我们的顶点位置数据就是三个点分别设置的呀,对了,也要传进来
怎么传呢,照葫芦画瓢,但是这着色器语言实在是有点似曾相识又陌生,像C却不是C,不要着急,我们一点点的学习,立马学一点:

vec4(1,0,1,1) 是一个四维的向量,还有vec3(三维向量),vec2(二位向量)

我们看看顶点着色器:

1
"attribute vec4 vPosition;\n"

对应着,在OpenGL里是:

1
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

我们得到一个代表vPosition的东西mPositionHandle, 然后对它做出里,那是不是可以也声明一个类似的东西,在OpenGL取得它的代表,然后向它传递数据呢?当然是可以的。
我们先来看看那个声明语句,它是声明了一个变量vPosition,它的类型是vec4,这我们知道,为什么前面还有一个attribute, 看这个函数glGetAttribLocation,有Attrib,尽管它不完整,我们也知道它就是attribute。什么意思呢?
看这里:
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.20.pdf
全英文,那要不看这里:
https://my.oschina.net/sweetdark/blog/208024

attribute 修饰的变量,有三个特点

  1. 从OpenGL里传入
  2. 只读
  3. 只能在顶点着色器出现,颜色着色器里就不能声明了

第一点,我们见识了,第二点我们先记住啦,第三点好像打破了我们美好的愿望呀,我们想在颜色着色器里使用呀,怎么办呢?

还要引入另一个变量的修饰符 varying
varying 有两个特点:

  1. 在顶点着色器里可读写,在颜色着色器里只读
  2. 顶点着色器和颜色着色器,都声明相同名字的变量,从而可以将数据从顶点着色器传给颜色着色器

了解了这两个修饰符,上代码:

1
2
3
4
5
6
7
8
9
10
11
12
private static final String VERTEX_SHADER = "attribute vec4 vPosition;\n"
+ "varying vec4 vColor;\n"
+ "void main() {\n"
+ " vColor = vPosition;\n"
+ " gl_Position = vPosition;\n"
+ " gl_PointSize = 100.0;\n"
+ "}";
private static final String FRAGMENT_SHADER = "precision mediump float;\n"
+ "varying vec4 vColor;\n"
+ "void main() {\n"
+ " gl_FragColor = vColor;\n"
+ "}";

首先我们看到,两端代码里都有这一句:

1
varying vec3 vColor

对,它就是在两个着色器之间传递颜色数据的变量。

另外还有两句是赋值语句,我相信你会明白的, 这里我们为了简单起见,直接把顶点的坐标作为颜色数据,运行后你可以看到三角形三个顶点分别是,黑色(0,0,0),红色(0,0.5,0),黄色(0.5,0.5,0), 让人惊奇的是三角形竟然被填充了,三个点之间颜色渐变,还挺漂亮,是吧?这是OpenGL的特性,这里的原理嘛,是这样:

OpenGL在渲染三角形图像时,会作一步一步的处理,有好多步,我们现在只见识了顶点着色器和颜色着色器,它们都是这一步一步处理中要执行的。在像素化阶段,通常会生成比顶点更多的像素,每个像素就会挨个传递自己数据到顶点着色器,而它们的坐标是它们基于三角形中的位置的。不仅位置坐标基于像素在三角形中的位置,颜色也同样,比如我们有一个线段,A顶点的颜色为绿色,B顶点的颜色为红色,则在线段上距离A 20%的点的颜色值将会是80%的绿色,20%的红色

加餐:
我们这一次,修改了着色器语言,对它不熟悉,而且也没有ide提醒,所以很容易出错,而且呢,出错也没有log的,简直无从下手呀! 其实OpenGL提供了打印编译错误的:

1
2
3
4
5
6
7
GLES20.glLinkProgram(mProgram); 
IntBuffer result = IntBuffer.allocate(1);
GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, result);
Log.e(TAG, "loadProgram: " + result.get(0));
if (result.get(0) == 1) {
Log.e("glGetProgramInfoLog", GLES20.glGetProgramInfoLog(mProgram));
}

我们在glLinkProgram后,调用了glGetProgramiv,它会获取到着色器程序的编译状态,然后又用glGetProgramInfoLog,获取到了编译log,这样,我们就可以快乐的找错误了。
再多说一点,glGetProgramiv的第三个参数使用了IntBuffer,因为OpenGL低层是C++,按照它的风格,会把结果从参数返回来,我们适应一下吧。IntBuffer以后会讲到


好的,over