2

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

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

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

使用 6 个角度:

在此处输入图像描述

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

在此处输入图像描述

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

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

在此先感谢您的任何建议。

4

3 回答 3

2

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

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

这是描述二次曲线的表示和转换的链接

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

于 2011-02-04T22:18:02.230 回答
1

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

于 2011-02-06T22:58:33.223 回答
1

我花了几个小时,但我最终开发了所有方程和 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);
}
于 2014-10-09T22:40:59.157 回答