2

I've been trying to add this post-processing (taken from sebastian lague video which I am trying to convert from unity to threejs) effect that when a ray hits the ocean on my mesh (the blue):

img

it is colored white (just like in his video):

img

and everywhere else the original color is returned. But for the life of me can't seem to figure out the problem, I assume my ray origin or direction might be wrong but nothing seems to work, Here's the code that I pass to the ray Sphere intersection function and the function itself.

        vec2 raySphere(vec3 centre, float radius, vec3 rayOrigin, vec3 rayDir) {
        vec3 offset = rayOrigin - centre;
        float a = 1.0; // set  to dot(rayDir, rayDir) instead of rayDir may not be normalized
        float b = 2.0 * dot(offset, rayDir);
        float c = dot(offset, offset) - radius * radius;

        float discriminant = b*b-4.0*a*c;
        // No intersection: discriminant < 0
        // 1 intersection: discriminant == 0
        // 2 intersection: discriminant > 0
        if(discriminant > 0.0) {
            float s = sqrt(discriminant);
            float dstToSphereNear = max(0.0, (-b - s) / (2.0 * a));
            float dstToSphereFar = (-b + s) / (2.0 * a);

            if (dstToSphereFar >= 0.0) {
                return vec2(dstToSphereNear, dstToSphereFar-dstToSphereNear);
            }
        }

        return vec2(99999999, 0.0);
        }

        vec4 ro = inverse(modelMatrix) * vec4(cameraPosition, 1.0);
        vec3 rd = normalize(position - ro.xyz);
        
        vec3 oceanCentre = vec3(0.0, 0.0, 0.0);
        float oceanRadius = 32.0;
        vec2 hitInfo = raySphere(oceanCentre, oceanRadius, ro.xyz, rd);
        float dstToOcean = hitInfo.x;
        float dstThroughOcean = hitInfo.y;

        vec3 rayOceanIntersectPos = ro.xyz + rd * dstToOcean - oceanCentre;
    
        // dst that view ray travels through ocean (before hitting terrain / exiting ocean)
        float oceanViewDepth = min(dstThroughOcean, depth - dstToOcean);
        vec4 oceanCol;
        float alpha;

        if(oceanViewDepth > 0.0) {
            gl_FragColor = vec4(vec3(1.0), .1);
        }
        gl_FragColor = texture2D(tDiffuse, vUv);

Can someone help point out where I might be messing up?

TylerH
  • 20,799
  • 66
  • 75
  • 101
alii
  • 21
  • 1
  • cross check/compare with this [ray and ellipsoid intersection accuracy improvement](https://stackoverflow.com/q/25470493/2521214). Also check the [Atmospheric scattering GLSL fragment shader](https://stackoverflow.com/a/19659648/2521214) I developed it for as its very similar to what you are doing (at least I think) – Spektre Jun 09 '21 at 08:10

1 Answers1

1

Oh wow, we're in the same place while we're stuck at making these shaders. I checked your ray intersectors have small problems. But here is the cases:

Ray Tracing sphere cases

What we want if case 3 happens like on your example, so the intersection are in count the problem probably come from no depth correction by doing this:

  1. Make sure your sphere intersection max depth same as the camera.
  2. I do suspect if the last line is the problem, try do this:
vec3 col; // Declare the color
vec2 o = sphere(ro, rd, vec3(0), 1.0); // Ocean Depth.
float oceanViewDepth = min(o.y - o.x, t - o.x);
if(depth > 0.0 && tmax > depth) {
    col = originalCol;
}
if(oceanViewDepth > 0.0) {
    col = vec3(1);
}
gl_FragColor = vec4(col, 1.0);

If that doesn't work for you I have some finished example for you to checkout at shadertoy