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

5

21

When using ShaderToy I often see people using something like:

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

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

over OpenGL's distance function:

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

float dist = distance(uv, centerPoint);

I'm just curious why this is (my guess is that it has something to do with speed or support for distance).

I loosely understand that if the arguments are the same, the square root of a dot product equals the length of the vector: the distance?

Wingspread answered 30/6, 2016 at 1:24 Comment(0)
D
17

Doing essentially the same thing, people often choose the sqrt option for one of two reasons: 1. They don't know about/remember the distance function 2. They are trusting themselves and their own math to prove that is not a problem to cause a bug (avoiding OpenGL problems)

Duplessismornay answered 30/6, 2016 at 1:29 Comment(1)
Is it faster? or can you compare two function cycles?Niels
T
7

Sometimes to optimize early exits as for light volumes for example:

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.

If you need the distance later on simply:

dist = sqrt( dist )

EDIT: Another example.

Another use case that I've recently learnt, suppose that you want to have two positions: vec3 posOne and vec3 posTwo and you want the distance to each of those. The naive way would be to compute them independently: float distanceOne = distance( posOne, otherPos ) and float distanceTwo = distance( posTwo, otherPos ). But you want to exploit SIMD! So you do: posOne -= otherPos; posTwo -= otherPos so you are ready to compute the euclidean distance by SIMD: vec2 SIMDDistance = vec2( dot( posOne ), dot( posTwo ) ); and you can then use SIMD for the square root: SIMDDistance = sqrt( SIMDDistance ); where the distance to posOne is on the .x component of the SIMDDistance variable and the .y component contains the distance to posTwo.

Tabatha answered 26/7, 2020 at 4:26 Comment(0)
A
2

According to The Book of Shader, distance() and length() use sqrt() internally. Using sqrt() and all the functions depend on it can be expensive. Just use dot() if possible!

I guess sqrt() is a mathematical computation, but dot() is a vector computation which GPU is good at.

Admittedly answered 23/7, 2020 at 12:9 Comment(2)
This is true, but the question was about sqrt(dot(...)) vs distance(...). In the scenarios they mention, the sqrt is not being avoided. So this isn't really an answer to the question, and more is a sort of tangential comment. I might be more inclined to consider it an answer to the question if you have some suggestions of specific scenarios where you could switch from distance and avoid the sqrt. One that comes to mind is if you know the maximum distance that might be involved, and are looking for a ratio, and are OK with a non-linear result. Or if doing a < or > check.Givens
just say something detail of the question, lol. distance(...) is really more semanticAdmittedly
L
1

Using dot gives you a quick way to experiment with quadratic/linear function of distance.

Lemma answered 26/6, 2020 at 7:17 Comment(0)
J
1

What I often do is the following (example):

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
}
Judie answered 25/7, 2021 at 10:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.