Valentine's Day exclusive pure JS script 1k size 3D rose effect _javascript Tips

Source: Internet
Author: User
Tags cos setinterval sin

The year before Christmas, Spanish programmer Roman Cortes brought the magic 3D Christmas tree, written in pure JavaScript script, impressive. February 14 Valentine's Day is coming, or Roman Cortes, and this time he brought the red roses written in JavaScript script. With the code to make the Rose, this is a good programmer to give a girlfriend the best Valentine's Day gift! (Hint: in different browsers to watch the effect, speed will be very different)
The picture is generated by code, and the user can refresh the page and repeat the process of seeing the rose.

The implementation code for the 3D rose flower is as follows:

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*b<1) {if (c>37) {n= (j=c&1)? 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* ) + (B&GT;0?W:-W))/25) *.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 ((n) (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;return[o*c (c)-w*s (c), B*99-c (p (b, 7 )) *50-c/3-z/1.35+450,z, (1-b/1.2) *.9+a*.1, P ((1-b),)/4+.05]}}setinterval (' for (i=0;i<1e4;i++) if (S=p (R), R (), i%46/.74)) {z=s[2];x=~~ (s[0]*f/z-h); y=~~ (s[1]*f/z-h); if (!m[q=y*f+x]|m[q]>z) m[q]=z,a.fillstyle= "RGB (" +~ h) + "," +~ (s[4]*h) + "," +~ (s[3]*s[3]*-80) + ")", A.fillrect (x,y,1,1)} ', 0)

Of course, interested people can understand the following implementation process and related theories:

This three-dimensional code rose is presented in a Monte Carlo way, and the creator is very popular with the Monte Carlo approach, saying that in terms of functional optimization and sampling, the Monte method is an "incredibly powerful tool". About the Monte Carlo method can refer to: Monte Carlo methods.

Specific actions:

Appearance sampling rendering effect drawing

I used a number of different shape diagrams to make up this code rose. A total of 31 shapes were used: 24 petals, 4 sepals, 2 leaves and 1 stems, each of which is depicted in code.

First, define a sample range:

function surface (A, B) {//I ' m using a and B as parameters ranging from 0 to 1.

return {

X:A*50,

Y:b*50

};

This surface would be a square of 50x50 units of size

}

Then, write the shape description code:

var canvas = Document.body.appendChild (document.createelement ("Canvas")),

Context = Canvas.getcontext ("2d"),

A, B, position;

Now I ' m going to sample the surface in. 1 intervals for A and B parameters:

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);

}

}

At this point, see the effect is this:

Now, try a more intensive sampling interval:

As is now seen, because the sampling interval is getting denser, the dots are getting closer, to the highest density, the distance between adjacent points is less than one pixel, and the naked eye cannot see the interval (see 0.01). To reduce the sampling interval further by not causing too much visual aberration, the plot area is filled (the comparison results are 0.01 and 0.001).

Next, I use this formula to draw a circle: (x-x0) ^ 2 + (y-y0) ^ 2 < radius ^ 2, where (X0,Y0) is the center of the circle:

function surface (A, b) {

var x = A * 100,

y = b * 100,

Radius = 50,

x0 = 50,

y0 = 50;

if ((x-x0) * (x-x0) + (y-y0) * (Y-Y0) < radius * radius) {

Inside the Circle

return {

X:x,

Y:y

};

} else {

Outside the Circle

return null;

}

}

To prevent overflow, add a sample condition:

if (position = surface (A, b)) {

Context.fillrect (position.x, POSITION.Y, 1, 1);

}

The results are as follows:

There are different ways to define a circle, some of which do not have to reject the sample. I'm not sure which one to use to define the meaning of the circle, so here's another way to define a circle:

function surface (A, b) {

Circle using polar coordinates

var angle = A * Math.PI * 2,

Radius = 50,

x0 = 50,

y0 = 50;

return {

X:math.cos (angle) * radius * b + x0,

Y:math.sin (angle) * radius * b + y0

};

}

As shown in figure:

(This method requires dense sampling for padding compared to the previous method.) )

OK, now let the circle deform to make it look more like a petal:

function surface (A, b) {

var x = A * 100,

y = b * 100,

Radius = 50,

x0 = 50,

y0 = 50;

if ((x-x0) * (x-x0) + (y-y0) * (Y-Y0) < radius * radius) {

return {

X:x,

Y:y * (1 + B)/2//deformation

};

} else {

return null;

}

}

Results:

It looks like the shape of a rose petal. Here you can also try to modify some of the function values, there will be many interesting shapes.

Next, you should add color to it:

function surface (A, b) {

var x = A * 100,

y = b * 100,

Radius = 50,

x0 = 50,

y0 = 50;

if ((x-x0) * (x-x0) + (y-y0) * (Y-Y0) < radius * radius) {

return {

X:x,

Y:y * (1 + B)/2,

r:100 + Math.floor ((1-b) *),//This'll add a gradient

G:50,

B:50

};

} else {

return null;

}

}

for (a = 0; a < 1; a =. 01) {

for (b = 0; b < 1; b = 001) {

if (point = surface (A, b)) {

Context.fillstyle = "RGB" ("+ POINT.R +", "+ Point.g +", "+ point.b +") ";

Context.fillrect (Point.x, Point.y, 1, 1);

}

}

}

