为什么人们在 OpenGL 的距离函数上使用 sqrt(dot(distanceVector, distanceVector))?

Why do people use sqrt(dot(distanceVector, distanceVector)) over OpenGL's distance function?

在使用 ShaderToy 时,我经常看到人们使用类似的东西:

vec2 uv = fragCoord / iResolution;
vec2 centerPoint = vec2(0.5);

vec2 distanceVector = uv - centerPoint;
float dist = sqrt(dot(distanceVector, distanceVector));

关于 OpenGL 的 distance 函数:

vec2 uv = fragCoord / iResolution;
vec2 centerPoint = vec2(0.5);

float dist = distance(uv, centerPoint);

我很好奇为什么会这样(我的猜测是它与速度或对 distance 的支持有关)。

我大致理解如果参数相同,点积的平方根等于向量的长度:距离?

做基本相同的事情,人们通常出于以下两个原因之一选择 sqrt 选项: 1.他们不知道about/remember距离函数 2. 他们相信自己和自己的数学来证明导致错误不是问题(避免 OpenGL 问题)

使用点可以让您快速试验 quadratic/linear 距离函数。

根据 The Book of Shaderdistence()length() 在内部使用平方根 (sqrt())。使用 sqrt() 和所有依赖于它的功能可能会很昂贵。尽可能使用 dot()

我猜sqrt()是一个数学计算,但是dot()是一个矢量计算,GPU是擅长.

有时为了光量优化提前退出:

float distSquared( vec3 A, vec3 B )
{

    vec3 C = A - B;
    return dot( C, C );

}

// Early escape when the distance between the fragment and the light 
// is smaller than the light volume/sphere threshold.
//float dist = length(lights[i].Position - FragPos);
//if(dist < lights[i].Radius)
// Let's optimize by skipping the expensive square root calculation
// for when it's necessary.
float dist = distSquared( lights[i].Position, FragPos );
if( dist < lights[i].Radius * lights[i].Radius )
{ 
 
    // Do expensive calculations.

如果您稍后需要distance,只需:

dist = sqrt( dist )

编辑:另一个例子。

我最近了解到的另一个用例,假设您想要两个位置:vec3 posOnevec3 posTwo,并且您想要到每个位置的距离。天真的方法是独立计算它们:float distanceOne = distance( posOne, otherPos )float distanceTwo = distance( posTwo, otherPos )。但是你想利用 SIMD!所以你这样做:posOne -= otherPos; posTwo -= otherPos 所以你准备好通过 SIMD 计算欧氏距离:vec2 SIMDDistance = vec2( dot( posOne ), dot( posTwo ) ); 然后你可以使用 SIMD 求平方根:SIMDDistance = sqrt( SIMDDistance ); 其中到 posOne 的距离在SIMDDistance 变量的 .x 分量和 .y 分量包含到 posTwo 的距离。

我经常做的是以下(例子):

vec3 vToLight = light.pos - cam.pos;
float lengthSqToLight = dot(vToLight, vToLight);
if (lengthSqToLight > 0 && lengthSqToLight <= maxLengthSq) {
    float lengthToLight = sqrt(lengthSqToLight); // length is often needed later
    ...
    vec3 vToLightNormalized = vToLight / lengthToLight; // avoid normalize() => avoids second sqrt
    ...
    // later use lengthToLight
}