从2D点计算单位球面上的3D坐标

时间:2011-08-28 08:43:38

标签: math graphics geometry

我有一个圆形的方形位图,我想计算该圆中所有像素的法线,就好像它是一个半径为1的球体:

enter image description here

球体/圆圈在位图中居中。

这个等式是什么?

4 个答案:

答案 0 :(得分:8)

不太了解人们如何编写3D内容,所以我只是给出纯数学并希望它有用。

半径为1的球体,以原点为中心,是满足以下条件的点集:

  

x 2 + y 2 + z 2 = 1

我们想要球体上一个点的三维坐标,其中x和y是已知的。所以,只需解决z:

  

z =±sqrt(1 - x 2 - y 2 )。

现在,让我们考虑一个从球体向外指向的单位向量。它是一个单位球体,所以我们可以使用从原点到(x,y,z)的向量,当然,它是< x,y,z&gt ;.

现在我们想要一个与球体在(x,y,z)处相切的平面方程,但是这将使用它自己的x,y和z变量,所以我将使它与球体相切at(x 0 ,y 0 ,z 0 )。这很简单:

  

x 0 x + y 0 y + z 0 z = 1

希望这有帮助。


(OP):

你的意思是:

const int R = 31, SZ = power_of_two(R*2);
std::vector<vec4_t> p;
for(int y=0; y<SZ; y++) {
    for(int x=0; x<SZ; x++) {
        const float rx = (float)(x-R)/R, ry = (float)(y-R)/R;
        if(rx*rx+ry*ry > 1) { // outside sphere
            p.push_back(vec4_t(0,0,0,0));
        } else {
            vec3_t normal(rx,sqrt(1.-rx*rx-ry*ry),ry);
            p.push_back(vec4_t(normal,1));
        }
    }
}

如果我将法线视为颜色并将其视为blit,它确实会形成一个漂亮的球形着色阴影;是不是?


(TZ)

抱歉,我不熟悉C ++的这些方面。最近没有使用过这门语言。

答案 1 :(得分:1)

显然,由于缺少维度,你只能将所有点都放在球体的一半或类似物上。过去,这很简单。

圆的中间有一个法线正好面向或向外,垂直于绘制圆的平面。

圆圈边缘的每个点都背对着中间,因此你可以计算出它的法线。

对于中间和边缘之间的任何点,你使用距离中间的距离,以及一些简单的触发(此刻我不能使用)。 lerp在某些点上大致准确,但不是你需要的,因为它是一条曲线。虽然简单的曲线,你知道开始和结束的值,所以搞清楚它们应该只采用一个简单的方程式。

答案 2 :(得分:1)

我想我得到了你想要做的事情:为图像生成深度数据网格。有点像射线追踪球体。

在这种情况下,您需要Ray-Sphere Intersection测试:

http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter1.htm

你的光线将是简单的垂直光线,基于你的U / V坐标(第二次,因为你的球体直径为2)。这将为您提供球体上的前向点。

从那里计算法线如下(point - origin,半径已经是1个单位)。

从上面的链接中删除:

你必须结合两个方程式:

  • Ray:R(t)= R0 + t * Rd,t> 0,R0 = [X0,Y0,Z0]和Rd = [Xd,Yd,Zd]
  • 球体:S =点集[xs,ys,zs],其中(xs - xc)2 +(ys - yc)2 +(zs - zc)2 = Sr2

为此,计算你的光线(x *像素/宽度,y *像素/宽度,z:1),然后:

  • A = Xd ^ 2 + Yd ^ 2 + Zd ^ 2
  • B = 2 *(Xd *(X0-Xc)+ Yd *(Y0-Yc)+ Zd *(Z0-Zc))
  • C =(X0-Xc)^ 2 +(Y0-Yc)^ 2 +(Z0-Zc)^ 2-Sr ^ 2

插入二次方程:

  • t0,t1 =( - B +(B ^ 2 - 4 * C)^ 1/2)/ 2

检查判别式(B ^ 2 - 4 * C),如果是实根,则交叉点为:

  • Ri = [xi,yi,zi] = [x0 + xd * ti,y0 + yd * ti,z0 + zd * ti]

表面法线是:

  • SN = [(xi - xc)/ Sr,(yi - yc)/ Sr,(zi - zc)/ Sr]

将其全部烧掉:

所以,既然我们正在讨论单位值,并且直接指向Z(没有x或y分量)的光线,我们可以大大简化这些方程式:

雷:

  • X0 = 2 * pixelX /宽度
    Y0 = 2 *像素Y /高度
    Z0 = 0

  • Xd = 0
    Yd = 0
    Zd = 1

球形:

  • Xc = 1
    Yc = 1
    Zc = 1

因素:

  • A = 1(单位光线)
  • <击>乙
    = 2 *(0 + 0 +(0 - 1))
    = -2(无x / y分量)
  • Ç
    =(X0-1)^ 2 +(Y0-1)^ 2 +(0-1)^ 2-1 =(X0-1)^ 2 +(Y0-1)^ 2

  • 判别
    =( - 2)^ 2 - 4 * 1 * C
    = 4 - 4 * C

从这里开始:

If discriminant < 0:
  Z = ?, Normal = ?
Else:
  t = (2 + (discriminant) ^ 1 / 2) / 2
If t < 0 (hopefully never or always the case)
  t = -t

然后:

  • Z:t
  • Nx:Xi - 1
    Ny:Yi - 1
    Nz:t - 1

再次煮沸:

直观地看起来像C(X^2 + Y^2)和平方根是这里最突出的数字。如果我对数学有更好的回忆(特别是对指数的变换),那么我敢打赌,我可以将其归结为Tom Zych给你的数学。由于我不能,我会把它留在上面。

答案 3 :(得分:1)

此公式通常用于“假冒envmapping”效果。

double x = 2.0 * pixel_x / bitmap_size - 1.0;
double y = 2.0 * pixel_y / bitmap_size - 1.0;
double r2 = x*x + y*y;
if (r2 < 1)
{
    // Inside the circle
    double z = sqrt(1 - r2);
    .. here the normal is (x, y, z) ...
}