Greatest

All about 非主流脑残技术

导航

Web Worker之Milo Yip的光线追踪



以上是milo yip写的《用JavaScript玩转计算机图形学(一)光线追踪入门》中代码的Web Worker版本。我将代码略作修改使其能够在Web Worker中运行,并且添加的uv坐标使得Checker材质能更通用,和折射(最后3个示例)。当然,我这篇文章只说Web Worker部分。

Web Worker简介

一个Web Worker对象就对应着一个操作系统的线程。使用如下方式创建:

var worker = new Worker("foo.js");

Worker构造函数的参数是个url,在新建的线程中就执行foo.js中的代码。但是在foo.js中的代码是有限制的,它不能直接访问在主线程也就是html页面中的任何对象,而只能使用消息来进行通信。
例如,html中的代码:

var worker = new Worker("foo.js");
worker.onmessage = function(e){
console.log(e.data);
}
worker.postMessage("world");

foo.js中的代码

this.onmessage = function(e){
postMessage("hello,"+e.data);
}

在上述代码中,html中新建一个Worker对象,并监听message事件(也可以使用AddEventListener),最后发送一个"world"字符串给Worker。
在foo.js中,监听message时间,当收到来自于主线程的消息时,在消息前面加上"hello,"并回复。
在大多数情况下,都是html页面中的代码发送一个消息给Worker,Worker进行复杂的计算,并且将结果用消息发送给html页面。
不过,postMessage能发送的消息并不能是任意的对象,这个对象不能包含函数,任何dom对象,等等。幸运的是,可以是canvas中的ImageData对象,上面的示例传递的就是ImageData对象。(具体哪些可以,哪些不可以请参考:https://developer.mozilla.org/en/DOM/The_structured_clone_algorithm)

Inline Web Worker

Worker对象构造函数参数一定要是一个url,那如何才能将Web Worker代码和html写在同一个文件中呢? 代码如下:

function createBlobUrl(text)
{
var bb;
if (window.BlobBuilder)
bb = new BlobBuilder();
else if (window.WebKitBlobBuilder)
bb = new WebKitBlobBuilder();
else if (window.MozBlobBuilder)
bb = new MozBlobBuilder();
else if (window.Blob)
bb = new Blob();
return null;
bb.append(text);
if (window.URL && URL.createObjectURL)
{
return window.URL.createObjectURL(bb.getBlob());
}
else if (window.webkitURL && webkitURL.createObjectURL)
{
return window.webkitURL.createObjectURL(bb.getBlob());
}
else
return null;
}
function createInlineWebWorker(id)
{
var url = createBlobUrl(document.getElementById(id).textContent);
if (!url) return null;
return new Worker(url);
}

CreateBlobUrl(text)会创建一个url,浏览器访问这个url就会返回text的内容(不过由于chrome一个该死的wontfix的bug,此函数对于保存的本地html不起作用)。 试试,复制下面的url,并在浏览器的新页面打开


是不是内容是abcdefg呢?
这样就可以这么写了:

<script id="worker1" type="webworker">
this.onmessage = function(e){
postMessage("hello,"+e.data);
}
</script>
<script>
var worker = createInlineWebWorker("worker1")
</script>

注意哦,第一个script的type是worker,所以浏览器并不会执行其代码。而且由于使用script标签,所以中间的内容并不需要html escape也不会显示出来。

最后

我来说一下,上面光线追踪中Web Worker代码是怎么写的。 Web Worker代码如下:

self.onmessage = function(e)
{
var data = e.data;
if (data.type=="eval")
{
var ret;
var code = data.code;
try
{
ret = eval(code);
}
catch(err)
{
postMessage({type:"log",msg:err.message+"\nline:"+err.lineNumber});
postMessage({type:"error",msg:err.message+"\nline:"+err.lineNumber});
return;
}
postMessage({type:"result",result:ret});
}
}

很简单吧,就是在Web Worker中运行一下html页面上发过来的代码(不是函数,是代码的文本哦)。如果成功,则将返回值返回给页面;出错则将出错信息返回给页面。例如,你想在Web worker中计算1到100的和,则代码如下:

function calc(n)
{
var ret = 0;
for (var i=1;i<=n;++i)
ret += i;
return ret;
}
worker.onmessage = function(e){
if (e.data.type == "result")
{
alert(e.data.result)
}
}
worker.postMessage({
type:"eval",
code:calc.toString()+";calc(100);"
});

好啦,就写到这里啦。其实,我对Web Worker的了解就是参考了google "Web Worker"中第一页的几篇文章,尤其这篇比较通俗易懂:http://www.html5rocks.com/en/tutorials/workers/basics/希望大家能认真看一下。
最后的最后,希望下次我能写篇文章来说一下光线追踪的折射。

posted on 2012-01-12 15:05  Greatest  阅读(1995)  评论(0编辑  收藏  举报