新博客地址

墙越来越高了,生活越来越不容易,我已经不打算继续用WordPress自己搭建blog了,接下来我的blog将会迁移到Github Pages,下面是blog的新地址

vincentdchan.github.io

新的blog主要讨论技术问题,生活上的问题以及各种naive的看法都不会再出现,当然可以fo我Twitter@cdzos97

新的blog里保留了这个blog里面的一些技术文章,算是我感觉写得还不错的文章都会保留下来,其他流水账日记都不保留了

一个月后,这个wp搭的blog将会消失,原有的地址将会重定向到新blog

用Python生成饼状旋转动画

在写一个小游戏过程中,打算做一个饼状旋转的动画,于是打算用Python来生成这个动画,假设我们有这样一张图片

最后生成的动画是这个样子的

当然,中间会生成很多帧的动画

怎么去生成每一帧动画呢?其实关键就在于挖去一个饼状图形里面的像素

那我们只要遍历这张图片的所有元素,然后挖去在这个饼状范围内的像素即可,从这个思路出发,我们可以很容易想到使用极坐标。假设我们有两条极坐标空间里面的直线p = Theta1p = Theta2那我们只要把这两条直线中间的像素挖掉即可。当我们遍历所有元素的时候,我们需要判断这个像素点在极坐标空间中的位置。当然,我们坐标的圆心是整个图片的中心,所以对于每个像素点,我们要减去整张图片中点坐标,求出的相对坐标再作atan2计算。

用math.atan2求出theta之后若在Theta1和Theta2之内,则删去即可,所以说核心代码其实很简单:

for x in range(SIZE[0]):
        for y in range(SIZE[1]):
            relative_point = (x - CENTER_POINT[0], y - CENTER_POINT[1])
            theta = math.atan2(relative_point[1], relative_point[0])
            theta = theta * 180 / math.pi + 180

            if theta >= theta1 and theta < theta2:
                draw = ImageDraw.Draw(img, 'RGBA')
                draw.point([x, y], (0, 0, 0, 0))    # write null pixel

最后附上源码Gist地址:
https://gist.github.com/ChannelOne/e120f3cacf88efbba3e51fa1b0084086

战狼2

我记得《战狼2》刚上映我就去看了,没想到现在这个话题这么火,而且战狼的票房似乎已经超越了《美人鱼》变成了华语最高?这个还没确认。

当时去电影院就抱着反正都没啥看随便挑一个的态度,在《战狼2》和《建军大业》之中选一坨屎来吃想法,却没想到《战狼2》最近几天一直都是人们热议的焦点,似乎不少键盘侠为此开战了。

有人赞吴京说,正确地把好莱坞电影的套路用在了中国电影上,问题是现在好莱坞的套路也像屎,也都已经没人愿意吃了,搬过来虽然说没错,但是似乎也不怎么对,不过也算是敢做,也勉强算是进步了吧。

不过,捧吴京怎么说也比捧那些小鲜肉的青春偶像古装强

暑假小总结

不知不觉暑假已经过了一半了,是时候做个小总结。

这个假期的大部分时间我都在学校的创客空间里面一家单位实习,这家单位是一家创业公司,老板是一个挺年轻的人,28岁左右,华师毕业,读的是工商管理好像。据传闻,是之前创业失败过,然后搬到华农里面来继续创业,而且还一直单身。

假期这个实习给我开的工资并不高,但是作为一名大二学生,能够靠自己本事找到一份职业相关的工作,我觉得还行,不算太差,我在学校实习的一个重要原因是可以住在学校,而离开家里面的各种烦心事。

我在公司里面负责的工作是前端开发,其实这种小公司的前端页面一般来说就是静态页面,写写HTML/CSS这种东西可以说丝毫没有难度。稍微有点难度的技术活就是做手机端的小游戏的时候可以用canvas来加点特技,这是我比较喜欢的地方,所以我接了两个小游戏的外包项目。我的工作也相当之轻松,工作之余可以和人聊聊天,下去买点东西吃,做做运动什么的都不是问题。

