2012年12月26日星期三

阮一峰的网络日志

阮一峰的网络日志


纪录片《Minecraft:Mojang的故事》

Posted: 25 Dec 2012 08:11 AM PST

2009年,30岁的瑞典程序员Markus Persson写了一个小游戏Minecraft

这个游戏模拟了一个虚拟世界,玩家可以在里面无尽地漫游。

你看到各种别人建造的地标,也可以自己动手,随心所欲地建造自己的地标。

这个游戏大获成功,很多人试玩后都想购买。2010年9月,Markus Persson决定辞职,与朋友合资成立Mojang(瑞典语"组件"的意思)游戏公司,专职开发Minecraft。

看到这里,你可能以为,这篇文章讲的是Minecraft的故事。不是的,我其实要讲的是另一个故事。

早在2005年,美国波特兰有三个爱打游戏的年轻人。他们成立了一家名为2 Player Productions(简称2PP)的制片工作室,专门拍摄电子游戏的制作过程。

三个成员平时都有自己的工作,只有确定题材以后,才会凑时间动工拍摄,平均每年生产一部作品。当他们看到Mojang成立的消息,意识到这可能是一个重大事件,决定跟拍Mojang的第一年。可是,他们没钱,必须找到愿意资助这个项目的人。

2011年2月21日,他们把这个项目放上了融资网站Kickstarter,附上一段20分钟的试拍样片,恳求资助。《项目介绍》这样写道:

"本片将第一次深入展示,一家游戏软件公司在成立后第一年遭遇的挑战和取得的成绩。我们将分析Minecraft史无前例的成功,采访新闻记者和行业专家,访问游戏玩家。

您的资助将帮助我们前往瑞典和别的地方,使我们可以雇佣人手,制作特效,聘请原创配乐。"

资助者获得的回报如下:

捐款金额 回报
1到14美元 数码纪念品一份,记录制作过程的blog的阅读密码。
15到29美元 影片的数码音轨,名字出现在片尾的致谢。
30到59美元 DVD套装,数码音轨,名字出现在片尾的致谢。
60到99美元 签名版DVD套装,配乐CD(以及非发售的隐藏音轨),定制的小玩具,名字出现在片尾致谢。
100到249美元 本片的大幅精美海报一张,签名版DVD套装,定制的小玩具,名字出现在片尾致谢。
250到349美元 本片的大幅精美海报一张,上面有Markus Persson的签名和限量版编号,配乐CD,定制的小玩具,名字出现在片尾的致谢。
350到499美元 片尾将展示您创造的地标(长度不超过15秒),Markus Persson签名的大幅精美海报一张,DVD签名套装,配乐CD,定制的小玩具,名字出现在片尾的致谢。
500到2499美元 Minecraft高级纪念品一份,Markus Persson签名的大幅精美海报一张,DVD签名套装,配乐CD,定制的小玩具,名字出现在片尾的致谢。
2500到9999美元 仿真的Minecraft斧子一把,高级纪念品一份,Markus Persson签名的大幅精美海报一张,DVD签名套装,配乐CD,定制的小玩具,名字出现在片尾的致谢。
10000美元及以上 您的名字将被列为"执行制片",进入IMDB数据库,您还获邀来到斯德哥尔摩,与Mojang团队共度一天(机票和食宿自理),以及前述的所有东西。

原计划是4星期筹集15万美元,结果反响热烈超乎想象。2011年3月26日截止时,一共有3631人捐款,总金额21万297美元。捐款人数排在Kickstarter有史以来第三位。

有了这笔钱,2PP终于可以去瑞典拍摄Mojang的第一年了。事实证明,这是一个正确决定。在这一年里,Mojang取得了巨大成功,注册玩家达到1600万,游戏拷贝卖出了400万份。这是值得研究和纪念的一年。外界好奇地等待着这部纪录片,想看看这些成绩是如何取得的。

