<blockquote>
  <p>How long should $i$ and $j$ be? By similar triangles, they should have length $R\times (1-\frac{R}{\lVert V\rVert})$.</p>
</blockquote>

<p>I believe this is where you went wrong. If you draw the 2D version of this on a sheet of paper, it will be obvious that the edge of your triangle which touches the side of your square goes through the sphere. More so as the camera comes closer.</p>

<p>That line needs to be tangent to the sphere. So your large similar triangle will have its right angle at the contact point with the sphere, not at the sphere's center as you did. If my trigonometry is not too rusty, this gives</p>

<p>$\frac{R}{\sqrt{\lVert V\rVert^2-R^2}} \times \left(\lVert V\rVert-R\right)$</p>

CC BY-SA 3.0
2018-02-19T22:40:40.187Z
Thanks. I asked a purer version of this question at [math stackexchange](https://math.stackexchange.com/questions/2657669/radius-of-circle-tangent-to-sphere-which-obscures-that-sphere/2657673#2657673) and got an equivalent answer which gives another hint at how to solve this.
spraff
CC BY-SA 3.0
2018-02-19T18:38:55.863Z
2018-02-19T20:06:16.347Z
2018-02-19T20:06:16.347Z
Olivier
<p>I am learning GLSL and want to raytrace a sphere. I am rendering rectangles which sit between the camera and sphere, and do a ray-sphere intersection test in the fragment shader. It almost works:</p>

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

<p>As you can see, the rectangles are a little too small. Here is how I calculated them.</p>

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

<p>Point $C$ is the centre of the rectangle, a distance $R$ from the radius of the sphere. Taking basis vectors $i,j$ I can construct the corners as $C+(\pm i, \pm j)$</p>

<p>Point $C$ is a fraction $1-\frac{R}{||V||}$ along the vector $V$ from the camera.</p>

<p>I can direct $i$ and $j$ given the vector $V$ and the "up" vector.</p>

<p>How long should $i$ and $j$ be? By similar triangles, they should have length $R\times (1-\frac{R}{||V||})$.</p>

<p>Here is the code (I'm new to GLSL so please ignore bad habits, for now I just want to get the geometry right).</p>

<p>A vertex array containing four $(\pm 1, \pm 1, 0)$ vectors forms a triangle strip.</p>

<p>The vertex shader:</p>

<pre><code>#version 300 es
in  vec2 position;
out vec3 vs_fs_position;

uniform vec3 i;
uniform vec3 j;
uniform vec3 centre;

uniform mat4 pvm; // projection * view * model

void main ()
{
    vec3 p = centre + position.x * i + position.y * j;

    vs_fs_position = p; // world space coordinate sent to fragment

    gl_Position = pvm * vec4 (p, 1); // to screen space
}
</code></pre>

<p>The fragment shader</p>

<pre><code>#version 300 es
precision mediump float;
out mediump vec4 out_colour;
in  mediump vec3 vs_fs_position;

uniform mediump vec3 camera_position;
uniform mediump vec3 camera_to_sphere;
uniform float radius;

void main ()
{
    vec3 direction = vs_fs_position - camera_position;

    float A = dot (direction, direction);
    float B = 2.0 * dot (direction, camera_to_sphere);
    float C = dot (camera_to_sphere, camera_to_sphere)
            - radius * radius;

    float det = B * B - 4.0 * A * C;

    if (det &lt; 0.0)
        out_colour = vec4 (0.0, 0.0, 0.0, 1.0);
    else
        out_colour = vec4 (0.5, 0.5, 0.5, 1.0);

}
</code></pre>

<p>Some C++ to draw it</p>

<pre><code>shader .camera_position = m_camera_position;

const float EPSILON = 0.0;

for (auto &amp; s : SPHERES)
{
    auto R = s .position - m_camera_position;

    float ratio = 1.0 - (s .radius + EPSILON) / length (R);

    float width = ratio * s .radius;

    auto &amp; up = m_camera_up;

    const float W = width * (1 + EPSILON);

    glm :: vec3 i = normalize (cross (up, R)) * W;
    glm :: vec3 j = normalize (cross (R,  i)) * W;

    shader .i = i;
    shader .j = j;

    shader .centre = s .position;
    shader .radius = s .radius;

    shader .camera_to_sphere = s .position - m_camera_position;

    glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
}
</code></pre>

<p>If it runs with <code>EPSILON=0.5</code>, I get this output.</p>

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

<p>Theoretically, I should be able to get a perfect fit with <code>EPSILON=0</code>, that way I can be confident it will work at all scales/positions.</p>

<p>What's wrong with my calculation of the <code>width</code> parameter?</p>

<geometry>
calculating size of rectangle which fully obscures a sphere
spraff
# calculating size of rectangle which fully obscures a sphere

(Asked by: username_0 on 2018-02-19)

I am learning GLSL and want to raytrace a sphere. I am rendering rectangles which sit between the camera and sphere, and do a ray-sphere intersection test in the fragment shader. It almost works:

[![enter image description here](https://i.sstatic.net/72env.png)](https://i.sstatic.net/72env.png)

As you can see, the rectangles are a little too small. Here is how I calculated them.

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

Point $C$ is the centre of the rectangle, a distance $R$ from the radius of the sphere. Taking basis vectors $i,j$ I can construct the corners as $C+(\pm i, \pm j)$

Point $C$ is a fraction $1-\frac{R}{||V||}$ along the vector $V$ from the camera.

I can direct $i$ and $j$ given the vector $V$ and the "up" vector.

How long should $i$ and $j$ be? By similar triangles, they should have length $R\times (1-\frac{R}{||V||})$.

Here is the code (I'm new to GLSL so please ignore bad habits, for now I just want to get the geometry right).

A vertex array containing four $(\pm 1, \pm 1, 0)$ vectors forms a triangle strip.

The vertex shader:

```
#version 300 es
in  vec2 position;
out vec3 vs_fs_position;

uniform vec3 i;
uniform vec3 j;
uniform vec3 centre;

uniform mat4 pvm; // projection * view * model

void main ()
{
    vec3 p = centre + position.x * i + position.y * j;

    vs_fs_position = p; // world space coordinate sent to fragment

    gl_Position = pvm * vec4 (p, 1); // to screen space
}

```

The fragment shader

```
#version 300 es
precision mediump float;
out mediump vec4 out_colour;
in  mediump vec3 vs_fs_position;

uniform mediump vec3 camera_position;
uniform mediump vec3 camera_to_sphere;
uniform float radius;

void main ()
{
    vec3 direction = vs_fs_position - camera_position;

    float A = dot (direction, direction);
    float B = 2.0 * dot (direction, camera_to_sphere);
    float C = dot (camera_to_sphere, camera_to_sphere)
            - radius * radius;

    float det = B * B - 4.0 * A * C;

    if (det < 0.0)
        out_colour = vec4 (0.0, 0.0, 0.0, 1.0);
    else
        out_colour = vec4 (0.5, 0.5, 0.5, 1.0);

}

```

Some C++ to draw it

```
shader .camera_position = m_camera_position;

const float EPSILON = 0.0;

for (auto & s : SPHERES)
{
    auto R = s .position - m_camera_position;

    float ratio = 1.0 - (s .radius + EPSILON) / length (R);

    float width = ratio * s .radius;

    auto & up = m_camera_up;

    const float W = width * (1 + EPSILON);

    glm :: vec3 i = normalize (cross (up, R)) * W;
    glm :: vec3 j = normalize (cross (R,  i)) * W;

    shader .i = i;
    shader .j = j;

    shader .centre = s .position;
    shader .radius = s .radius;

    shader .camera_to_sphere = s .position - m_camera_position;

    glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
}

```

If it runs with `EPSILON=0.5`, I get this output.

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

Theoretically, I should be able to get a perfect fit with `EPSILON=0`, that way I can be confident it will work at all scales/positions.

What's wrong with my calculation of the `width` parameter?

**Tags:** geometry


---

## 1 answers

### Answer by username_1 on 2018-02-19. Score: 3 | Accepted answer

> How long should $i$ and $j$ be? By similar triangles, they should have length $R\times (1-\frac{R}{\lVert V\rVert})$.

I believe this is where you went wrong. If you draw the 2D version of this on a sheet of paper, it will be obvious that the edge of your triangle which touches the side of your square goes through the sphere. More so as the camera comes closer.

That line needs to be tangent to the sphere. So your large similar triangle will have its right angle at the contact point with the sphere, not at the sphere's center as you did. If my trigonometry is not too rusty, this gives

$\frac{R}{\sqrt{\lVert V\rVert^2-R^2}} \times \left(\lVert V\rVert-R\right)$

> **Comments:**
> **username_0**: Thanks. I asked a purer version of this question at [math stackexchange](https://math.stackexchange.com/questions/2657669/radius-of-circle-tangent-to-sphere-which-obscures-that-sphere/2657673#2657673) and got an equivalent answer which gives another hint at how to solve this.  

---