最难搞最难搞的东西呢就是客户,一般来说外包项目的流程就是甲方提需求,然后确定好需求之后就按需求做,最后测试交货,交货之后的bug都不管,加feature就得加钱,这是一般外包项目的流程。而我们的老板呢就比较怂,因为我们公司和甲方那家公司有四五个项目,不敢谈崩,所以甲方一直改需求,而最后遭殃的也就是程序员,所以我们员工对那家公司很大意见,但我个人觉得这个锅老板也是要背的,毕竟我觉得做老板做到这个地步也是挺失败的,虽然说甲方是上帝,但是无止境地改需求就应该怼回去。不过实话实说,现在国家大搞创业,家家创业,真正能赚钱的有几家。我老板也是毕业之后一直创业到现在,可是一直都没有出头的日子,本来自己有几个拿得出手的项目,可是到了社会就是要接受各种坑,收不到钱,最后沦落到要搞外包公司。

甲方那个公司我也有了解,就是一个皮包公司,招点销售人员,然后去技术公司(我们)买,订制软件来进行宣传和销售。这些人根本就不懂技术,也不尊重技术,口口声声见面就说辛苦了辛苦了,转头就把你当牛使。

这样做试试看吧?不行,哦那这样试试看?

还是不行,那不如这样吧

唉我还是觉得最初那个版本最好

对于这种人除了说操你妈我无fuck说。公司里有以为长做的员工因为客户这些狗屁需求改到凌晨五点才睡,而这帮人在干嘛。

前几天我们公司和他们公司员工聚餐,算是为了和解之前产生的不愉快,而看对面公司聚餐的过程仲,我又看到了那些腐朽的影子,他们公司的老板,讲情怀,讲理想,把业绩和个人荣誉,个人生活都捆绑在一起。我觉得这样很恶心,我从来都是按劳分配的坚定支持者,觉得做多少就应该拿多少,讲情怀有用,喝酒有用?所以这顿饭真的让我觉得对面老板的恶心,满满的套路。

我从来没想过在公司里面继续发展,因为我觉得这种公司迟早是倒闭的,不过作为一个暑假实习也不算太差,所以就暂时先做着。

什么是足够好的语言(一)

关于语言的争论一直是programmer的日常话题。写了这么久的代码,我也想说说我自己的想法,说说在我的心目中,什么才是足够好的语言。

为什么说C语言是一门足够好的语言

我认为C语言是一门足够好的语言,我这里所说的“足够好”是指C语言在它所在的领域做得足够好

C语言和硬件的关系非常紧密,也就是人们所说得“贴近硬件”,而这个贴近硬件我觉得更准确一点就是“贴近内存”,因为硬件又很多种,我认为编程者最直接打交道得就是内存,而C可以说是十分贴近内存的语言,这主要是因为C的指针可以直接操控内存。C语言的内存空间和变量的映射关系非常好,比如说struct,你struct怎么写,内存里面就是怎样,你用sizeof得到大小是多少,在内存里面就占多少空间,不多也不少。

C++的struct和class也能做到上面这一点,但是前提是你没有使用虚函数。C++的标准是没有规定虚表的实现的,也就是说各个编译器的实现不一样,虚表在内存中的表示就不一样。假设你要写需要精确内存分配的东西,比如操作系统,比如VM,那你就不能用虚表了,因为你总不想自己在写内存分配的同时,编译器偷偷帮你分配了一片区域。而当你发现你写一个C++的class却无法用虚表的时候,你会觉得很难受,还不如去用纯C

Java虽说也能估计内存的布局,但是因为Java大量使用指针,同时区分primitive type和object,所以当一个class写得很复杂的时候,就很难估计,而且也没这个必要。另一方面,这跟JVM的实现也有关系,当然会有工具去分析内存,但是从语言层面上来说,你是无法确保的。

我也可以说C语言是”面向内存编程“,另一方面也可以说是”面向字节编程“,那么其实C这个做法有什么好处呢,就是你涉及数据内存、字节操作的时候,C都能几乎完美地完成。比如说写一个文件,写一个socket,写一个数据库,你能精确的表示你要传输多少数据,你要储存多少数据,写一个操作系统的这些最基础的设施的时候,都十分地爽。这里就要吐槽一下Java,连个uint都不给我用,这要我说怎么好呢。

