<p>If I reflect a vector over a mirror, I expect it to end up on the other side of the mirror, even if there's a bit of numerical error. More precisely, if I run the GLSL code</p>
<pre><code>float dot_before = dot(v, mirror)
vec3 v_reflected = reflect(v, mirror)
float dot_after = dot(v_reflected, mirror)
</code></pre>
<p>on a given <code>vec3 v</code> and <code>vec3 mirror</code>, I expect <code>dot_before</code> and <code>dot_after</code> to have opposite signs, even if <code>dot_after</code> isn't exactly equal to <code>-dot_before</code>.</p>
<p>When I replicate the code above in Python, using NumPy float32 vectors, I get the behavior I expect. In GLSL, however, when the vector is very close to the mirror, <code>dot_before</code> and <code>dot_after</code> often come out with the same sign. (See minimal working example below.) My graphics processor is an Intel HD Graphics 520.</p>
<p>This could happen because the second term in the reflection formula <code>v - 2*dot(v, mirror)*mirror</code> is small enough to be rounded off—but why would that round-off affect GLSL but not NumPy at the same floating point precision?</p>
<p><strong>Questions</strong></p>
<ul>
<li>Why doesn't reflection act like I expect in GLSL?</li>
<li>Can I write a reflection function that does act like I expect in GLSL?</li>
<li>If not, is there a good way to identify vectors which are close enough to the mirror that reflection won't put them on the other side? I can choose a threshold that works case-by-case, but it would be nice to have a general principle.</li>
</ul>
<p><strong>Minimal working example</strong></p>
<p>In Python 3, using VisPy. The blue and white columns in the output window show vectors where <code>dot_before</code> and <code>dot_after</code> have the same sign.</p>
<pre><code>import sys
from vispy import app, gloo
from math import cos, sin, pi

vertex = '''
attribute vec2 position;

void main() {
  gl_Position = vec4(position, 0., 1.);
}
'''

fragment = '''
uniform vec2 resolution;
uniform vec3 mirror;

const float COS45 = 0.7071067811865475;

void main() {
  // set up vector
  vec2 u = COS45 * (2.*gl_FragCoord.xy/resolution - vec2(1.));
  float r_sq = 2.*u.x*u.x;
  vec3 v = vec3(2.*u.x, -2.*u.x, 1.-r_sq) / (1.+r_sq);
  
  // do reflection
  float dot_before = dot(mirror, v);
  vec3 v_refl = reflect(v, mirror);
  float dot_after = dot(mirror, v_refl);
  
  // show graph
  vec3 color = vec3(0.);
  if (sign(dot_before) == sign(dot_after)) {
    float level = u.y*1e-6;
    if (level &lt; dot_before) {
      color.r = 1.;
    }
    if (level &lt; dot_after) {
      color.g = 1.;
    }
    color.b = 1.;
  }
  gl_FragColor = vec4(color, 1.);
}
'''

class TestCanvas(app.Canvas):
  def __init__(self, *args, **kwargs):
    app.Canvas.__init__(self, *args, **kwargs)
    self.program = gloo.Program(vertex, fragment, count = 6) # we'll always send 6 vertices
    
    # draw a rectangle that covers the canvas
    self.program['position'] = [
      (-1, -1), (-1, 1), (1, 1), # northwest triangle
      (-1, -1), (1, 1), (1, -1)  # southeast triangle
    ]
    
    # initialize mirror and signature
    self.program['mirror'] = (-sin(pi/4), -cos(pi/4), 0)
    
    # initialize settings
    self.update_resolution()
    self.title = 'Vector reflection test'
  
  def update_resolution(self):
    width, height = self.physical_size
    gloo.set_viewport(0, 0, width, height)
    self.program['resolution'] = [width, height]
  
  def on_draw(self, event):
    self.program.draw()
  
  def on_resize(self, event):
    self.update_resolution()

if __name__ == '__main__' and sys.flags.interactive == 0:
  TestCanvas(size = (500, 500)).show()
  app.run()
<span class="math-container">```</span>
</code></pre>

CC BY-SA 4.0
2021-01-15T10:27:19.490Z
Not sure if this would be an answer, but your use of the term `mirror` suggest that you are using a position rather than a surface normal. Second term of the `reflect` should be the *normalized* surface normal. You might also have a zero division in `1-r_sq`
Kaan E.
CC BY-SA 4.0
2021-01-17T18:50:10.357Z
Whoops! Thanks, @KaanE., for pointing out the wrong normalization in the test code. I've edited the test code to correct the normalization. This also removes the possibility of a zero division.
Vectornaut
CC BY-SA 4.0
2021-01-22T02:40:27.700Z
It is easy to write your own reflect function v = i - 2 * n * dot(i n);
pmw1234
CC BY-SA 4.0
2021-01-26T23:15:06.327Z
@pmw1234, the implementation you suggest acts the same as the built-in.
Vectornaut
CC BY-SA 4.0
2021-01-26T23:48:59.923Z
I suggest putting the computations that calculate u and v "under a microscope" there may be a minor difference in the values. Like gl_fragCoord might have slightly different values because of how OpenGL computes fragment locations. https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_FragCoord.xhtml
pmw1234
CC BY-SA 4.0
2021-01-27T00:54:28.307Z
@pmw1234, numerical errors in the calculation of v don't matter, because the behavior I want should happen for every value of v.
Vectornaut
<glsl>
Numerical error in GLSL vector reflection
Vectornaut
# Numerical error in GLSL vector reflection

(Asked by: username_0 on 2021-01-14)

If I reflect a vector over a mirror, I expect it to end up on the other side of the mirror, even if there's a bit of numerical error. More precisely, if I run the GLSL code

```
float dot_before = dot(v, mirror)
vec3 v_reflected = reflect(v, mirror)
float dot_after = dot(v_reflected, mirror)

