<p>Your <em>actual</em> result is correct in terms of what you can achieve in a single-pass with a fragment shader. It calculates the distance of the fragment's world position to the line segment. That distance is <strong>different for each fragment</strong> so the stretched black ellipsoid is the correct output.</p>

<p>A fragment shader has only local information about the current fragment being processed. You can't do more with that. Your <em>expected</em> result requires some global knowledge about the scene, since you are searching for the <strong>minimum distance across the whole surface</strong>.</p>

<p>Without any thoughts on optimization, the naive solution path should involve contextual computation of local minima of the fragment-to-linesegment distance. In order to get such context, you need to compute the distance field first and then access it to find the local minima in a separate pass.</p>

<ol>
<li>Compute the raw distance field in the first pass (same as your example but no <code>radius</code> subtraction at the end.</li>
<li>Mark the pixels with local minima in the second pass (e.g. by setting the alpha channel to 1). This will be screen-space pass. The best is to have a <code>rgba</code> float texture at output with <code>rgb</code> being fragment's world position and <code>a</code> being 1 for local minima and <code>0</code> else.</li>
<li>Paint the black circles/spheres in a third pass (also screen-space).</li>
</ol>

<p>Having the information about the local minimum of your distance function enables you to output the right shape for around the minima in the last pass. In pseudocode:</p>

<pre class="lang-glsl prettyprint-override"><code>vec4 worldPos = tex2D(distance_texture, frag.x, frag.y);
if (worldPos.a &gt; 0.5) //is minimum
    return vec3(0,0,0);
else
{
    //Sample the screen-space neighborhood in larger and larger circles
    // until a fragment with distance.a == 1 is found
    // or until all fragments are more than radius away (in world coords).

    //Minimum world space distance of any sampled fragment.
    float minDist = 0.0;
    int iter = 1;
    //Search for a local minimum until all fragments are more than radius away,
    // since then even if a local minimum gets found it will no longer produce
    // the black shading.
    while (minDist &lt; radius &amp;&amp; minDist &gt;= 0.0 &amp;&amp; iter &lt; Math.Max(screenWidth, screenHeight))
        minDist = sampleNeighborhood(iter++, worldPos);

    if (minDist &lt; 0.0) //found a local minimum
        return vec3(0,0,0);
    else
        return vec3(1,1,1); //or any other computed shading

    //I am aware that the function call above checks central fragments several times.
    //That should be of course optimized in production code.
}

float sampleNeighborhood(int neigh, vec4 worldPos)
{
    float minDist = float.MaxValue;
    for(int x = Math.max(0, frag.x - neigh); x &lt;= Math.Min(screenWidth, frag.x + neigh; ++x)
        for(int y = Math.max(0, frag.y - neigh); x &lt;= Math.Min(screenHeight, frag.y + neigh; ++y)
        {
            float p = tex2D(distance_texture, x, y);
            float d = distance(p.xyz, worldPos.xyz);
            if (p.a &gt; 0.5 &amp;&amp; d &lt;= radius)
                //Return negative distance to indicate a local minimum was found.
                return -1.0; 
            else
                minDist = Math.min(minDist, d);
        }
    return minDist;
}
</code></pre>

<p>Finding the local minima in the second pass is much easier, since you only need to sample the local 3x3 neighborhood.</p>

<p>I hope that helps you in reaching the desired rendering!</p>

CC BY-SA 4.0
2020-06-11T12:15:28.163Z
Notice, that the same question is also on the game development site: [link](https://gamedev.stackexchange.com/questions/183427/closest-sphere-on-segment). I wasn't sure how to handle this, so I found this [Meta question](https://meta.stackexchange.com/questions/172307/duplicate-questions-on-other-se-sites) - Long story short: Maybe you could provide your answer there too by copying or linking it (Don't want to farm reputation that you earned ;) ).
wychmaster
CC BY-SA 4.0
2020-06-11T12:25:05.517Z
Thank you :) Haha it automatically converted it to a comment stating that it is trivial :)
Isolin
CC BY-SA 4.0
2020-06-11T11:52:32.100Z
2020-06-11T13:09:36.263Z
2020-06-11T13:09:36.263Z
Isolin
<p>I am trying to get a segment closest point on a surface and display a circle (or sphere in this case) at that position.</p>

<p>I actually get the correct position but I can't get a uniform sphere based on the computed data.</p>

<p><a href="https://i.sstatic.net/fdhyQ.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/fdhyQ.jpg" alt="enter image description here"></a></p>

<p>Here's the associated code I use to find the intersection point and draw the sphere.</p>

<pre><code>float3 a = from;
float3 b = to;
float3 c = worldPosition;

float3  ab = b - a;
float t = dot(c - a, ab) / dot(ab, ab);
float3 point = a + saturate(t) * ab;

return length(point - worldPosition) - radius;
</code></pre>

CC BY-SA 4.0
2020-06-11T10:29:40.110Z
I don't fully understand your question. You have a line segment and you are trying to use a fragment shader to display kind-of a clipped distance field on the mesh surface?
Isolin
CC BY-SA 4.0
2020-06-11T11:02:44.443Z
Thanks for your answer. I have a line segment and I compute the surface intersection closest point using the cylinder fragment shader. Using this closest segment point I compute a sphere distance field. Everything is done in world space.
MaT
CC BY-SA 4.0
2020-06-11T11:04:39.113Z
Should there be a black circle displayed also when there is no true intersection but only strong proximity?
Isolin
CC BY-SA 4.0
2020-06-11T11:09:54.760Z
I'm not sure to understand, the main issue is the deformation of the computed length which should be uniform. I guess that there should be a black circle when there's no true intersection because it illustrates the distance but it should be uniform.
MaT
CC BY-SA 4.0
2020-06-11T11:13:10.580Z
Got it, I will try to answer the question accordingly.
Isolin
<shader><glsl><mathematics><hlsl><signed-distance-field>
Closest sphere on segment
MaT
# Closest sphere on segment

(Asked by: username_0 on 2020-06-11)

I am trying to get a segment closest point on a surface and display a circle (or sphere in this case) at that position.
I actually get the correct position but I can't get a uniform sphere based on the computed data.

Here's the associated code I use to find the intersection point and draw the sphere.
float3 a = from;
float3 b = to;
float3 c = worldPosition;

float3  ab = b - a;
float t = dot(c - a, ab) / dot(ab, ab);
float3 point = a + saturate(t) * ab;

return length(point - worldPosition) - radius;

**Tags:** shader, glsl, mathematics, hlsl, signed-distance-field
> **Comments:**
> **username_1**: I don't fully understand your question. You have a line segment and you are trying to use a fragment shader to display kind-of a clipped distance field on the mesh surface?  
> **username_0**: Thanks for your answer. I have a line segment and I compute the surface intersection closest point using the cylinder fragment shader. Using this closest segment point I compute a sphere distance field. Everything is done in world space.  
> **username_1**: Should there be a black circle displayed also when there is no true intersection but only strong proximity?  
> **username_0**: I'm not sure to understand, the main issue is the deformation of the computed length which should be uniform. I guess that there should be a black circle when there's no true intersection because it illustrates the distance but it should be uniform.  
> **username_1**: Got it, I will try to answer the question accordingly.  

---

## 1 answers

### Answer by username_1 on 2020-06-11. Score: 2

Your actual result is correct in terms of what you can achieve in a single-pass with a fragment shader. It calculates the distance of the fragment's world position to the line segment. That distance is different for each fragment so the stretched black ellipsoid is the correct output.
A fragment shader has only local information about the current fragment being processed. You can't do more with that. Your expected result requires some global knowledge about the scene, since you are searching for the minimum distance across the whole surface.
Without any thoughts on optimization, the naive solution path should involve contextual computation of local minima of the fragment-to-linesegment distance. In order to get such context, you need to compute the distance field first and then access it to find the local minima in a separate pass.

Compute the raw distance field in the first pass (same as your example but no radius subtraction at the end.
Mark the pixels with local minima in the second pass (e.g. by setting the alpha channel to 1). This will be screen-space pass. The best is to have a rgba float texture at output with rgb being fragment's world position and a being 1 for local minima and 0 else.
Paint the black circles/spheres in a third pass (also screen-space).

Having the information about the local minimum of your distance function enables you to output the right shape for around the minima in the last pass. In pseudocode:
vec4 worldPos = tex2D(distance_texture, frag.x, frag.y);
if (worldPos.a > 0.5) //is minimum
    return vec3(0,0,0);
else
{
    //Sample the screen-space neighborhood in larger and larger circles
    // until a fragment with distance.a == 1 is found
    // or until all fragments are more than radius away (in world coords).

    //Minimum world space distance of any sampled fragment.
    float minDist = 0.0;
    int iter = 1;
    //Search for a local minimum until all fragments are more than radius away,
    // since then even if a local minimum gets found it will no longer produce
    // the black shading.
    while (minDist < radius && minDist >= 0.0 && iter < Math.Max(screenWidth, screenHeight))
        minDist = sampleNeighborhood(iter++, worldPos);

    if (minDist < 0.0) //found a local minimum
        return vec3(0,0,0);
    else
        return vec3(1,1,1); //or any other computed shading

    //I am aware that the function call above checks central fragments several times.
    //That should be of course optimized in production code.
}

float sampleNeighborhood(int neigh, vec4 worldPos)
{
    float minDist = float.MaxValue;
    for(int x = Math.max(0, frag.x - neigh); x <= Math.Min(screenWidth, frag.x + neigh; ++x)
        for(int y = Math.max(0, frag.y - neigh); x <= Math.Min(screenHeight, frag.y + neigh; ++y)
        {
            float p = tex2D(distance_texture, x, y);
            float d = distance(p.xyz, worldPos.xyz);
            if (p.a > 0.5 && d <= radius)
                //Return negative distance to indicate a local minimum was found.
                return -1.0; 
            else
                minDist = Math.min(minDist, d);
        }
    return minDist;
}

Finding the local minima in the second pass is much easier, since you only need to sample the local 3x3 neighborhood.
I hope that helps you in reaching the desired rendering!

> **Comments:**
> **username_2**: Notice, that the same question is also on the game development site: [link](https://gamedev.stackexchange.com/questions/183427/closest-sphere-on-segment). I wasn't sure how to handle this, so I found this [Meta question](https://meta.stackexchange.com/questions/172307/duplicate-questions-on-other-se-sites) - Long story short: Maybe you could provide your answer there too by copying or linking it (Don't want to farm reputation that you earned ;) ).  
> **username_1**: Thank you :) Haha it automatically converted it to a comment stating that it is trivial :)  

---