说到内存管理,一方面还是要数char这个神奇的东西,在C语言里面,char表示1byte,一般人用char[]来表示字符串,甚至抱怨char的不好用,因为不支持Unicode 上文说了,C是一种极度贴近硬件的语言,硬件才不管你是什么编码,硬件只知道你是bytes,所以无论传输、复制、储存,都要看作bytes来看,管你用Unicode\UTF-8\GBK呢。那有人说写VM和操作系统怎么办,我只能说你爱用啥用啥,反正最后你输出的时候搞对就行了。举个例子,你可以用int32_t或者int16_t来表示一个Unicode字符,在输出或者传输的时候再转成UTF-8,相反的,你也可以只存bytes,等用到的时候再转成相应的Unicode。

正因为C语言贴近内存,所以你才可以直接copy一块内存,对它做任何操作,而不用什么复制构造函数。但这不是没有代价的,代价就是你必须对每个struct了如指掌,对于逻辑简单,数据结构比较明显的情况下这没问题,所以对于大型系统,C语言并没有展现它本身的优势,对于那种逻辑系统,由很多模块组成,就是面向对象发挥优势的地方了,这里不详细说。

另一方面,C也可以精确地控制CPU,每一步执行了什么,基本上你都可以直接说出来。这方面C++就比较难做到了,特别是加上stl这种东西之后,也就是说除非你只用C++里面C的那部分,不然你很难做到精确控制CPU。也许你会跟我辩驳说stl如何强大,是的,我不否认stl的强大,但是如果你要精确控制内存和cpu,那么sorry你不能用stl。

还不够好

资源释放问题

C是直接控制资源的,那么这就涉及了资源的释放问题,我这里说的不是内存,而是文件,IO这种资源,这是我觉得这方面是C一个做得不够人性化的地方。

C可以直接操控硬件资源,意味着也要手动去回收资源,可是程序员总是会忘了回收的,或者没搞对回收的时机。在我看来,在语言引入一些机制来协助程序员管理资源和能够精确控制机器之间并没有冲突,举些例子:C++引入了RAII我觉得就是一个不错的解决方案,用对象的生命周期来表示资源的生命周期,另一方面Golang的defer也是一个不错的改进,同时defer关键字也没有引入更多的语义就解决了资源回收的问题。

要在编译器完成对程序逻辑的抽象,在C语言里面必须借助宏,可是要用宏就必须要明白宏只是一个lexical层面的生成器,不然就会产生误用。

我觉得要理解lexical作用不难,我觉得宏的问题主要还是在于不够强大,以及不够好看,你一个程序开头一大堆井号加一堆大写是几个意思,不把人绕晕?还有人喜欢用宏来搞面向对象,我觉得这又是何苦呢……

作为一种编译器语法上的抽象,能够称得上魔法的就要数C++的template了,我个人是挺欣赏C++的template的,一方面它是在编译期抽象语法,不用牺牲运行时的时间,另一方面语义非常强大,看看网上的人都用template来写Lisp了,这里就不一一列举了。

我认为宏是用来弥补C语法不够强大的方案,但是也不失为一种还不错的方案,能凑合着用,但还不够优雅。

命名空间

我觉得这是C语言让我崩溃的一个问题,没有module,没有pakcage,没有namespace,所有代码都是XX_XX_XX_XX,为了不让名字取太长,还采用各种缩写,写C程序这个问题简直要让我崩溃。

为什么C语言不是一门适合初学者的语言

过于贴近硬件

对于不熟悉计算机硬件的学生,就会对很多现象无法解释,包括一些高校的老师也解释不好一些硬件的问题。比如为什么会产生溢出,为什么要动态分配内存,为什么要malloc,什么是堆什么是栈。就拿下面这一段代码来说,初学者也许不清楚为什么行不通

int* some() {
    int a = 3
    return &a
}

这就是因为C语言和硬件联系很紧密,你要学懂C语言,你必须还得学懂计算机硬件,学懂C语言,这样你才能写出正确的C程序

平台相关的基本类型定义

作为一门贴近硬件的语言,C语言对类型的定义非常取决于编译器和平台。试问一下,谁能背出int, long, float, double在32位和64位的Linux和Windows下分别是多少位的?

没有内置的字符串类型

对于初学者来说,能干点什么是很重要的,像C这样的字符串,是很消耗别人耐性的

隐式类型变换

对于int,float等类型的隐式变换对于初学者来说是非常不友好的。因为初学者不明白为什么1 / 31 / 3.0 之间到底又什么不同,为什么他们的结果会不一样。

总结