```

on a given `vec3 v` and `vec3 mirror`, I expect `dot_before` and `dot_after` to have opposite signs, even if `dot_after` isn't exactly equal to `-dot_before`.

When I replicate the code above in Python, using NumPy float32 vectors, I get the behavior I expect. In GLSL, however, when the vector is very close to the mirror, `dot_before` and `dot_after` often come out with the same sign. (See minimal working example below.) My graphics processor is an Intel HD Graphics 520.

This could happen because the second term in the reflection formula `v - 2*dot(v, mirror)*mirror` is small enough to be rounded off—but why would that round-off affect GLSL but not NumPy at the same floating point precision?

**Questions**

* Why doesn't reflection act like I expect in GLSL?
* Can I write a reflection function that does act like I expect in GLSL?
* If not, is there a good way to identify vectors which are close enough to the mirror that reflection won't put them on the other side? I can choose a threshold that works case-by-case, but it would be nice to have a general principle.

**Minimal working example**

In Python 3, using VisPy. The blue and white columns in the output window show vectors where `dot_before` and `dot_after` have the same sign.

```
import sys
from vispy import app, gloo
from math import cos, sin, pi

vertex = '''
attribute vec2 position;

void main() {
  gl_Position = vec4(position, 0., 1.);
}
'''

fragment = '''
uniform vec2 resolution;
uniform vec3 mirror;

const float COS45 = 0.7071067811865475;

void main() {
  // set up vector
  vec2 u = COS45 * (2.*gl_FragCoord.xy/resolution - vec2(1.));
  float r_sq = 2.*u.x*u.x;
  vec3 v = vec3(2.*u.x, -2.*u.x, 1.-r_sq) / (1.+r_sq);
  
  // do reflection
  float dot_before = dot(mirror, v);
  vec3 v_refl = reflect(v, mirror);
  float dot_after = dot(mirror, v_refl);
  
  // show graph
  vec3 color = vec3(0.);
  if (sign(dot_before) == sign(dot_after)) {
    float level = u.y*1e-6;
    if (level < dot_before) {
      color.r = 1.;
    }
    if (level < dot_after) {
      color.g = 1.;
    }
    color.b = 1.;
  }
  gl_FragColor = vec4(color, 1.);
}
'''

class TestCanvas(app.Canvas):
  def __init__(self, *args, **kwargs):
    app.Canvas.__init__(self, *args, **kwargs)
    self.program = gloo.Program(vertex, fragment, count = 6) # we'll always send 6 vertices
    
    # draw a rectangle that covers the canvas
    self.program['position'] = [
      (-1, -1), (-1, 1), (1, 1), # northwest triangle
      (-1, -1), (1, 1), (1, -1)  # southeast triangle
    ]
    
    # initialize mirror and signature
    self.program['mirror'] = (-sin(pi/4), -cos(pi/4), 0)
    
    # initialize settings
    self.update_resolution()
    self.title = 'Vector reflection test'
  
  def update_resolution(self):
    width, height = self.physical_size
    gloo.set_viewport(0, 0, width, height)
    self.program['resolution'] = [width, height]
  
  def on_draw(self, event):
    self.program.draw()
  
  def on_resize(self, event):
    self.update_resolution()

if __name__ == '__main__' and sys.flags.interactive == 0:
  TestCanvas(size = (500, 500)).show()
  app.run()
```

```

**Tags:** glsl

> **Comments:**
> **username_1**: Not sure if this would be an answer, but your use of the term `mirror` suggest that you are using a position rather than a surface normal. Second term of the `reflect` should be the *normalized* surface normal. You might also have a zero division in `1-r_sq`  
> **username_0**: Whoops! Thanks, @KaanE., for pointing out the wrong normalization in the test code. I've edited the test code to correct the normalization. This also removes the possibility of a zero division.  
> **username_2**: It is easy to write your own reflect function v = i - 2 * n * dot(i n);  
> **username_0**: @username_2, the implementation you suggest acts the same as the built-in.  
> **username_2**: I suggest putting the computations that calculate u and v "under a microscope" there may be a minor difference in the values. Like gl_fragCoord might have slightly different values because of how OpenGL computes fragment locations. https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_FragCoord.xhtml  
> **username_0**: @username_2, numerical errors in the calculation of v don't matter, because the behavior I want should happen for every value of v.  

---

## 0 answers

