我有一个圆形的方形位图,我想计算该圆中所有像素的法线,就好像它是一个半径为1的球体:
球体/圆圈在位图中居中。
这个等式是什么?
答案 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个单位)。
从上面的链接中删除:
你必须结合两个方程式:
为此,计算你的光线(x *像素/宽度,y *像素/宽度,z:1),然后:
插入二次方程:
检查判别式(B ^ 2 - 4 * C),如果是实根,则交叉点为:
表面法线是:
将其全部烧掉:
所以,既然我们正在讨论单位值,并且直接指向Z
(没有x或y分量)的光线,我们可以大大简化这些方程式:
雷:
X0 = 2 * pixelX /宽度
Y0 = 2 *像素Y /高度
Z0 = 0
Xd = 0
Yd = 0
Zd = 1
击>
球形:
因素:
Ç
=(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
然后:
再次煮沸:
直观地看起来像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) ...
}