C语言适合写需要精确控制CPU和内存小模块,小工具。其实很多现代语言的语法C都没有,已经很难被用来写点什么了,即使要写一个VM或者操作系统,估计我也不会用纯C,感觉写完了整篇post感觉自己在写C还是不够好,不过anyway啦,表达一下我对一门语言的看法。

险过科目二——想法和吐槽

我想多年以后的某个晚上,我还会想到自己被科目二支配的恐惧。

第一次考科目二已经是一个月前了,那时候学了几天兴致冲冲的就去考了,倒不是我想这样,而是事实让我很无奈。首先教练不愿意多教,也不愿意让你多练,按照教练的说法是“不需要练太多,练得多错得多”,马马虎虎地考就过了。然而实际上教练哪管你死活,你不过教补考费再练再考就是了,至于你的时间你的钱,who care?然而我觉得更加实在的一个问题是教练想省油费,还有要照顾那辆破得不行的教练车。

这就形成了教练和学员间的矛盾,学费都是那点钱,但是学费只是让他教你,让你学会,而你中间的什么细节,要考都少次才过,他都不管的。对于学员个体来说,当然我想越早过越好,因为实在太耗我时间了

然而我想了很久,觉得驾校这种做法,其实是有一定道理,把一个学员从完全不会教到马马虎虎,只需要一点时间,两三天,把完全不会的学员教到很好的水准,可能要两三周,甚至一个月。而水平马马虎虎的学员通过率可能是50%,而一个很好的学员,通过率也只不过是80%,因为考场可能会出现各种各样的情况,比如考试紧张什么的,但是练的时间就会大大增加。所以,把所有学员教到马马虎虎的水平,是最划算的。如果你不是那些一开始那50%,你还得回去练车,你回去练车他也只是给你练一周差不多,多的话都会赶你走,多练一周后,可能你的通过率到了70%-80%了,一般来说第二次都能过。稍微对比一下:

把所有学员随便教点就去考试的通过率,简化一下模型,假设第一次之后,每学一周,通过率提高20%,以10%递减:

第一次考试学员通过率 50%,总通过率 50% 一周
第二次 50% *70% = 35%,总通过率 85% 两周
第三次 15% * 80% = 12%,总通过率 97% 三周

假设把学员教得很6才去考试:

第一次考试学员通过率 70% 总通过率 70% 两周
第二次考试学员通过率 30% * 80 % = 24%, 总通过率 94% 四周

可以这么说,B驾校考2次就可以全过了,A驾校要考3次。如此看来,其实第一种做法很精明,可以让一些掌握比较好或者运气比较好的学员快速通过,其实对于学员来说,练的总时长其实还是比第二种短的,因为第二种来说,学员容易隔很长时间才去练导致学过的知识忘了,第一种就有点类似“快速迭代”的思想,也就是说第一种做法的迭代次数更多。对于驾校来讲,第一种做法是要划算些,因为补考费是学员交的,也就是说增加考试次数对驾校来说是不会增加成本的,反而可以加快学员通过的时间,但是对学员个体来说,或许会让学员的心灵受伤(比如我),还有钱包受伤(比如我)。而且这种做法给学员的感觉容易是驾校教得不好,你看上图,有50%在第一次通过了,剩下的学员当中,35%在第二次考才通过。和B驾校的学员一比,卧槽70%学员第一次就过了,好厉害,对比起来A驾校就很渣了,所以说A这种做法让学员体验很不好。

最后,欢迎指正。

吐槽

考科目二的过程中,各种潜规则就不吐槽了,现在电子监考已经比原来好很多了,听别人讲以前的故事才叫精彩。练车过程中,最为尴尬的过程就是和教练聊天的过程,教练都是没文化的,讲的东西极度反智,什么“吸烟有助身体健康”之类的,有时候也不好意思反驳,只好跟着呵呵,大家学员一起聊天,总有一种“尬聊”的味道。


还有就是极度嚣张的引考员,虽然说引考员这个职务,可能因为每天要对各种各样的奇葩而有点不耐烦,但是他妈也太嚣张了。


不开空调,热成狗,还多蚊子,导致极度不想去练车

HTML Canvas实现《黑客帝国》数字雨

《黑客帝国》是我最喜欢的电影之一,我感觉《黑客帝国》里面的数字雨简直是一种艺术,非常好看,看上去非常高大上,而且和“雨”这种东西结合,非常有意思,于是想自己实现一下。

