Tutorial: Intro to Raymarching - With Mouse Control

176 views 0 replies
Live Shader
Loading versions...

This is an extension of Intro to Raymarching but with added Mouse Control for orbiting around the sphere + shadows.

Image

precision mediump float;

uniform vec2 iResolution;
uniform float iTime;
uniform vec4 iMouse;

// --------------------------------------------------
// SDF scene
// --------------------------------------------------

float sdSphere(vec3 p, float r) {
    return length(p) - r;
}

float sdFloor(vec3 p) {
    return p.y + 1.0; // floor at y = -1
}

float scene(vec3 p) {
    float sphere = sdSphere(p - vec3(0.0, 0.0, 0.0), 0.8);
    float floorD = sdFloor(p);
    return min(sphere, floorD);
}

// --------------------------------------------------
// Helpers
// --------------------------------------------------

vec3 getNormal(vec3 p) {
    vec2 e = vec2(0.001, 0.0);
    return normalize(vec3(
        scene(p + e.xyy) - scene(p - e.xyy),
        scene(p + e.yxy) - scene(p - e.yxy),
        scene(p + e.yyx) - scene(p - e.yyx)
    ));
}

mat3 cameraLookAt(vec3 ro, vec3 ta, float roll) {
    vec3 ww = normalize(ta - ro);
    vec3 uu = normalize(cross(ww, vec3(sin(roll), cos(roll), 0.0)));
    vec3 vv = normalize(cross(uu, ww));
    return mat3(uu, vv, ww);
}

// --------------------------------------------------
// Main
// --------------------------------------------------

void main() {
    vec2 fragCoord = gl_FragCoord.xy;
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;

    // Normalised mouse in 0..1 range
    vec2 m = iMouse.xy / iResolution.xy;

    // Fallback slow auto orbit when mouse not pressed and no mouse available
    bool mouseActive = (iMouse.z > 0.0) || (iMouse.x > 0.0 || iMouse.y > 0.0);

    float yaw;
    float pitch;
    float dist;

    if (mouseActive) {
        // Horizontal mouse = yaw
        yaw = (m.x - 0.5) * 6.28318;

        // Vertical mouse = pitch
        pitch = (m.y - 0.5) * 2.4;
        pitch = clamp(pitch, -1.2, 1.2);

        // Also use vertical mouse to control zoom a bit
        dist = mix(2.5, 10.0, 1.0 - m.y);
    } else {
        yaw = iTime * 0.35;
        pitch = 0.25 + 0.2 * sin(iTime * 0.7);
        dist = 6.0;
    }

    vec3 target = vec3(0.0, 0.0, 0.0);

    // Orbit camera around target
    vec3 ro = target + vec3(
        cos(pitch) * sin(yaw),
        sin(pitch),
        cos(pitch) * cos(yaw)
    ) * dist;

    mat3 cam = cameraLookAt(ro, target, 0.0);
    vec3 rd = normalize(cam * vec3(uv, 1.5));

    // Raymarch
    float t = 0.0;
    bool hit = false;

    for (int i = 0; i < 200; i++) {
        vec3 p = ro + rd * t;
        float d = scene(p);
        if (d < 0.001) {
            hit = true;
            break;
        }
        t += d;
        if (t > 50.0) break;
    }

    vec3 col = vec3(0.1, 0.1, 0.15);

    if (hit) {
        vec3 p = ro + rd * t;
        vec3 n = getNormal(p);

        vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));
        float diff = max(dot(n, lightDir), 0.0);

        vec3 albedo = vec3(0.8, 0.3, 0.2);

        if (p.y < -0.99) {
            float check = mod(floor(p.x) + floor(p.z), 2.0);
            albedo = mix(vec3(0.3), vec3(0.8), check);
        }

        // Specular
        vec3 viewDir = normalize(ro - p);
        vec3 halfDir = normalize(lightDir + viewDir);
        float spec = pow(max(dot(n, halfDir), 0.0), 64.0);

        // Soft-ish shadow
        float shadow = 1.0;
        float st = 0.02;
        for (int j = 0; j < 40; j++) {
            vec3 sp = p + n * 0.01 + lightDir * st;
            float h = scene(sp);
            shadow = min(shadow, 12.0 * h / st);
            if (h < 0.001) {
                shadow = 0.0;
                break;
            }
            st += clamp(h, 0.01, 0.2);
            if (st > 20.0) break;
        }
        shadow = clamp(shadow, 0.0, 1.0);

        float ambient = 0.2;
        col = albedo * (ambient + diff * 0.8 * shadow) + spec * 0.35 * shadow;
    }

    col = pow(col, vec3(1.0 / 2.2));
    gl_FragColor = vec4(col, 1.0);
}
Moonjump
Forum Search Shader Sandbox
Sign In Register