我目前正在使用一种采样方法来跟踪射线,并且使用以下代码对半球上的一个随机点进行采样并输出一个 vector :
vec3 CosWeightedRandomHemisphereDirection( vec3 n, float rand1, float rand2 )
{
float Xi1 = rand1;
float Xi2 = rand2;
float theta = acos(sqrt(1.0-Xi1));
float phi = 2.0 * 3.1415926535897932384626433832795 * Xi2;
float xs = sin(theta) * cos(phi);
float ys = cos(theta);
float zs = sin(theta) * sin(phi);
vec3 y = n;
vec3 h = y;
if (abs(h.x)<=abs(h.y) && abs(h.x)<=abs(h.z))
h.x= 1.0;
else if (abs(h.y)<=abs(h.x) &&abs(h.y)<=abs(h.z))
h.y= 1.0;
else
h.z= 1.0;
vec3 x = normalize(cross(h,y));
vec3 z = normalize(cross(x,y));
vec3 direction = xs * x + ys * y + zs * z;
return normalize(direction);
}
现在,如果我希望样本相对于半球始终处于固定位置,例如those vectors,它们是从半球以60°采样的,那么我该如何修改代码?我将 vector 保存在数组中。
所以我的函数会有一个标题
vec3 FixedHemisphereDirection( vec3 n, vec3 sampleDir)
其中sampleDir是6个固定方向之一
另外,由于位置将被固定,代码是否可以优化?
编辑:
我注意到方向仅适用于向上或向下的法线,而其余方向则不起作用(花了我一段时间才注意到,因为我一直使用随机方向)。这是我现在正在使用的代码。
vec3 FixedHemisphereDirection( vec3 n, vec3 sampleDir)
{
vec3 x;
vec3 z;
if(abs(n.x) < abs(n.y)){
if(abs(n.x) < abs(n.z)){
x = vec3(1.0f,0.0f,0.0f);
}else{
x = vec3(0.0f,0.0f,1.0f);
}
}else{
if(abs(n.y) < abs(n.z)){
x = vec3(0.0f,1.0f,0.0f);
}else{
x = vec3(0.0f,0.0f,1.0f);
}
}
z = normalize(cross(x,n));
x = cross(n,z);
mat3 M = mat3( x.x, n.x, z.x,
x.y, n.y, z.y,
x.z, n.z, z.z);
return M*sampleDir;
}
最佳答案
单个法线不足以唯一地识别半球的局部坐标系。它可以围绕该法线沿任何方向旋转。
我们首先需要构造局部坐标系。因此,我们需要局部的x和z轴。 y轴已经由法线给出。所有轴应彼此正交。因此,我们可以执行以下操作:
x := (1, 0, 0)
z := normalize(cross(x, n))
x := cross(n, z)
如果法线与
(1, 0, 0)
平行,则应选择另一个x轴,因为叉积将为零。从这些轴,我们可以构造一个转换矩阵:
/ x.x n.x z.x \
M := | x.y n.y z.y |
\ x.z n.z z.z /
这是将六个给定方向转换为
n
指定的半球方向的矩阵。dir := randomly pick on of the six directions
return M * dir