3

I've been trying to generate water effects via fragment shader in shader toy. Right now I'm trying to use octave ridge noise multifractals in order to generate a water-like surface. So far, this works fine. The next step I wanted to take was doing proper light refraction through this "water surface", however I end up with a strange situation.

I've set up the shader to raymarch two spheres, with soft shadowing, and a plane with a checkerboard pattern to easily see the distortion.

Here is my shader. https://www.shadertoy.com/view/XddcRB

(x and y axis rotation via, top, down, left, right, wasd for lateral movement) Look down to see the refraction surface (if you move too far down, you will be below the surface, and no refraction will take place)

At first glance it will appear as if this effect is working, but if you move into the water you'll see that until you move below the surface (where no refraction takes place), the checkerboard doesn't actually obey y axis movmement to change its perspective (that is, when looking down and moving up or down, the pattern stays the same)

I thought that was because I didn't take into account the new origin with displaying the pattern, however, when I change the line to decide if we should show the refraction,

vec3 normal_c;
float water_surface = gradientNoiseRayMarch(ray, origin, normal_c);
vec3 water_ray = origin + ray * water_surface;
float depth;
if(origin.y > water_ray.y){

    vec3 refract_ray = refract(ray, normal_c, 1.0);
    ray = normalize(refract_ray);
    //origin = water_ray;
    depth = rayMarch(normalize(refract_ray), water_ray);
}
...
vec3 surface_point = vec3(origin+ray*depth);    
float value = getCheckerPattern(surface_point.xz, 2.0);

to

vec3 normal_c;
float water_surface = gradientNoiseRayMarch(ray, origin, normal_c);
vec3 water_ray = origin + ray * water_surface;
float depth;
if(origin.y > water_ray.y){

    vec3 refract_ray = refract(ray, normal_c, 1.0);
    ray = normalize(refract_ray);
    origin = water_ray; //CHANGED
    depth = rayMarch(normalize(refract_ray), water_ray);
}
...
vec3 surface_point = vec3(origin+ray*depth);    
float value = getCheckerPattern(surface_point.xz, 2.0);

it removes the refraction effect entirely.

enter image description here

Additionally if I try to increase the index of refraction, I see nothing below the surface (even with 1.1 index of refraction).

enter image description here

vs

enter image description here

In addition to these issues, the spheres never appear to be warped like the pattern does.

I would think that I would need to set the origin of each ray at the contact point of the water, and angle each ray from that point (hence why I thought it would be necessary to set the origin = to water_ray which is the ray up until the surface of the water).

Krupip
  • 4,404
  • 2
  • 32
  • 54

0 Answers0