可是,2PP一直拖到三天前(2012年12月22日)才宣布正式上市:DVD套装定价20美元,视频文件下载定价8美元,音轨定价7美元。

令人震惊的是,第二天(12月23日)2PP就把这部电影放上了全世界最大的文件分享网站"海盗湾",允许免费下载。说明档是这样写的:

"我们是这部纪录片的拍摄者,希望也是它的第一个上传者。因为我们知道,它迟早会被人放到这里,那还不如我们自己来放,希望你们能够看完下面的话。

盗版是一种生活方式,虽然无法在短期内得到推广,还可能受到惩罚,但是我们的态度比较现实。

我们都看过盗版电影,有时也确实需要盗版。比如,你可能没钱买DVD,也可能想在购买前试看一下,或者因为对我们的一些做法不满,盗版表示抗议。这些理由都很好。但是如果你盗版只是为了获取视频文件,那么请考虑购买我们的无DRM的版本,下载后可用任何方式观看。

我们只是三个想靠自己的兴趣爱好谋生的年轻人。我们热爱电子游戏,我们渴望让电子游戏变得更真实。如果你购买我们的影片,就是在支持我们的努力。我们之所以把这部影片放到Kickstarter筹款,就是因为我们的钱不够。即使筹款成功,它还是花掉了很大很大一笔我们自己的钱,更不要提我们投入的这两年的劳动了。

请观看这部影片,希望你喜欢它,理解我们想做的事情。请考虑支持我们,购买8美元的下载版或者20美元的DVD。

我们感到很幸运,能与电子游戏行业许多杰出人物共事,拍出我们想拍的电影。请让我们继续走在这条路上,让我们拍出更好的作品。"

下面就是海盗湾的磁力链接,你可以用它下载全片。在这之前,你不妨先看看2分钟预告片:Youtube / Youku

magnet:?xt=urn:btih:41b2fd2403eba5a1dc23743fb08a15f968ac c1b5&dn=Minecraft%3A+The+Story+of+Mojang&tr=udp% 3A%2F%2Ftracker.openbittorrent.com%3A80&tr=udp%3A%2F %2Ftracker.publicbt.com%3A80&tr=udp%3A%2F%2Ftracker. istole.it%3A6969&tr=udp%3A%2F%2Ftracker.ccc.de%3A80

你下载下来的,是一个2.52GB的MOV高清文件。这是一个盗版,但是它的提供者就是版权所有人。

我觉得,这个事件很有启发。它提供了一个案例,让我们思考在互联网时代,内容提供商如何生存、如何应对盗版。

我从来不相信,强调版权保护、应用各种防盗版措施(比如DRM)是解决之道,但是确实不知道路在何方。在这方面,2PP采用网络融资、自己推动自己的盗版(gangnam style不也是这样吗),这些做法具有探索意义,令人耳目一新,而且具有可操作性,完全可以被其他项目仿效和借鉴。

(完)

文档信息

2012年12月21日星期五

阮一峰的网络日志

阮一峰的网络日志


Javascript异步编程的4种方法

Posted: 21 Dec 2012 12:27 AM PST

你可能知道,Javascript语言的执行环境是"单线程"(single thread)。

所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。

这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。

"同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

"异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。

本文总结了"异步模式"编程的4种方法,理解它们可以让你写出结构更合理、性能更出色、维护更方便的Javascript程序。

一、回调函数

这是异步编程最基本的方法。

假定有两个函数f1和f2,后者等待前者的执行结果。

  f1();

  f2();

如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。

  function f1(callback){

    setTimeout(function () {

      // f1的任务代码

      callback();

    }, 1000);

  }

执行代码就变成下面这样:

  f1(f2);

采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。

回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。

二、事件监听

另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

还是以f1和f2为例。首先,为f1绑定一个事件(这里采用的jQuery的写法)。

  f1.on('done', f2);

