透视圆形形状的实用方法?

发布于 2024-10-16 01:58:38 字数 744 浏览 0 评论 0原文

不完全确定这是否应该属于 Stack Overflow,但这里是。

我正在使用 HTML5 对象创建 3D 井字游戏的简单版本。第一个玩家使用十字符号,而第二个玩家使用圆形符号。关键是我不知道如何透视圆形。

目前,我使用的方法是创建一个具有尽可能多角度(但在一定程度上)的正多边形,通过在这些点之间绘制直线来伪造一个圆。我使用正弦/余弦计算了这些点(角度)的坐标。

使用 6 个角度:

在此处输入图像描述

使用 50 个角度(看起来足够像一个圆):

在此处输入图像描述

这效果很好,但需要相当多的点才能很好地伪造一个圆。而且,如果我创造一个球,我就会遇到更多麻烦。例如,维基百科上的图片显示,即使有很多点,它仍然会有一个相当“块状”的表面:http://en.wikipedia.org/wiki/File:Sphere_wireframe.svg

我想知道是否有任何方法可以更有效地透视圆,也许没有点,以便能够以更实用的方式创建逼真的圆形形状。

预先感谢您的任何建议。

Not entirely sure if this should belong on Stack Overflow, but here goes.

I'm creating a simple version of tic-tac-toe in 3D using the HTML5 <canvas> object. The first player uses the cross symbol, whereas the second player uses the circle symbol. The point is that I'm not sure how to put circular shapes into perspective.

Currently, the method I'm using is creating a regular polygon with as many angles as possible (to a certain extent, though) to fake a circle by drawing straight lines between those points. The coordinates of these points (angles) I have calculated using sine / cosine.

Using 6 angles:

enter image description here

Using 50 angles (looks like a circle well enough):

enter image description here

This works well, but it requires quite a lot of points to fake a circle nicely. Moreover, if I were to create a ball, I'd be in more trouble. The picture at Wikipedia, for example, shows that even with a great deal of points, it would still have a rather 'blocky' surface: http://en.wikipedia.org/wiki/File:Sphere_wireframe.svg

I was wondering if there is any way to put a circle in perspective more effectively, perhaps without points, so as to be able to create a realistic looking circular shapes in a more practical way.

Thanks in advance for any suggestions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

独﹏钓一江月 2024-10-23 01:58:38

圆的多边形近似是实用的方法。计算坐标并对它们应用透视变换非常简单。您可能应该坚持该解决方案。

也就是说,如果您热衷于数学,那么您正在考虑的兔子洞非常酷。事实证明,所有二次曲面(包括球体和椭圆形)都可以用 4x4 矩阵表示。不仅如此,一旦转换为 4x4,您就可以应用所有标准 4x4 变换矩阵(不仅仅是乘法)。 IIRC 你甚至可以对它们应用透视变换,结果仍然是二次曲面。现在,这对您处理 3D 世界中的 2D 形状并没有多大帮助。但是,由于圆是圆柱体和平面的交集,并且两者都可以变换,因此应该有一个解决方案来解决您的问题。

这里是描述二次曲面的表示和变换的链接

正如您所展示的,圆形在地面上的透视投影通常是屏幕空间中的旋转椭圆。我没有变换方法,但我确实相信存在一种变换方法,并且比您现在所拥有的更复杂。

Your polygonal approximation of a circle is the practical way. It's very simple to compute coordinates and apply the perspective transformation to them. You should probably stick to that solution.

