Going further than the tutorial:

  • Moved from ShaderToy to Processing
  • Added an interface with sliders in Processing so users can change the size and location of the ball

Live ShaderToy Version:


Download the Processing Code


GLSL / ShaderToy Code

#define MAX_STEPS 100
#define MAX_DIST 100.0
#define SURFACE_DIST 0.01

float sphereSize = 1.0;
vec2 sphereLocation = vec2(0, 6);
vec3 lightColor = vec3(1.0, 1.0, 1.0);

float GetDist(vec3 point) {
    // Set sphere location
    vec4 spherePos = vec4(sphereLocation.x, sphereSize, sphereLocation.y, sphereSize);
    
    // Calculate sphere distance
    float sphereDist = length(point - spherePos.xyz) - spherePos.w;
    
    // Calculate plane distance
    float planeDist = point.y;
    
    // Calculate total distance
    float dist = min(sphereDist, planeDist);
    
    return dist;
}

float RayMarch(vec3 rOrigin, vec3 rDirection) {
    float distFromOrigin = 0.0;
    
    for (int i = 0; i < MAX_STEPS; i++) {
        vec3 hitPoint = rOrigin + distFromOrigin * rDirection;
        float dist = GetDist(hitPoint);
        distFromOrigin += dist;
        
        if (dist < SURFACE_DIST || distFromOrigin > MAX_DIST) { break; }
    }
    
    return distFromOrigin;
}

vec3 GetNormal(vec3 point) {
    float dist = GetDist(point);
    vec2 e = vec2(0.01, 0.0);
    vec3 normal = dist - vec3(
        GetDist(point - e.xyy),
        GetDist(point - e.yxy),
        GetDist(point - e.yyx)
        );
    
    return normalize(normal);
}

float GetLight(vec3 point) {
    vec3 lightPos = vec3(0, 5, 6);
    
    // Make light move in a circle around
    lightPos.xz += vec2(sin(iTime), cos(iTime)) * 3.0;
    
    vec3 light = normalize(lightPos - point);
    vec3 normal = GetNormal(point);
    
    float difLight = clamp(dot(normal, light), 0.0, 1.0);
    
    // For shadows
    float dist = RayMarch(point + normal * SURFACE_DIST * 2.0, light);
    if (dist < length(lightPos - point)) {
        difLight *= 0.1;
    }
    return difLight;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalize pixel coordinates (from 0 to 1) and set origin to center
    vec2 uv = (fragCoord - 0.5 * iResolution.xy)/iResolution.y;

    vec3 color = vec3(0);
    
    // Set camera position
    vec3 rayOrigin = vec3(0, 1, 0);
    vec3 rayDirection = normalize(vec3(uv.x, uv.y, 1));

    float dist = RayMarch(rayOrigin, rayDirection);
    vec3 lightPoint = rayOrigin + rayDirection * dist;
    
    // Get diffuse lighting
    float difLight = GetLight(lightPoint);
    
    color = vec3(difLight) * lightColor;
    // Output to screen
    fragColor = vec4(color,1.0);
}

Tutorial I followed:


Resources:
ShaderToy
Processing.org

Leave a Reply

Your email address will not be published. Required fields are marked *