上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:

  function f1(){

    setTimeout(function () {

      // f1的任务代码

      f1.trigger('done');

    }, 1000);

  }

f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2。

这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。

三、发布/订阅

上一节的"事件",完全可以理解成"信号"。

我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。

这个模式有多种实现,下面采用的是Ben Alman的Tiny Pub/Sub,这是jQuery的一个插件。

首先,f2向"信号中心"jQuery订阅"done"信号。

  jQuery.subscribe("done", f2);

然后,f1进行如下改写:

  function f1(){

    setTimeout(function () {

      // f1的任务代码

      jQuery.publish("done");

    }, 1000);

  }

jQuery.publish("done")的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。

此外,f2完成执行后,也可以取消订阅(unsubscribe)。

  jQuery.unsubscribe("done", f2);

这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

四、Promises对象

Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口

简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:

  f1().then(f2);

f1要进行如下改写(这里使用的是jQuery的实现):

  function f1(){

    var dfd = $.Deferred();

    setTimeout(function () {

      // f1的任务代码

      dfd.resolve();

    }, 500);

    return dfd.promise;

  }

这样写的优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。

比如,指定多个回调函数:

  f1().then(f2).then(f3);

再比如,指定发生错误时的回调函数:

  f1().then(f2).fail(f3);

而且,它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。

五、参考链接

  * Asynchronous JS: Callbacks, Listeners, Control Flow Libs and Promises

(完)

文档信息

2012年12月14日星期五

阮一峰的网络日志

阮一峰的网络日志


奥巴马筹款网站的制作过程

Posted: 14 Dec 2012 12:19 AM PST

1.

Kyle Rush是一个网站工程师。

2011年6月,他加入BarackObama.com,负责设计2012美国大选的奥巴马官网。

(图为2011年6月的奥巴马官网)

除了宣传,官网的主要目的就是筹款。

上一次大选,奥巴马筹到了6.9亿美元。这是一个很大的数字,但由于过去4年美国经济一直没有起色,本次大选势必要投入更多的资金,团队内部估计资金需求将达到创纪录的10亿美元。

一个筹集10亿美元的网站,历史上从来没有过。Kyle Rush不知道自己能否做到,但是他很清楚,如果筹不到钱,奥巴马没法赢得大选。

2.

2012年美国大选现在已经结束了,奥巴马有惊无险地击败了罗姆尼。他最终筹到了11亿美元,成为历史上筹款金额最高(也是花钱最多)的总统候选人。(排在第二位的就是罗姆尼,他也筹到了10亿美元。)

这11亿美元之中,线下筹集了4.1亿,线上筹集了6.9亿。单单BarackObama.com一个网站,就创造了2.5亿美元的捐款。

在6个月的时间里,BarackObama.com共有

  * 17,807,917个访问者,81,548,259次页面访问

  * 4,276,463次捐款

  * 捐款转化率24%(每四个访问者,就有一人会捐款)

这样辉煌的成绩,是如何取得的?

3.

制作一个超大流量的、体验良好的、能够说服人们捐款、并能安全快速处理这些捐款的网站、绝非易事。

最近,Kyle Rush写了一篇文章,披露了许多内幕,从技术角度总结了BarackObama.com的制作心得。下面,我们就来看看奥巴马的技术团队是怎么做到的。

(图为2012年5月的奥巴马官网)

网站的制作班子,从2011年下半开始组建,Kyle Rush是第一个加入的前端工程师,负责网页的外观和用户体验。

一开始,网站放在团队自购的服务器上,运行和捐款都还算平稳。但是,随着竞争不断加剧,局势变得令人担忧了。到了2012年5月,罗姆尼当月的筹款金额第一次超过了奥巴马。

竞选总部决定,网站必须改版,尽一切可能争取捐款。于是,技术团队开始大规模的扩充,全职的前端工程师从1个人扩充到了14个人,其中6人专门负责制作筹款页面。

