With the development of front-end technology, especially the application of canvas and SVG in HTML5, the Web can easily render various brilliant effects.
This article discusses the first knowledge of the 3D effect based on rotate. Use some transformations to simulate the getcontext ('2d ') of canvas. Webgl is not discussed in this article.
[Brief principle]
Because it is still simulated in 2D, the so-called 3D will eventually be reduced to 2D.
In terms of coordinates, the 3D interface should have three coordinates: X, Y, and Z. in 2D, only the X and Y directions are displayed.
So how to associate the z-axis of 3D with the X and Y of 2D is the key.
To show the 3D Z-direction attention on the 2D interface, a view well is required.
I believe that those who have learned painting should be clear about the need to draw perspective or hierarchical objects. At the beginning of modeling, the teacher will teach you to "Create a grid" based on the observation angle, and simulate the object size and hierarchy first.
The grid is actually a kind of "well" from near to far.
The most intuitive feeling is that you can imagine a photo taking a long corridor. The corridor in the photo must be close to the width. As the distance is drawn, the corridor width must be narrow, it looks like two diagonal lines extending to a distance.
Therefore, in the coding process, according to this principle, it is hard to imagine that the original zcoordinate is displayed on the 2D X and Y coordinates, and the influence is the offset of XY coordinates.
At the same time, there are also changes in the object size and transparency (ambiguity), which should be easy to think.
[Demo1]
The following uses a small ball to show the effect of changing the zcoordinate position on the X and Y positions and sizes on the 2D interface.
// Create a ball
VaR Ball = Createball (ballr );
// Add to stage
Stage. addchild (ball );
// Obtain the canvas Center Position
Vpx = Canvas. Width / 2;
Vpy = Canvas. Height / 2;
// Obtains the relative center offset of the current mouse from xpos and ypos.
Stage. addeventlistener ( ' Mousemove ' , Function (X, y ){
Xpos = X - Vpx;
Ypos = Y - Vpy;
});
// Use the keyboard up/down key to change the zcoordinate position
Document. addeventlistener ( ' Keydown ' , Function (E ){
If (E. keycode = 38 ) Zpos + = 5 ;
If (E. keycode = 40 ) Zpos -= 5 ;
}, False )
// Changes when each frame is refreshed
Stage. onrefresh = Function (){
// Flatten zcoordinate
VaR Scale = Focallength / (Focallength + zpos );
// Apply the zcoordinate After flattening to the X and Y coordinates of the ball.
Ball. x = Vpx + Xpos * Scale;
Ball. Y = Vpy + Ypos * Scale;
// Influence on Ball Size
Ball. Width = Ballr * 2 * Scale;
Document. getelementbyid ( ' Scale ' ). Innerhtml = Scale;
}
Stage. Start ();
CodeIt's very easy. They all licked comments.
<! Doctype HTML> <style> <br/> HTML {overflow: hidden} <br/> body {position: absolute; margin: 0; padding: 0; width: 100%; Height: 100%} <br/> canvas {display: block; Border: 2px solid # CCC; margin: 10px auto ;}< br/> P {text-align: center; font-size: 12px; color: #454545 ;} <br/> </style> <SCRIPT src = "http://hongru.github.com/js/JCanvas.js"> </SCRIPT> <br/> <canvas id = "canvas" width = "600" Height = "400 "> </canvas> <p> keyboard up and down The key changes the Z-direction depth. Current scale: <span id = "scale"> </span> </P> <SCRIPT> <br/> var canvas = document. getelementbyid ('canvas '); <br/> var stage = new stage (canvas); <br/> var createball = function (RADIUS) {<br/> radius = (radius = undefined )? 20: radius; <br/> return New sprite (stage. CTX, {<br/> X: 0, <br/> Y: 0, <br/> width: radius * 2, <br/> draw: function () {<br/> This. CTX. beginpath (); <br/> This. CTX. ARC (0, 0, this. width/2, 0, math. pI * 2, true); <br/> This. CTX. closepath (); <br/> This. CTX. fillstyle = 'rgba (0, 0, 0, '+ math. min (1, this. width/(2 * radius) + ')'; <br/> This. CTX. fill (); <br/>}< br/>}); <br/>}; </P> <p> var initialize = function () {<br/> var xpos = 0, <br/> ypos = 0, <br/> zpos = 0, <br/> focallength = 250, <br/> ballr = 20, <br/> vpx, <br/> vpy; <br/> var ball = createball (ballr); <br/> stage. addchild (ball); <br/> vpx = canvas. width/2; <br/> vpy = canvas. height/2; </P> <p> stage. addeventlistener ('mousemove ', function (x, y) {<br/> xpos = x-vpx; <br/> ypos = Y-vpy; <br/> }); <br/> document. addeventlistener ('keylow', function (e) {<br/> If (E. keycode = 38) zpos + = 5; <br/> If (E. keycode = 40) zpos-= 5; <br/>}, false) </P> <p> stage. onrefresh = function () {<br/> var scale = focallength/(focallength + zpos); <br/> ball. X = vpx + xpos * scale; <br/> ball. y = vpy + ypos * scale; <br/> ball. width = ballr * 2 * scale; </P> <p> document. getelementbyid ('Scale '). innerhtml = scale; <br/>}</P> <p> stage. start (); <br/>}; </P> <p> initialize (); </P> <p> </SCRIPT> </ptml> </P> <p>
[Demo2]
The demo above may be too simple to see the so-called 3D effect. According to the above idea, we can add a rotation effect to the X direction. Combined with the influence of the Z direction, we can see the so-called 3D effect.
// Retrieve canvas Center
Vpx = Canvas. Width / 2;
Vpy = Canvas. Height / 2;
// Calculate the selected angle (speed) based on the mouse position)
Stage. addeventlistener ( ' Mousemove ' , Function (X, y ){
Angley = (X - Vpx) * . 001 ;
});
// Main rotation Function
Function Rotatey (ball, angley ){
// Convert the angle trigonometric function to make it look like it is a circle Rotation
VaR Cosy = Math. Cos (angley ),
Siny = Math. Sin (angley ),
// Calculate the Z-Direction Impact.
X1 = Ball. xpos * Cosy - Ball. zpos * Siny,
Z1 = Ball. zpos * Cosy + Ball. xpos * Siny;
Ball. xpos = X1;
Ball. zpos = Z1;
// The zcoordinate is flat and assigned to the ball.
VaR Scale = Focallength / (Focallength + Ball. zpos );
Ball. x = Vpx + Ball. xpos * Scale;
Ball. Y = Vpy + Ball. ypos * Scale;
Ball. Width = Ballr * 2 * Scale;
}
The actual code runs as follows:
<! Doctype HTML> <style> <br/> HTML {overflow: hidden} <br/> body {position: absolute; margin: 0; padding: 0; width: 100%; Height: 100%} <br/> canvas {display: block; Border: 2px solid # CCC; margin: 10px auto ;}< br/> P {text-align: center; font-size: 12px; color: #454545 ;} <br/> </style> <SCRIPT src = "http://hongru.github.com/js/JCanvas.js"> </SCRIPT> <br/> <canvas id = "canvas" width = "600" Height = "400 "> </canvas> <p> </P> <SCRIPT> <br/> var canvas = document. getelementbyid ('canvas '); <br/> var stage = new stage (canvas); <br/> var createball = function (RADIUS) {<br/> radius = (radius = undefined )? 20: radius; <br/> return New sprite (stage. CTX, {<br/> X: 0, <br/> Y: 0, <br/> width: radius * 2, <br/> draw: function () {<br/> This. CTX. beginpath (); <br/> This. CTX. ARC (0, 0, this. width/2, 0, math. pI * 2, true); <br/> This. CTX. closepath (); <br/> This. CTX. fillstyle = 'rgba (0, 0, 0, '+ math. min (1, this. width/(2 * radius) + ')'; <br/> This. CTX. fill (); <br/>}< br/>}); <br/>}; </P> <p> var initialize = function () {<br/> var focallength = 250, <br/> ballr = 20, <br/> BALlN = 20, <br/> bils = [], <br/> vpx = 0, <br/> vpy = 0, <br/> angley = 0; </P> <p> for (VAR I = 0; I <BALlN; I ++) {<br/> var ball = createball (ballr); <br/> stage. addchild (ball); <br/> ball. xpos = math. random () * 200-100; <br/> ball. ypos = math. random () * 200-100; <br/> ball. zpos = math. random () * 200-100; <br/> bils. push (ball); <br/>}< br/> vpx = canvas. width/2; <br/> vpy = canvas. height/2; </P> <p> stage. addeventlistener ('mousemove ', function (x, y) {<br/> angley = (X-vpx )*. 001; <br/>}); </P> <p> function rotatey (ball, angley) {<br/> var cosy = math. cos (angley), <br/> Siny = math. sin (angley), <br/> X1 = ball. xpos * cosy-ball. zpos * Siny, <br/> z1 = ball. zpos * cosy + ball. xpos * Siny; <br/> ball. xpos = x1; <br/> ball. zpos = Z1; </P> <p> var scale = focallength/(focallength + ball. zpos); <br/> ball. X = vpx + ball. xpos * scale; <br/> ball. y = vpy + ball. ypos * scale; <br/> ball. width = ballr * 2 * scale; <br/>}</P> <p> stage. onrefresh = function () {<br/> for (VAR I = 0, ball; ball = bils [I]; I ++) {rotatey (ball, angley )} <br/>}</P> <p> stage. start (); <br/>}; </P> <p> onload = initialize; </P> <p> </SCRIPT> </ptml> </P> <p>
Well, I still want to write more in this article, but I am hungry. I can't help but fill in my stomach first. I will go to work tomorrow ....
Today's Mid-Autumn Festival, although it is a little late, I wish you a happy holiday.
Next, continue...