不完全确定这是否应该属于Stack Overflow,但是这里有。
我正在使用HTML5 <canvas>
对象在3D中创建一个简单的tic-tac-toe版本。第一个玩家使用十字符号,而第二个玩家使用圆圈符号。关键是我不确定如何将圆形形状放入透视中。
目前,我正在使用的方法是创建一个具有尽可能多的角度的正多边形(尽管在某种程度上),通过在这些点之间绘制直线来伪造圆形。我用正弦/余弦计算的这些点(角度)的坐标。
使用6个角度:
使用50个角度(看起来像一个圆圈):
这很好用,但要很好地伪造一个圆圈需要很多点。而且,如果我要创造一个球,我会遇到更多麻烦。例如,维基百科上的图片显示,即使有很多分数,它仍然会有一个相当“块状”的表面:http://en.wikipedia.org/wiki/File:Sphere_wireframe.svg
我想知道是否有任何方法可以更有效地放置圆形透视,也许没有点,以便能够以更实际的方式创建逼真的圆形形状。
提前感谢任何建议。
答案 0 :(得分:2)
圆形的多边形近似是实用的方法。计算坐标并将透视变换应用于它们非常简单。你应该坚持这个解决方案。
那就是说,你正在考虑的兔子洞非常酷,如果你是数学的东西。事实证明,所有二次曲面 - 包括球体和椭圆 - 都可以用4x4矩阵表示。不仅如此,一旦转换为4x4,您可以应用所有标准的4x4转换矩阵(它不仅仅是乘法)。 IIRC你甚至可以对它们应用透视变换,结果仍然是二次曲面。现在,这对3D世界中的2D形状没有多大帮助。但是,由于圆是圆柱体和平面的交点,并且两者都可以变换,因此应该可以解决问题。
Here is a link describing the representation and transformations of quadrics
如图所示,圆形在地面上的透视投影通常是屏幕空间中的旋转椭圆。我没有变换方法,但我相信一个存在并且比你现在所拥有的更复杂。
答案 1 :(得分:1)
从透视角度看,圆是椭圆形。 Here's an explanation
答案 2 :(得分: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);
}