4.

技术团队做出的第一个决定是,使用静态网站生成器Jekyll,用静态网页取代动态网页,加快网页打开速度。网站的打开应该越快越好。有研究称,打开速度每慢100毫秒,Amazon的销售额就下降1%。

第二个决定是,将全部网页放上CDN,使用的服务商是Akamai。它是世界最大的CDN供应商,共部署了50000多台服务器,美国各地都能获得理想的访问速度。奥巴马芝加哥竞选总部,可以在20毫秒内载入官网的HTML网页。

第三个决定是,将捐款的后台做成API调用。这是因为有23%的访问者使用移动设备,所以必须部署多个前端(Web端和移动端)。使用API,可以让不同前端以相同方式与后台通信,彼此之间用JSON格式传递信息。

第四个决定是,后台用PHP语言开发,放在Amazon的EC2平台上。

第五个决定是,为了避免宕机,开发两个后台。一旦一个系统停止工作,立刻自动切换到另一个。这点很重要,因为宕机不仅影响士气,而且经济损失巨大。因为捐款每分钟都在涌入,最高记录是一小时300万美元,你不能让它停下来。

5.

新网站初步完成后,使用webpagetest.org进行测试,结果令人鼓舞。

原版页面4秒钟后还没载入,新版只用1秒就可以看到。整个平台的访问速度上升了60%,捐款转化率增加了14%。

接下来,就是微调页面的各种细节,一共进行了240次a/b测试,也就是说,至少迭代了240个版本。

调整后的页面,视觉效果和用户体验都有了巨大的提升(点击看大图),捐款转化率因此又提高了49%。。

随着奥巴马的当选,BarackObama.com共进行了1101次前端部署。

6.

事实证明,整个开发方案非常成功,顺利完成筹款任务,没有一分钟宕机。

Kyle Rush感到有必要总结,留下记录。除了上面的开发过程,他还提到前端团队使用的工具:版本控制Github ,a/b测试管理Optimizely,代码编译CodeKit

Kyle Rush最后总结说:

"我百分之百肯定,这是我经历过的最好的开发环境。我们不断调整,捐款转化率的提高令人难以置信。整个团队感到无比满足。但是,最高兴的还是看到,2013年1月21日巴拉克·奥巴马依然是美国总统!"

(完)

文档信息

2012年12月6日星期四

阮一峰的网络日志

阮一峰的网络日志


为什么数码相机可以拍出彩色照片?

Posted: 05 Dec 2012 11:24 PM PST

上个月(11月13日),83岁的柯达公司退休工程师布赖斯·拜尔(Bryce Bayer)去世。

一家国内杂志邀请我写纪念文章,回顾他对数码摄影的巨大贡献。

我看了一些材料,觉得这个题材很有意思,涉及数码相机的成像原理,使我对数字图像技术有了新的认识。但是,由于体例限制,杂志不允许我插入彩图。

下面,我把我的那篇文章配上图片,解释彩色数码照片是怎么拍出来的。

1.

为了更好地理解原理,让我们从照片的起源讲起。1825年,法国人涅普斯(Joseph Nicéphore Nièpce),拍出历史上第一张照片。

2.

他采用的感光剂是氯化银(silver chloride)。当光线照射氯化银,后者会分解成纯银和氯气,纯银在空气中很快氧化变成黑色。因此,底片颜色越深代表光线越强,颜色越浅代表光线越弱。黑白照片就是这样拍出来。

3.

19世纪中期,人们发现,人眼的圆锥细胞对三种颜色----红、绿、蓝----特别敏感。伟大的英国物理学家麦克斯韦因此假设,红绿蓝作为基色,可以拍出彩色照片。

4.

1861年,在麦克斯韦的指导下,人类的第一张彩色照片诞生了。

