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

问题描述 投票:0回答:5

使用 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
的支持有关)。

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

opengl-es glsl shader webgl
5个回答
17
投票

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


7
投票

有时为了优化早期退出,例如轻量:

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 posOne
vec3 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 的距离。


2
投票

根据The Book of Shader

distance()
length()
在内部使用
sqrt()
。使用
sqrt()
以及依赖它的所有功能可能会很昂贵。如果可能的话就使用
dot()

我猜

sqrt()
数学计算,但是
dot()
是GPU擅长的向量计算


1
投票

使用 dot 为您提供了一种快速实验距离的二次/线性函数的方法。


1
投票

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

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
}
© www.soinside.com 2019 - 2024. All rights reserved.