我正在尝试在我的光线追踪器中为球体实现纹理.我设法得到了一些工作,但我不确定它的正确性.下面是获取纹理坐标的代码.目前,纹理是随机的,并在运行时生成.
virtual void GetTextureCoord(Vect hitPoint, int hres, int vres, int& x, int& y) {
float theta = acos(hitPoint.getVectY());
float phi = atan2(hitPoint.getVectX(), hitPoint.getVectZ());
if (phi < 0.0) {
phi += TWO_PI;
}
float u = phi * INV_TWO_PI;
float v = 1 - theta * INV_PI;
y = (int) ((hres - 1) * u);
x = (int) ((vres - 1) * v);
}
Run Code Online (Sandbox Code Playgroud)
这就是球体现在的样子:

我不得不规范化生命点的坐标以使球体看起来像那样.否则他们看起来像:

将命中点坐标正规化为正确的方法,还是我的代码中的其他东西被破坏了?谢谢!
我尝试将其翻译为世界原点(就好像球体中心在那里)而不是标准化生命点,并获得以下结果:

顺便说一句,我使用256x256分辨率纹理.
目前尚不清楚您所说的“正常化”生命值是什么意思,因为您发布的代码中没有任何内容可以将其正常化,但您提到您的生命值位于世界空间中。
另外,您没有说明您想要实现什么纹理映射,但我假设您希望 U 和 V 纹理坐标来表示球体表面上的纬度和经度。
您的第一个问题是将笛卡尔坐标转换为球坐标要求球体以笛卡尔空间中的原点为中心,这在世界空间中是不正确的。如果击中点位于世界空间中,则必须减去球体的世界空间中心点才能获得局部坐标中的有效击中点。(您已经弄清楚了这一部分,并用新图像更新了问题。)
第二个问题是,您的计算方式theta要求球体的半径为 1,即使将球体的中心移动到原点,这也是不正确的。记住你的三角函数: 的参数acos是三角形边与其斜边的比率,并且始终在 (-1, +1) 范围内。在这种情况下,Y 坐标是边,球体的半径是斜边。因此,调用时必须除以球体的半径acos。将值限制在 (-1, +1) 范围内也是一个好主意,以防浮点舍入误差使其稍微超出范围。
(原则上,您还必须将 X 和 Z 坐标除以半径,但您仅将它们用于反正切,并且将它们除以半径不会改变它们的商,因此也不会改变phi.)
现在,您的球体交集和纹理坐标函数正在世界空间中运行,但您可能会发现稍后实现变换矩阵很有用,它可以让您将事物从一个坐标空间变换到另一个坐标空间。然后,您可以更改球体函数,使其在以原点为中心、半径为 1 的局部坐标空间中运行,并为每个对象提供一个关联的变换矩阵,将局部坐标空间映射到世界坐标空间。这将简化您的射线/球体相交代码,并让您删除原点减法和半径除法GetTextureCoord(因为它们始终分别为 (0, 0, 0) 和 1)。
要将射线与对象相交,您需要使用对象的变换矩阵将射线变换到对象的局部坐标空间,在那里进行相交(并计算纹理坐标),然后变换结果(例如,命中点和表面法线) )回到世界空间。
| 归档时间: |
|
| 查看次数: |
913 次 |
| 最近记录: |