采用的方法是在镜头前,分别用红丝带、绿丝带、蓝丝带过滤光线,曝光形成三张底片,然后用三部放映机向同一处投影这三张底片,每部放映机的镜头前都拧上对应颜色的镜头,它们的合成效果就是一张彩照。

5.

真正意义上的彩色胶卷,1933年诞生于柯达公司,底片之上依次有三个感光层,分别对红、绿、蓝三种颜色进行曝光,最后叠加形成一张彩色底片。

6.

二战后,计算机诞生,科学家发现图像可以用数字形式表示。如果将光信号转变成电信号,就可以直接拍出数码照片。这意味着,照相机不再需要胶卷,而是需要一个图像传感器(image sensor)。

7.

图像传感器将光线转化成电流,光线越亮,电流的数值就越大;光线越暗,电流的数值就越小。所以,如果用0到255的范围,表示光线的亮度,最亮的光线是白光,数值是十六进制的FF,最暗的光线是黑光(没有光),数值是十六进制的00。

8.

图像传感器的表面,分成若干个捕捉点,每个点都会产生一个数值,表示该点感受到的光线亮度,这就叫做"像素"。像素越多,图像细节就越丰富。如果一台相机的像素是1600x1200,就说明图像传感器横向有1600个捕捉点,纵向有1200个,合计192万个。

9.

但是,图像传感器有一个很严重的缺陷:它只能感受光的强弱,无法感受光的波长。由于光的颜色由波长决定,所以图像传播器无法记录颜色,也就是说,它只能拍黑白照片,这肯定是不能接受的。

10.

一种解决方案是照相机内置三个图像传感器,分别记录红、绿、蓝三种颜色,然后再将这三个值合并。这种方法能产生最准确的颜色信息,但是成本太高,无法投入实用。

11.

1974年,柯达公司的工程师布赖斯·拜尔提出了一个全新方案,只用一块图像传感器,就解决了颜色的识别。他的做法是在图像传感器前面,设置一个滤光层(Color filter array),上面布满了滤光点,与下层的像素一一对应。也就是说,如果传感器是1600x1200像素,那么它的上层就有1600x1200个滤光点。

12.

每个滤光点只能通过红、绿、蓝之中的一种颜色,这意味着在它下层的像素点只可能有四种颜色:红、绿、蓝、黑(表示没有任何光通过)。

13.

不同颜色的滤光点的排列是有规律的:每个绿点的四周,分布着2个红点、2个蓝点、4个绿点。这意味着,整体上,绿点的数量是其他两种颜色点的两倍。这是因为研究显示人眼对绿色最敏感,所以滤光层的绿点最多。

14.

接下来的问题就是,如果一个像素只可能有四种颜色,那么怎么能拍出彩色照片呢?这就是布赖斯·拜尔聪明的地方,前面说了,每个滤光点周围有规律地分布其他颜色的滤光点,那么就有可能结合它们的值,判断出光线本来的颜色。以黄光为例,它由红光和绿光混合而成,那么通过滤光层以后,红点和绿点下面的像素都会有值,但是蓝点下面的像素没有值,因此看一个像素周围的颜色分布----有红色和绿色,但是没有蓝色----就可以推测出来这个像素点的本来颜色应该是黄色。

15.

这种计算颜色的方法,就叫做"去马赛克"(demosaicing)。上图的下半部分是图像传感器生成的"马赛克"图像,所有的像素只有红、绿、蓝、黑四种颜色;上半部分是"去马赛克"后的效果,这是用算法处理的结果。

16.

虽然,每个像素的颜色都是算出来的,并不是真正的值,但是由于计算的结果相当准确,因此这种做法得到广泛应用。目前,绝大部分的数码相机都采用它,来生成彩色数码照片。高级的数码相机,还提供未经算法处理的原始马赛克图像,这就是raw格式(raw image format)。

为了纪念发明者布赖斯·拜尔,它被称作"拜尔模式"或"拜尔滤光法" (Bayer filter)。

(完)

文档信息