优化球体折叠函数(GLSL)
Optimizing sphere fold function (GLSL)
有一个球体折叠函数,它根据与原点的距离变换 space。有两个常量参数:fR2
和 mR2
。该函数如下所示:
const float fR2 = 1.0;
const float mR2 = 0.25;
vec3 s_fold(in vec3 v) {
float mag = dot(v, v);
if (mag < mR2)
{
v = v * fR2 / mR2;
}
else if (mag < fR2)
{
v = v * fR2 / mag;
}
return v;
}
可以用,但是因为if-else分支,所以运行很慢。如果我使用 step
函数,可以去掉分支:
float a = step(mR2 , mag);
float b = step(fR2 , mag);
float sc = dot( vec3(
1.0-a,
a*(1.0-b),
b
), vec3(
fR2 / mR2,
fR2 / mag,
1.0)
);
return sc*v;
现在速度快了一点,但我想进一步优化它。我找到了 one-line solution,但它给了我不同的结果:
return v*clamp(max(mR2/mag,mR2),0.0,fR2);
我不清楚,怎么可能用一个 clamp
.
来计算
您的 if-else 分支是类似于 res= v * F
的函数,其中 F
是三个可能值之一:常量 (fR2/mR2)、(双曲线)变量 (fR2/mag),又是一个常数 (1.0)。
clamp(x, minVal, maxVal)
执行相同的逻辑 (const-var-const)。所以你可以这样写:
res = v * clamp(fR2/mag, 1.0, fR2/mR2); //with fR2 >= mR2
换个方式写吧:
res = v * fR2 * clamp(1.0/mag, 1.0/fR2, 1.0/mR2);
我们可以避免两次除法因为1/mR2 <= 1/fR2
意味着fR2 >= mR2
res = v * fR2 / clamp(mag, mR2, fR2);
最终代码为
const float fR2 = 1.0;
const float mR2 = 0.25;
vec3 s_fold(in vec3 v) {
return v * fR2 / clamp(dot(v, v), mR2, fR2);
}
当 mag=0
时,您的解决方案和发布的 "liner" 都可能被零除
有一个球体折叠函数,它根据与原点的距离变换 space。有两个常量参数:fR2
和 mR2
。该函数如下所示:
const float fR2 = 1.0;
const float mR2 = 0.25;
vec3 s_fold(in vec3 v) {
float mag = dot(v, v);
if (mag < mR2)
{
v = v * fR2 / mR2;
}
else if (mag < fR2)
{
v = v * fR2 / mag;
}
return v;
}
可以用,但是因为if-else分支,所以运行很慢。如果我使用 step
函数,可以去掉分支:
float a = step(mR2 , mag);
float b = step(fR2 , mag);
float sc = dot( vec3(
1.0-a,
a*(1.0-b),
b
), vec3(
fR2 / mR2,
fR2 / mag,
1.0)
);
return sc*v;
现在速度快了一点,但我想进一步优化它。我找到了 one-line solution,但它给了我不同的结果:
return v*clamp(max(mR2/mag,mR2),0.0,fR2);
我不清楚,怎么可能用一个 clamp
.
您的 if-else 分支是类似于 res= v * F
的函数,其中 F
是三个可能值之一:常量 (fR2/mR2)、(双曲线)变量 (fR2/mag),又是一个常数 (1.0)。
clamp(x, minVal, maxVal)
执行相同的逻辑 (const-var-const)。所以你可以这样写:
res = v * clamp(fR2/mag, 1.0, fR2/mR2); //with fR2 >= mR2
换个方式写吧:
res = v * fR2 * clamp(1.0/mag, 1.0/fR2, 1.0/mR2);
我们可以避免两次除法因为1/mR2 <= 1/fR2
意味着fR2 >= mR2
res = v * fR2 / clamp(mag, mR2, fR2);
最终代码为
const float fR2 = 1.0;
const float mR2 = 0.25;
vec3 s_fold(in vec3 v) {
return v * fR2 / clamp(dot(v, v), mR2, fR2);
}
当 mag=0