罗马Cortes也带来了红玫瑰写Javascript
脚本。玫瑰的代码,这是最好的情人节礼物送给他的女朋友的
程序员。(
提示:有着不同的
浏览器。差别很大)
图片是由代码生成的,
用户可以刷新页面来重复玫瑰的过程。
3D Rose的实现代码如下所示:
复制代码 代码如下:with(m=Math)C=cos,S=sin,P=pow,R=random;c.width=c.height=f=500;h=-250;function p(a,b,c){if(c>60)return{S(a*7)*(13+5/(.2+P(b*4,4)))-S(b)*50,b*f+50,625+C(a*7)*(13+5/(.2+P(b*4,4)))+b*400,a*1-b/2,a};A=a*2-1;B=b*2-1;if(A*A+B*B37){n=(j=c1)6:4;o=.5/(a+.01)+C(b*125)*3-a*300;w=b*h;return{o*C(n)+w*S(n)+j*610-390,o*S(n)-w*C(n)+550-j*350,1180+C(B+A)*99-j*300,.4-a*.1+P(1-B*B,-h*6)*.15-a*b*.4+C(a+b)/5+P(C((o*(a+1)+(B>0w:-w))/25),30)*.1*(1-B*B),o/1e3+.7-o*w*3e-6}}if(c>32){c=c*1.16-.15;o=a*45-20;w=b*b*h;z=o*S(c)+w*C(c)+620;return{o*C(c)-w*S(c),28+C(B*.5)*99-b*b*b*60-z/2-h,z,(b*b*.3+P((1-(A*A)),7)*.15+.3)*b,b*.7}}o=A*(2-b)*(80-c*2);w=99-C(A)*120-C(b)*(-h-c*4.9)+C(P(1-b,7))*50+c*2;z=o*S(c)+w*C(c)+700;返回{ O * C(C)- W的(C),B 99-c(P(B,7))* 50-c / 3-z / 1.35 + 450,Z(1-B / 1.2)* 9 + *。1、P((1-B)/ 4 +。05 } } } setInterval(',20)(i = 0;IZ)M {重置} = Z a.fillstyle = RGB(+ ~(S { 3 }×H)+(S { 4 }×H)
当然,感兴趣的人可以理解下面的实现过程和相关理论:
三维代码上升是由Monte Carlo
方法提出的,创作者对蒙特卡洛方法非常推崇。他说,Monte Carlo方法在
函数优化和抽样中是一个令人难以置信的强有力的
工具。蒙特卡洛方法可以
参考:Monte Carlo方法。
具体
操作:
外观取样绘制
我用了许多不同的形状来编代码,一共有31个形状:24个花瓣,4个萼片,2个叶子和1个茎,每一个都用代码来描述。
首先,定义采样范围:
函数表面(a,b)使用a和i i b作为
参数,范围从0到1。
返回{
x:A * 50,
y:B * 50
};
这种表面将方/大小50X50单位
}
然后,编写形状描述代码:
VaR的画布document.body.appendchild(document.createelement(画布))),
背景canvas.getcontext(2D),
A,B,
位置;
现在我要对A和B参数进行1点间隔采样:
对于(a = 0;a<1;a=1){
对于(b = 0;b<1;b=1){
位置=表面(A,B);
context.fillrect(位置。X,Y位置。,1, 1);
}
}
现在,尝试更密集的采样间隔:
正如我们现在看到的,因为采样间隔越来越密集,而且距离越来越近。当密度最高时,相邻点之间的距离小于一个像素,肉眼看不到间隔(见0.01),为了不造成太多的视觉差异,采样间隔进一步缩小。此时,绘图
区域已经填充(结果为0.01和0.001)。
接下来,我用这个公式来画一个圆:(x-x0)^ 2 +(y-y0)^ 2 <半径^ 2,其中(x0,y0)是圆的中心:
函数表面(a,b){
var = a * 100,
y = b * 100,
半径=50,
x0 = 50,
y0 = 50;
如果((x x0)*(x x0)+(Y y0)*(Y y0)<半径*半径){
圆圈内
返回{
X,
Y: y
};
{人}
圆圈{ / }外面
返回null;
}
}
为了防止溢出,添加一个采样
条件:
如果(位置=表面(A,B)){
context.fillrect(位置。X,Y位置。,1, 1);
}
定义一个圆有不同的方法,其中一些不需要拒绝采样,我不必用它来定义圆的意义,所以这里有另一种定义圆的方法:
函数表面(a,b){
使用极坐标
功角= * math.pi * 2,
半径=50,
x0 = 50,
y0 = 50;
返回{
X:Math.cos(角)×半径×B + x0,
Y:Math.sin(角)×半径×B + y0
};
}
(与以前的方法相比,这种方法需要密集的采样)。
好了,现在让圆变形,使它看起来更像一个花瓣:
函数表面(a,b){
var = a * 100,
y = b * 100,
半径=50,
x0 = 50,
y0 = 50;
如果((x x0)*(x x0)+(Y y0)*(Y y0)<半径*半径){
返回{
X,
y *(1 + B) 2变形
};
{人}
返回null;
}
}
它看起来像玫瑰花瓣的形状。在这里你也可以尝试改变一些函数值,并且会有很多有趣的形状。
然后你应该给它添加颜色:
函数表面(a,b){
var = a * 100,
y = b * 100,
半径=50,
x0 = 50,
y0 = 50;
如果((x x0)*(x x0)+(Y y0)*(Y y0)<半径*半径){
返回{
X,
y *(1 + B) 2,
R:math.floor(100 +(1 - B)* 155) / /这将添加一个渐变。
G:50,
B:50
};
{人}
返回null;
}
}
对于(a = 0;a<1;a=01){
对于(b = 0;b<1;b=001){
如果(点=面(a,b)){
context.fillstyle =RGB(+ R +点。
context.fillrect(点X,Y,1, 1点。);
}
}
}
一片彩色花瓣出现了。
三维表面透视投影
定义一个三维曲面是非常简单的,例如,定义一个管状物体:
函数表面(a,b){
功角= * math.pi * 2,
半径=100,
长度= 400;
返回{
X:Math.cos(角)×半径,
Y:Math.sin(角)×半径,
z长度长度为2/0, 0, 0,减去长度2。
R:0,
G:Math.floor(B 255),
B:0
};
}
然后添加投影透视图。首先,我们需要定义一个摄像机:
如上所示,照相机被放置在(0, 0,z)的位置,画布位于X / Y平面上,投影到画布上的采样点是:
在画布x和y坐标下投影
透视图= 350,
halfheight = canvas.height / 2,
半宽度= canvas.width / 2,
CameraZ = -700;
对于(a = 0;a<1;a=001){
对于(b = 0;b<1;b=01){
如果(点=面(a,b)){
PX =(点。X透视)/(点。Z cameraz)+半宽度;
py =(点。Y *角度)/(点。Z cameraz)+ halfheight;
context.fillstyle =RGB(+ R +点。
context.fillrect(px,py,1, 1);
}
}
}
效果是:
z
z是
计算机图形学中一个很常见的技术。当它为对象着色时,它
执行隐藏面的消除,这样隐藏对象后面的部分就不会
显示出来。
上面的图片是玫瑰与Z-Buffer技术
处理。(可以看出它有立体感。)
代码如下:
VaR zbuffer = { },
zbufferindex;
对于(a = 0;a<1;a=001){
对于(b = 0;b<1;b=01){
如果(点=面(a,b)){
PX = math.floor((点。X透视)/(点。Z cameraz)+半角);
py = math.floor((点。Y *角度)/(点。Z cameraz)+ halfheight);
zbufferindex = Py×canvas.width + PX;
如果((typeof将zbufferindex } = {定义)| |(点。Z < zbuffer { zbufferindex })){
ZBuffer zbufferindex } = { Z点;
context.fillstyle =RGB(+ R +点。
context.fillrect(px,py,1, 1);
}
}
}
}
旋转
你可以用任何一种方法来旋转矢量。在生成代码的时候,我用了罗斯的旋转。
函数表面(a,b){
功角= * math.pi * 2,
半径=100,
长度= 400,
x = math.cos(角)×半径,
Y = Math.sin(角)×半径,
z *长度长度 2,
yaxisrotationangle = - 4, /弧度!
rotatedx = X * Math.cos(yaxisrotationangle)+ Z * math.sin(yaxisrotationangle),
rotatedz =××-math.sin(yaxisrotationangle)+ Z * math.cos(yaxisrotationangle);
返回{
X:rotatedx,
Y,
Z:rotatedz,
R:0,
G:Math.floor(B 255),
B:0
};
}
uff1a效应
蒙特卡洛法
关于采样时间,过大或过小的间隔会引起极端的视觉感知,所以我们需要
设置一个合理的采样间隔,这里使用蒙特卡洛方法。
var i;
Window.setInterval(function(){()
对于(i = 0;i < 10000;i + +){
如果(点=面(Math.random)、Math.random(())){
PX = math.floor((点。X透视)/(点。Z cameraz)+半角);
py = math.floor((点。Y *角度)/(点。Z cameraz)+ halfheight);
zbufferindex = Py×canvas.width + PX;
如果((typeof将zbufferindex } = {定义)| |(点。Z < zbuffer { zbufferindex })){
ZBuffer zbufferindex } = { Z点;
context.fillstyle =RGB(+ R +点。
context.fillrect(px,py,1, 1);
}
}
}
},0);
设置a和b作为随机参数,完成表面填充,并进行充分的采样,每次绘制10000点,然后
等待屏幕完成更新。
它还指出,如果随机数是
错误的重要,表面的填充效果将是错误的。在一些浏览器中执行,Math.random是线性的,这会导致一个错误在地表充填的效果。在这一点上,像Mersenne Twister(随机数算法)应该必须使用高质量的PRNG采样,从而避免错误的发生。
完成
为了完成和渲染玫瑰花的每一部分,我们需要添加一个函数来设置每个部分的参数返回到
同步的值,并且用一个分段函数来表示玫瑰的各个部分,例如,在花瓣部分,我用旋转和变形来
创建它们。
Although the surface sampling method is one of the most famous and oldest methods to create 3D graphics, this method of adding Monte Carlo and z-buffer into surface sampling is not common.It may not be very creative for the production of real life, but its simple code implementation and small volume are still satisfactory.
我希望这篇文章能激发计算机图形学爱好者尝试不同的呈现方式和享受它。(罗马Cortes)
以上是本文的全部内容,希望能对您有所帮助,希望大家多多
支持。