简体   繁体   中英

Adding perspective to fake 3D animation

I'm working on a canvas-based animation, and I'm trying to get a 3D effect in a 2D canvas.

So far, things are going well! I've got my "orbiting line of triangles" working very well:

 var c = document.createElement('canvas'); c.width = c.height = 100; document.body.appendChild(c); var ctx = c.getContext("2d"); function Triangles() { this.rotation = { x: Math.random()*Math.PI*2, y: Math.random()*Math.PI*2, z: Math.random()*Math.PI*2 }; /* Uncomment this for testing perspective... this.rotation = { x: Math.PI/2, y: 0, z: 0 }; */ } Triangles.prototype.draw = function(t) { this.rotation.z += t/1000; var i, points; for( i=0; i<15; i++) { points = [ this.computeRotation(Math.cos(0.25*i),-Math.sin(0.25*i),0), this.computeRotation(Math.cos(0.25*(i+1)),-Math.sin(0.25*(i+1)),-0.1), this.computeRotation(Math.cos(0.25*(i+1)),-Math.sin(0.25*(i+1)),0.1) ]; ctx.fillStyle = "black"; ctx.beginPath(); ctx.moveTo(50+40*points[0][0],50+40*points[0][1]); ctx.lineTo(50+40*points[1][0],50+40*points[1][1]); ctx.lineTo(50+40*points[2][0],50+40*points[2][1]); ctx.closePath(); ctx.fill(); } }; Triangles.prototype.computeRotation = function(x,y,z) { var rz, ry, rx; rz = [ Math.cos(this.rotation.z) * x - Math.sin(this.rotation.z) * y, Math.sin(this.rotation.z) * x + Math.cos(this.rotation.z) * y, z ]; ry = [ Math.cos(this.rotation.y) * rz[0] + Math.sin(this.rotation.y) * rz[2], rz[1], -Math.sin(this.rotation.y) * rz[0] + Math.cos(this.rotation.y) * rz[2] ]; rx = [ ry[0], Math.cos(this.rotation.x) * ry[1] - Math.sin(this.rotation.x) * ry[2], Math.sin(this.rotation.x) * ry[1] + Math.cos(this.rotation.x) * ry[2] ]; return rx; }; var tri = new Triangles(); requestAnimationFrame(function(start) { function step(t) { var delta = t-start; ctx.clearRect(0,0,100,100) tri.draw(delta); start = t; requestAnimationFrame(step); } step(start); }); 

As you can see it's using rotation matrices for calculating the position of the points after their rotation, and I'm using this to draw the triangles using the output x and y coordinates.

I want to take this a step further by using the z coordinate and adding perspective to this animation, which will make the triangles slightly bigger when in the foreground, and smaller when in the background. However, I'm not sure how to go about doing this.

I guess this is more of a maths question than a programming one, sorry about that!

Define a focal length to control the amount of perspective. The greater the value the less the amount of perspective. Then

var fl = 200; // focal length;
var px = 100; // point in 3D space
var py = 200;
var pz = 500;

Then to get the screen X,Y

var sx = (px * fl) / pz;
var sy = (py * fl) / pz;

The resulting point is relative to the center of the veiw so you need to center it to the canvas.

sx += canvas.width/2;
sy += canvas.height/2;

That is a point.

It assumes that the point being viewed is in front of the view and further than the focal length from the focal point.

I've managed to figure out a basic solution, but I'm sure there's better ones, so if you have a more complete answer feel free to add it! But for now...

Since the coordinate system is already based around the origin with the viewpoint directly on the Z axis looking at the (x,y) plane, it's actually sufficient to just multiply the (x,y) coordinates by a value proportional to z . For example, x * (z+2)/2 will do just fine in this case

There's bound to be a more proper, general solution though!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM