只要1K纯js脚本发送给你一个3D的红玫瑰

只要1K纯js脚本发送给你一个3D的红玫瑰
罗马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)

以上是本文的全部内容,希望能对您有所帮助,希望大家多多支持

免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部