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:
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