That said, the rabbit hole you're considering is VERY cool if you're into mathematical things. It turns out that all quadric surfaces - including spheres and ellipses - can be represented with a 4x4 matrix. Not only that, but once converted to a 4x4 you can apply all the standard 4x4 transformation matrices (it's not just a multiply). IIRC you can even apply the perspective transform to them and the result is still a quadric surface. Now that doesn't quite help you with 2D shapes in a 3d world. However, since a circle is the intersection of a cylinder and a plane and both can be transformed, there should be a solution to your problem.

Here is a link describing the representation and transformations of quadrics

As you have shown, the perspective projection of a circle on the ground is often a rotated ellipse in screen space. I do not have a transform method, but I do believe one exists and is more complex that what you've got now.

黯然#的苍凉 2024-10-23 01:58:38

从透视角度看,圆形是椭圆形。 这里有一个解释

A circle, when viewed in perspective, is an ellipse. Here's an explanation.

凉城已无爱 2024-10-23 01:58:38

我花了几个小时,但最终开发出了所有方程和 SVG 代码演示:
http://jsfiddle.net/6b8oLhz0/9/
我使用 http://mathworld.wolfram.com/Ellipse.html 来计算中心,半径和轴的旋转(仅给出其方程)。
代码中最有趣的部分可能是这样的:

function ellipseBy3DCircle(circle){
  var r=circle.radius;
  var n=circle.normal;
  var c=circle.center;
  //Let (u,v) be a point of the Ellipse.
  //Which point of the circle it represents?
  //This 3-D point must have a form of (u*z,v*z,z) for some z,
  //bacause it lays on a ray from observer (0,0,0) through (u,v,1) on the screen.
  //A circle is an intersection of a plane with a sphere.
  //So we have two conditions for our point :
  //1) it has to belong to the plane given by the center and normal of the circle:
  //(u*z-c.x)*n.x+  (v*z-c.y)*n.y + (z-c.z)*n.z = 0
  //2) it has to belong to the sphere given by the center and radius
  //(u*z-c.x)^2  +  (v*z-c.y)^2   + (z-c.z)^2   = 0
  //The first equation alows us to express z in terms of u,v and constants:
  //z =   (c.x*n.x+c.y*n.y+c.z*n.z) / (u*n.x+v*n.y+n.z) 
  //      ^^^^^^^^^^^^ s ^^^^^^^^^    ^^^^  t(u,v) ^^^^
  var s=c.x*n.x+c.y*n.y+c.z*n.z;
  //t(u,v)=u*n.x+v*n.y+n.z
  //The second equation gives us:
  //zz(uu+vv+1)-2z(u*c.x+v*c.y+z*c.z)+c.x^2+c.y^2+c.z^2-r^2 = 0
  //                                  ^^^^^^^^ H  ^^^^^^^^^
  var H=c.x*c.x+c.y*c.y+c.z*c.z-r*r;
  //Recall however, that z has u and v in denominator which makes it hard to solve/simplify.
  //But z=s/t(u,v), so let us multiply both sides by t(u,v)^2 :
  //ss*(uu+vv+1)-2*s*t(u,v)*(u*c.x+v*c.y+c.z)+t(u,v)^2*H=0
  //ss*uu+ss*vv+ss-2*s*(u*n.x+v*n.y+n.z)*(u*c.x+v*c.y+c.z)+(u*n.x+v*n.y+n.z)*(u*n.x+v*n.y+n.z)*H=0 
  //By regrouping terms so as to match the ax^2+2bxy+cy^2+2dx+2fy+g = 0 formula, we get:
  var A=s*s+H*n.x*n.x-2*s*n.x*c.x;
  var B=H*n.x*n.y-s*n.x*c.y-s*n.y*c.x;
  var C=s*s+H*n.y*n.y-2*s*n.y*c.y;
  var D=H*n.x*n.z-s*n.x*c.z-s*n.z*c.x;
  var F=H*n.y*n.z-s*n.y*c.z-s*n.z*c.y;
  var G=s*s+H*n.z*n.z-2*s*n.z*c.z;

  return ellipseByEquation(A,B,C,D,F,G);
}

It took me a few hours, but I've finnally developed all the equations and SVG code demo:
http://jsfiddle.net/6b8oLhz0/9/
I've used http://mathworld.wolfram.com/Ellipse.html to compute center, radii, and rotation of axis given it's equation only.
The most interesting part of the code is perhaps this:

function ellipseBy3DCircle(circle){
  var r=circle.radius;
  var n=circle.normal;
  var c=circle.center;
  //Let (u,v) be a point of the Ellipse.
  //Which point of the circle it represents?
  //This 3-D point must have a form of (u*z,v*z,z) for some z,
  //bacause it lays on a ray from observer (0,0,0) through (u,v,1) on the screen.
  //A circle is an intersection of a plane with a sphere.
  //So we have two conditions for our point :
  //1) it has to belong to the plane given by the center and normal of the circle:
  //(u*z-c.x)*n.x+  (v*z-c.y)*n.y + (z-c.z)*n.z = 0
  //2) it has to belong to the sphere given by the center and radius
  //(u*z-c.x)^2  +  (v*z-c.y)^2   + (z-c.z)^2   = 0
  //The first equation alows us to express z in terms of u,v and constants:
  //z =   (c.x*n.x+c.y*n.y+c.z*n.z) / (u*n.x+v*n.y+n.z) 
  //      ^^^^^^^^^^^^ s ^^^^^^^^^    ^^^^  t(u,v) ^^^^
  var s=c.x*n.x+c.y*n.y+c.z*n.z;
  //t(u,v)=u*n.x+v*n.y+n.z
  //The second equation gives us:
  //zz(uu+vv+1)-2z(u*c.x+v*c.y+z*c.z)+c.x^2+c.y^2+c.z^2-r^2 = 0
  //                                  ^^^^^^^^ H  ^^^^^^^^^
  var H=c.x*c.x+c.y*c.y+c.z*c.z-r*r;
  //Recall however, that z has u and v in denominator which makes it hard to solve/simplify.
  //But z=s/t(u,v), so let us multiply both sides by t(u,v)^2 :
  //ss*(uu+vv+1)-2*s*t(u,v)*(u*c.x+v*c.y+c.z)+t(u,v)^2*H=0
  //ss*uu+ss*vv+ss-2*s*(u*n.x+v*n.y+n.z)*(u*c.x+v*c.y+c.z)+(u*n.x+v*n.y+n.z)*(u*n.x+v*n.y+n.z)*H=0 
  //By regrouping terms so as to match the ax^2+2bxy+cy^2+2dx+2fy+g = 0 formula, we get:
  var A=s*s+H*n.x*n.x-2*s*n.x*c.x;
  var B=H*n.x*n.y-s*n.x*c.y-s*n.y*c.x;
  var C=s*s+H*n.y*n.y-2*s*n.y*c.y;
  var D=H*n.x*n.z-s*n.x*c.z-s*n.z*c.x;
  var F=H*n.y*n.z-s*n.y*c.z-s*n.z*c.y;
  var G=s*s+H*n.z*n.z-2*s*n.z*c.z;

  return ellipseByEquation(A,B,C,D,F,G);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文