效果图:

在Canvas里面实现动画的思路其实很简单,在很短的时间里面刷新一次就行了。每次刷新的时候,字符都会下降,然而数字雨里面并不是整串“雨”往下移动一个单位,而是这个雨的最下端,显示了一个新的字符。

所以我们不妨换个思路,就是其实每个字符的位置其实是固定,每次刷新的不是每个字符的位置,而是刷新他们的颜色,让一个字符的颜色从最绿慢慢变黑,然后又变最绿,然后慢慢变黑……周而复始。最后把每个字符用Canvas在对应的坐标画出来就行了。

当然这当中有先后顺序,一列里面,第n个字符的颜色应该刚好比第n-1个字符少一个梯度,也就是说

第i秒的时候:
    第N个字符的颜色为 A
        第N-1字符的颜色为 A -1

第i+1秒的时候
        第N个字符的颜色为A-1
        第N-1个字符的颜色为A-2

当然了,为了要让每一条雨条下落的先后顺序不一样,必须给它们的颜色加一个随机的偏移量,然后取模,这样就会有先后落下的效果。

最后附上源码,需要用Babel编译一下

Github gist 源代码

关于人工智能和音乐创作的讨论

今天和一位很好的朋友讨论了人工智能创作音乐的可能性。其实现在人工智能已经不断开始创作音乐了,网上也流传了不少,比如一个Google的简单音阶的音乐,我之所以讨论这个话题是因为我看到了一个Sony人工智能创作出模仿The Beatles的音乐的作品。下面是我和我的这位也在读CS朋友的讨论,讲出了我们对音乐、艺术和人工智能的拙略的见解。

我:我觉得机器可能会比人类更了解自己。比如现在深度学习已经可以通过学习图片来清晰化图片,未来人工智能作画也不是不可能。不是我鼓吹人工智能,我觉得有生之年可以看到一大波人被取代。比如你喜欢古典贝多芬柴可夫斯基,他们挂了,以后人工智能就可以学习他们的曲目,再创作,让你无法分辨,让你觉得这就是贝多芬。而且机器不会局限于自己无法创作于新风格,机器运算比人快得多,它可以按照固定模式大量进行创作,总有你喜欢的新风格,然后再按你喜欢的方向继续学习,创作。

麦:不错,我现在在看一部讲座,讲的就是作曲与语言学的关系。我发现作曲家在作曲的时候的确是有很多规则可循,比如和声的法则,机器做这个一点不难,但是这样你觉得艺术的意义何在?我们欣赏音乐,尤其是古典音乐,更多的不仅实在旋律和乐器本身,而是背后作曲家想要表达什么,曲子做出来肯定是有目的的,机器可能能作出旋律很动人的乐曲,但是我觉得背后没有任何意义,尤其是古典音乐,这么多乐器,比如说我拿长笛描写小溪,小提琴声部描写江河,圆号描写冲锋的士兵。。。很多很多,这些是根据作曲家本身的意愿和理解加上乐器的特点决定的。机器要做这些,他要描写什么?
而且在古典音乐里,还有个再创作的问题,你听到的版本,是指挥家和演奏家自己的版本,不同人不一样,这个就完全无规律可言了。当然,有些作品可能可以由机器来作,比如我之前给你推荐的哥德堡变奏,巴赫作这个的目的是给一个睡不着的人催眠用的,本身就没什么特别的意思,虽然技巧纷繁复杂,配合很巧妙。当然自不自然是个问题,我们这种外行的我觉得还是把作曲尤其是古典音乐作曲想简单了。

