用HTML5献上爱的3D玫瑰

最后更新于:2022-04-01 19:43:27

译自:[http://www.romancortes.com/blog/1k-rose/](http://www.romancortes.com/blog/1k-rose/) 转载请标明作者和出处:[http://blog.csdn.net/hfahe](http://blog.csdn.net/hfahe) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2ddad2ee.gif)       我曾参与[js1k](http://js1k.com/2012-love/)爱情主题的第四次活动(译者注:关于有趣的js1k,可以看看我上一篇博文《[JS1k比赛与3D玫瑰](http://blog.csdn.net/hfahe/article/details/7249682)》)。我所提交的是一个静态图像,由程序生成的三维玫瑰。你可以在[这里](http://js1k.com/2012-love/demo/1022)看到它。       它是通过显式分段三维曲面的蒙特卡洛采样所实现的。我要在这篇文章中尝试解释所有内容。 **关于蒙特卡罗方法的简短说明**       蒙特卡罗方法是令人难以置信的强大工具。我一直在使用它们来实现很多功能优化和采样的问题。相比起设计和编写算法,如果你有更多CPU时间的话,它们几乎可以像变魔术一样。在这个关于玫瑰的案例里,它对于代码大小的优化非常有用。       如果你对于蒙特卡罗方法了解不多,你可以读读[Wikipedia上一篇不错的相关文章](http://en.wikipedia.org/wiki/Monte_carlo_method)。 **显式的曲面和采样/绘图**       我使用多个显式定义的曲面来定义玫瑰的形状。我总共使用了31个面:24片花瓣,4片萼片(花瓣周围的薄叶),2片叶子以及玫瑰枝。       那么它们是如何表示这些显式曲面的呢?这非常容易,我将会提供一个二维的例子:       首先,我定义了显式曲面的函数: ~~~ function surface(a, b) { // 我使用0到1之间的a和b作为参数 return { x: a*50, y: b*50 }; // 曲面将会是50*50大小的一个正方形 } ~~~       然后下面是绘制它的代码: ~~~ var canvas = document.body.appendChild(document.createElement("canvas")), context = canvas.getContext("2d"), a, b, position; // 现在我将要为a和b参数采用0.1间隔来进行曲面采样 for (a = 0; a < 1; a += .1) { for (b = 0; b < 1; b += .1) { position = surface(a, b); context.fillRect(position.x, position.y, 1, 1); } } ~~~       下面是结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2dded1ac.gif) 放大了4倍       现在,让我们尝试更密集的采样间隔(更小的间隔=更密集的采样): ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2de0da19.gif)       正如你看到的一样,因为你的样例越来越密集,点越来越接近,当相邻两点的距离小于一个像素时,屏幕上区域已经被完全的充满了(见0.01的图)。之后使它更密集并不会造成太大的视觉差别,因为你只是在已经填满的区域上继续绘制(比较0.01和0.001的结果)。       OK,现在让我们重新定义曲面函数来画一个圆。 有多种方法可以做到这一点,但我会用这个公式:(x-x0)^2 + (y-y0)^2 ';