简体   繁体   English

为假的3D动画添加透视图

[英]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. 我正在基于画布的动画上工作,并且试图在2D画布中获得3D效果。

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. 如您所见,它使用旋转矩阵来计算点旋转后的位置,而我使用它来使用输出的x和y坐标绘制三角形。

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. 我想通过使用z坐标并向此动画中添加透视图来使这一步骤更进一步,这将使三角形在前景时变大,而在背景时变小。 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 然后得到屏幕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 . 由于坐标系已经基于原点,并且视点直接位于Z轴上,看着(x,y)平面,因此只需将(x,y)坐标乘以与z成正比的值就足够了。 For example, x * (z+2)/2 will do just fine in this case 例如,在这种情况下, x * (z+2)/2就可以了

There's bound to be a more proper, general solution though! 当然,肯定会有一个更合适的通用解决方案!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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