Results:

A piece of colored petals appeared.

3D Surfaces and perspective projections

Defining a three-dimensional surface is simple, for example, to define a tubular object:

function surface (A, b) {

var angle = A * Math.PI * 2,

RADIUS = 100,

length = 400;

return {

X:math.cos (angle) * radius,

Y:math.sin (angle) * radius,

Z:B * LENGTH-LENGTH/2,//by subtracting LENGTH/2 I have centered of the tube at (0, 0, 0)

r:0,

G:math.floor (b * 255),

b:0

};

}

Then add a projection perspective, first we need to define a camera:

As pictured above, place the camera in the (0,0,z) position, with the canvas on the x/y plane. The sample points that are projected onto the canvas are:

var PX, PY,//projected on canvas x and y coordinates

Perspective = 350,

Halfheight = CANVAS.HEIGHT/2,

Halfwidth = CANVAS.WIDTH/2,

Cameraz =-700;

for (a = 0; a < 1; a =. 001) {

for (b = 0; b < 1; b = 01) {

if (point = surface (A, b)) {

PX = (Point.x * perspective)/(Point.z-cameraz) + Halfwidth;

PY = (POINT.Y * perspective)/(Point.z-cameraz) + halfheight;

Context.fillstyle = "RGB" ("+ POINT.R +", "+ Point.g +", "+ point.b +") ";

Context.fillrect (PX, PY, 1, 1);

}

}

}

The effect is:

Z-buffer

Z-buffer is a fairly common technique in computer graphics, which performs "hidden surface elimination" When coloring objects, so that the parts behind hidden objects are not displayed.

The image above is a rose treated with z-buffer technology. (You can see it already has three-dimensional)

The code is as follows:

var zbuffer = [],

Zbufferindex;

for (a = 0; a < 1; a =. 001) {

for (b = 0; b < 1; b = 01) {

if (point = surface (A, b)) {

PX = Math.floor ((point.x * perspective)/(Point.z-cameraz) + Halfwidth);

PY = Math.floor ((POINT.Y * perspective)/(Point.z-cameraz) + halfheight);

Zbufferindex = PY * canvas.width + PX;

if ((typeof zbuffer[zbufferindex] = = "undefined") | | (Point.z < Zbuffer[zbufferindex]) {

Zbuffer[zbufferindex] = point.z;

Context.fillstyle = "RGB" ("+ POINT.R +", "+ Point.g +", "+ point.b +") ";

Context.fillrect (PX, PY, 1, 1);

}

}

}

}

Rotating

You can use any vector rotation method. In the creation of the code rose, I used the Euler rotation. Now rotate the previously written tube to rotate around the y axis:

function surface (A, b) {

var angle = A * Math.PI * 2,

RADIUS = 100,

Length = 400,

x = Math.Cos (angle) * radius,

y = Math.sin (angle) * radius,

z = b * LENGTH-LENGTH/2,

Yaxisrotationangle =-.4,//in radians!

Rotatedx = x * Math.Cos (yaxisrotationangle) + Z * Math.sin (yaxisrotationangle),

Rotatedz = x *-math.sin (yaxisrotationangle) + Z * MATH.COS (yaxisrotationangle);

return {

X:rotatedx,

Y:y,

Z:rotatedz,

r:0,

G:math.floor (b * 255),

b:0

};

}

Effect:

Monte Carlo method

About the sampling time, the interval over the small will cause a very poor visual feeling, so we need to set a reasonable sampling interval, here using the Monte Carlo method.

var i;

Window.setinterval (function () {

for (i = 0; i < 10000; i++) {

if (point = surface (Math.random (), Math.random ())) {

PX = Math.floor ((point.x * perspective)/(Point.z-cameraz) + Halfwidth);

PY = Math.floor ((POINT.Y * perspective)/(Point.z-cameraz) + halfheight);

Zbufferindex = PY * canvas.width + PX;

if ((typeof zbuffer[zbufferindex] = = "undefined") | | (Point.z < Zbuffer[zbufferindex]) {

Zbuffer[zbufferindex] = point.z;

Context.fillstyle = "RGB" ("+ POINT.R +", "+ Point.g +", "+ point.b +") ";

Context.fillrect (PX, PY, 1, 1);

}

}

}

}, 0);

Set A and B as random parameters, with sufficient sampling to complete the surface fill. I draw 10,000 points at a time, and then wait until the screen completes the update.

Also note that if there is an error in the random number, the surface fill effect will be wrong. In some browsers, the execution of Math.random is linear, which can result in errors in the surface fill effect. At this point, you have to use something like Mersenne twister (a random number algorithm) to perform high-quality prng sampling, thus avoiding the occurrence of errors.

Complete

To make each part of the rose complete and present at the same time, you also need to add a feature that sets a parameter for each section to be synchronized with the return value. and a piecewise function to represent the various parts of the rose. For example, in the Petals section, I use rotation and deformation to create them.

Although surface sampling is one of the most famous and ancient methods for creating three-dimensional graphics, this method of adding Monte Carlo and Z-buffer to surface sampling is uncommon. This may not be a very creative way of making a real-life scene, but its simple code implementation and small volume are still satisfying.

Hopefully this article will inspire computer graphics enthusiasts to try different presentation methods and get some fun from them. (Roman Cortes)

English site: romancortes.com

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.