我:首先,音乐的表达肯定是有目的,比如用来表达喜怒哀乐,可是喜怒哀乐的表达也是有一定套路而言的,先不说古典,我不懂,就说流行吧,比如说高兴的曲子速度快点,大调和弦,怨曲blues喜欢用快速的颤音,还有小提琴的颤音来表达幽怨,愤怒的重金属大把套路,首先是重金属和弦,其次很重要的它的贝司和效果器,都是可以组合的。也就是我可能只要告诉机器,我要一首重金属,有多重,机器可以给你合成出来,给你合成一百首,一千首都行,然后你可以挑选出你喜欢的,然后机器再学习,再合成,重复迭代。比如甚至可以根据你给的关键字进行,合成,比如高山流水,只要有大量的高山流水的曲目,学习它的pattern,在不断反馈,肯定能够产生出让你觉得这是在描写高山流水的歌。比如你说的,用长笛描写什么,小提琴描写什么,那可能以后只要你跟机器说我要一首描写什么什么什么的歌曲,机器就会自动的用长笛、小提琴去合成。
作曲家做什么,和弦是什么,这个我专门去了解了一下,和弦的音阶在震动的频率上有巧妙的关系,不知道你知不知道这一点。震动频率倍数为有理数的音阶,比如说震动频率为v, 1/2 v 1/4 v的三个音阶可以组成一个和弦,大脑同时接受这三个音,会觉得悦耳,为什么?因为大脑可以识别,他们的关系简单。大脑是什么?也就是一个可以学习的模式匹配器啊。而简单的倍数关系,比如1,2,4 1,4,8 这些简单的和弦早已被用烂了,而音乐家总是可以发现一些新的音阶组合,是因为他们的大脑足够灵敏,对一些倍数关系比较大的音阶也觉得悦耳,比如1, 24, 48。而计算机有一个好处,就是可以大量快速的计算,有理数组合的音阶虽然有无穷多,但是普通人觉得悦耳的其实也就是我们平时听的几个和弦,这时,难道计算机不就可以快速的给我们发掘新的好听的和弦吗?就算你说的,毫无规律可言的歌曲,计算机照样能够创作出来。
神经网络发展到今天,已经不只是只会识别套路了。虽然说人脑科学只要一天不突破,人工智能就无法真正模拟大脑,但是能做的东西已经远超过人的想象,因为人脑也是神经网络。

麦:我知道一点,这个在和声里也有体现。你说的一点不错,有些东西机器学习可以做到,但归根结底还是缺少“人”的东西。就像你刚刚说的高山流水,我写的是珠江还是东濠涌?假如是珠江,是什么时候的珠江?我路过的时候心情是什么样的?这些很多因素影响下我作出来的东西就完全不一样,而且后人解读我写的这些东西又千差万别。机器思考出来的东西和人思考出来的东西是一样的吗?后面我很赞同,创造出来好听的和弦我认为完全没有任何问题,但这是不是仅仅停留在好听的层面上?我的观点是,艺术是不能脱离人而存在的,这点不仅仅在于作品是人作的这一个已经不是事实的事实,而在于艺术本身。我们解读,欣赏艺术作品实际上就是在解读,欣赏一个人不是吗?

我:我觉得是不是有点本末倒置呢?比如说人不是通过人去欣赏作品的啊。比如人们不是因为要欣赏理解李白才去读床前明月光。而是人们读了窗前明月光……低头思故乡,很有共鸣,才去了解李白的。你是因为觉得啊原来明月和故乡可以这么写,才去通过这个去解读李白。那你凭什么觉得机器不能创作珠江,然后你才觉得啊原来珠江可以这么写?人的创作很有局限性,可是机器没有啊。
不同的人解读确实很不同,比如我让机器产生了一段你说的“很动听旋律但是没有内涵”的音乐,让某些人去听,他们说不定也能觉得很有内涵不是吗?然后你在告诉他,这首曲是给我的程序设计了这些这些参数而合成出来的,那岂不是让人更能了解自己的内心?
发掘新的 音乐模式->情感 的映射也可以通过机器去完成啊。而且已经有机器学习用上了人类的心理学模型了哦。

麦:有道理,虽然有点不服气,但是觉得没有办法反驳你。我觉得,即使刚才你说的都做到了,只有到了机器自己觉得自己要创作而且知道自己想要创作什么,创作的对象是什么,这样人在艺术史上的地位才会发生变化吧,不然也只是创作的工具。但这时候机器已经完全有了人的全部特性了。

我:那是,只能说以后很可能是人和机器配合作曲编曲,靠机器独立还是不可能。而且机器目前还无法弹奏,还是要人类弹奏,人类弹奏又会融入自己的情感。但是我觉得音乐的格局会因此大很多,特别是流行音乐。

谈论到此就结束了,我重新看回自己的言论,觉得我还是把神经网络和人工智能的作用夸大了,实际上我现在觉得人工智能的能力可能还没能到达我说的那个地步,但是我觉得是可行的,毕竟以后的事情谁也不知道。Alpha Go之后,期待人工智能在各方面仍然能够有更大突破吧。希望各位有看法的留言说一下。

