<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.

[![enter image description here](https://i.sstatic.net/fdhyQ.jpg)](https://i.sstatic.net/fdhyQ.jpg)

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.

1. Compute the raw distance field in the first pass (same as your example but no `radius` subtraction at the end.
2. 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.
3. 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:

```glsl
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 :)  

---

