# Reflections and Refractions

When I have made a raymarched sphere I was quite happy. But I wanted to make a glass one. So the first experiment was to make a sphere which only worked like a lens. Just to see what’s behind it with a bit refracted rays.

I shoot a ray from the eye adjusting it for the current pixel with`vec3 ray_dir = normalize(up * uv.y + right *uv.x + forward);`

Where `right`

and `forward`

are just static vectors and `uv`

is my current pixel. Like this:

1 2 3 | vec3 up = vec3(0.0, 1.0, 0.0); vec3 forward = vec3(0.0, 0.0, 1.0); vec3 right = cross(up, forward); |

So now once my ray hit the ball, I didn’t take the pixel from the texture and display it but I have used a cubemap. First for the refraction I am happy *GLSL* handles it internally as well as `reflect()`

, I just need a vector and a vector I am going refract on and of course a coefficient. For the cubemap there is `textureCube()`

instead of `texture2D()`

. So the whole magic happens here:

1 2 | vec3 refracted_ray = refract(ray_dir, -point_normal, refract_koef); vec4 refracted_color = textureCube(iChannel2, refracted_ray); |

I use

`-point_normal`

because I refract the ray going from me instead of going into me that’s why I invert it and `refract_koef`

is `1.02`

. Refraction coefficient only needs to be above `1`

to be a convex lens and below `1`

to be a concave lens. Now for the rays that don’t hit anything I need to draw a normal pixel from the cubemap:`gl_FragColor = textureCube(iChannel2, ray_dir);`

The pseudocode is this:

1 2 3 4 5 6 7 8 9 | ... float dist = raymarch(...); if (dist < max_distance) { vec3 refracted_ray = refract(ray_dir, -point_normal, refract_koef); vec4 refracted_color = textureCube(iChannel2, refracted_ray); } else { gl_FragColor = textureCube(iChannel2, ray_dir); } ... |

And the result looks good:

I wanted to push this lens a bit forward and make it look like a sphere - so reflections too. For this I simply need to reflect the ray, get the pixel from the cubemap and mix reflection and refraction colors. Reflection is even more easy. Now `point_normal`

is positive because it points my the viewers eye.

1 2 | vec3 reflected_ray = reflect(ray_dir, point_normal); vec4 reflected_color = textureCube(iChannel2, reflected_ray); |

And I mix the colors with

`gl_FragColor = mix(reflected_color, refracted_color, 0.5);`

. This shows up:It reflects rays and also refracts but it isn’t realistic as I have hardcoded a constant `0.5`

so refraction and reflection rays are combined as equals while in reality the more straight I look into the object the more refraction I see and less reflection while on the other hand when I look into the object from the side almost all I can see are - reflections. To fix this I have found fresnel lens algorithm on GPU Gems 2. So we simply need to get coefficient between reflection and refraction and it looks ok when written like this:

1 2 3 4 | float fresnelBias = 0.00; float fresnelScale = 0.25; float fresnelPower = 1.97; float mix_coef = fresnelBias + fresnelScale*pow(1.0 + dot(ray_dir, point_normal), fresnelPower); |

The constants are hand tweaked because I didn’t find any suitable ones. So consider this an experiment. So now my color is calculated with this:

`vec4 mixed = mix(reflected_color, refracted_color, mix_coef);`

;And the result looks more realistic:

The last thing which I wanted to do - a rainbow on a bubble. This is due to the different refraction coefficient of colors, so to implement this I refract R, G and B components of a texel differently. Again - the coefficients are hand tweaked:

1 2 3 4 5 6 7 8 9 10 | vec3 etaRatioRGB = vec3(1.03, 1.06, 1.09); vec3 TRed = refract(ray_dir, -point_normal, etaRatioRGB.r); vec3 TGreen = refract(ray_dir, -point_normal, etaRatioRGB.g); vec3 TBlue = refract(ray_dir, -point_normal, etaRatioRGB.b); vec4 refracted_color; refracted_color.r = textureCube(iChannel2, TRed).r; refracted_color.g = textureCube(iChannel2, TGreen).g; refracted_color.b = textureCube(iChannel2, TBlue).b; |

And the result looks bubbly!:

In conclusion - it was really fun and quite fun and fresnel lens formula really makes sense. From my understanding as `ray_dir`

and `point_normal`

are normalized the `dot`

just gives me a `cos`

of those vectors so when I look forward into the bubble I get `1`

which maximizes refractions I see and when I look from the very side into it all I can see are reflections because of `cos`

giving me zero. The `pow`

there exists because of inverse square law or I believe so.

For the bonus here is the concave lens with `refract_koef = 0.98;`

:

You can see the code and tweak it also online here:

Lens on Shadertoy

Bubble on Shadertoy