写一个光线追踪渲染器

最近都在做一件事情,做一个光线追踪渲染器,一直很想揭开光线追踪渲染器的大门,于是跟着Milo Yip的步伐开撸了

用JavaScript玩转计算机图形学(一)光线追踪入门

渲染结果图:
file.png

其实制作的过程是非常坎坷的,我首先用C#按照博文的思路重写了一边,渲染出结果(1024×1024),总共耗时6秒,结果令人很不满意,觉得有点慢,于是打算用C++重新实现一遍,使用MSVC编译器,第一次做出来的结果是2.1s,比C#快一点,但是优势还不是很明显。但是我做了如下改动之后,性能得到了极大的提升:

本来的写法:

std::shared_ptr<Result> function()
{
    if (do_something()) return std::make_share<Result>();
    else return null;
}

改为:

bool function(Result& result)
{
    if (do_something()) 
    {
        result = xxx;
        return true;
    }
    else return false
}

经过这一改动之后,渲染实践从原来的2.1秒瞬间缩短到了0.6s,有点令人不可思议,个人猜测是shared_ptr进行频繁的分配和释放空间导致的速度大幅度变慢。0.6s的渲染时间让我觉得很满意,本来想继续做下一步实验,但是不知道怎么的,我总是觉得程序还能优化。于是我看了看Profile,没发现什么问题,我觉得该改的都改了,再改可能也得不到大幅度的提升,后来我往另一个方面想:多线程

光线追踪算法每个像素的计算之间没有任何关系,这意味着,可以同时进行计算,然后最后把结果合并,pbrt也讲了这种思想,于是我也试试。一开始我使用了Windows的API,可是我没有什么Windows的编程经验,Win32的API都是现查现用,于是出现了一个我解决不了的问题,就是我用WaitForMultipleObjects函数去等待子线程结束,调度线程才结束,可是每次调度线程自己先结束了,WaitForMultipleObjects函数没起到作用,我检查了结果,在正确范围内,也没发现问题,但是就是不行,没办法解决。

后来采用boost的thread框架,成功地使用了join,调度程序等所有渲染都完成了才结束,由于我使用的电脑的CPU是i5-5200U,双核四线程,所以我开了四线程,进行渲染,总共耗时0.3s,速度可以说是加快了许多,我尝试开八线程进行渲染,也是0.3s,速度没有得到提升,说明四线程在我的电脑上应该是最合适的。

多线程的问题解决了,然后就可以进行下一步的实验了。

用JavaFX写界面

最近要完成一门面向对象程序设计的作业,因为队友只会Java,所以,也就用Java写了。
既然用Java,那么界面当然就是用JavaFX写的,难道还会用Swing吗?

Github地址

main.png

说实话,网上对于JavaFX的资源实在不多,说实话,现在GUI的框架都那么多了,JavaFX的吸引力确实不够。

我发现JavaFX是想做到像WPF那用实现内容和试图进行绑定,但是JavaFX和WPF的模型和试图分离不同,JavaFX的控件把模型写到控件里面去了,每个控件都有不同的property,可以绑定各种数据,也可以监视数据的变动。其实我一直不太理解JavaFX为什么要这么做,似乎不太直观,似乎是以View层为主导来编写界面。

而WPF的模型都实现成了Observable,这一点上比较麻烦,但是WPF的绑定非常直观,很好理解。这一点上算是两个的不同之处吧。

JavaFX总体实现下来也不算太啰嗦,应该说在Java这门语言下,JavaFX还是实现得不错的,Java本身的啰嗦就是太依赖面向对象了,要知道面向对象不是银弹,有些事情用面向对象很好解决,但是有些事情面向对象并没有什么帮助。应该说Java8的lambda表达式提供的很大的方便,但是相比C#的语法糖,实在是相形见绌。

下面列一些JavaFX的好处和坑吧

Pros

  • 自带Webkit引擎,也就是说如果你想Hybrid是不用加什么别的插件的,直接上WebView
  • Java跨平台,这个没什么好说,虽说坑比较多,但是个人觉得做得还行
  • 可用FXML定义界面,但是不如WPF的XAML灵活
  • 可用CSS定义样式

Cons

  • Java语法啰嗦
  • 自带的控件不够多
  • 默认样式不够漂亮,属于”经典风格“,但是也算是有所改良