start . me .
Directory path . web , canvas .

HTML Document File : raycalc.html


<!DOCTYPE html>
<html>
<head>
    <title>3D Sphere Renderer</title>
    
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>

<canvas id="calculated" > </canvas>

<script>
// Canvas setup
const canvas = document.querySelector('canvas#calculated');
canvas.width = 800;
canvas.height = 600;
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(canvas.width, canvas.height);
const data = imageData.data;

// 3D Math utilities
class Vec3 {
    constructor(x, y, z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    normalize() {
        const len = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
        return new Vec3(this.x / len, this.y / len, this.z / len);
    }

    dot(v) {
        return this.x * v.x + this.y * v.y + this.z * v.z;
    }

    add(v) {
        return new Vec3(this.x + v.x, this.y + v.y, this.z + v.z);
    }

    sub(v) {
        return new Vec3(this.x - v.x, this.y - v.y, this.z - v.z);
    }

    mul(s) {
        return new Vec3(this.x * s, this.y * s, this.z * s);
    }

    reflect(normal) {
        const dot = this.dot(normal);
        return this.sub(normal.mul(2 * dot));
    }
}

// Scene configuration
const sphere = {
    center: new Vec3(0, 1, 0),
    radius: 1,
    color: new Vec3(0.8, 0.3, 0.3),
    specular: 0.7,
    reflectivity: 0.5,
    transparency: 0.2
};

const light = {
    position: new Vec3(5, 5, -5),
    color: new Vec3(1, 1, 1),
    intensity: 1.0
};

const plane = {
    normal: new Vec3(0, 1, 0),
    point: new Vec3(0, 0, 0),
    textureScale: 0.5
};

const camera = {
    position: new Vec3(0, 2, -5),
    target: new Vec3(0, 0, 0),
    up: new Vec3(0, 1, 0),
    fov: 60,
    aspectRatio: canvas.width / canvas.height
};

// Texture generation
function createCheckerboardTexture(size) {
    const texture = new Array(size * size);
    for (let y = 0; y < size; y++) {
        for (let x = 0; x < size; x++) {
            const isEven = ((x + y) % 2) === 0;
            texture[y * size + x] = isEven ? new Vec3(0.9, 0.9, 0.9) : new Vec3(0.2, 0.2, 0.2);
        }
    }
    return texture;
}

const planeTexture = createCheckerboardTexture(256);

// Intersection functions
function intersectSphere(origin, direction) {
    const oc = origin.sub(sphere.center);
    const a = direction.dot(direction);
    const b = 2 * oc.dot(direction);
    const c = oc.dot(oc) - sphere.radius * sphere.radius;
    const discriminant = b * b - 4 * a * c;

    if (discriminant < 0) return null;

    const t = (-b - Math.sqrt(discriminant)) / (2 * a);
    if (t < 0) return null;

    const point = origin.add(direction.mul(t));
    const normal = point.sub(sphere.center).normalize();
    return { point, normal, t };
}

function intersectPlane(origin, direction) {
    const denom = direction.dot(plane.normal);
    if (Math.abs(denom) < 1e-6) return null;

    const t = plane.point.sub(origin).dot(plane.normal) / denom;
    if (t < 0) return null;

    const point = origin.add(direction.mul(t));
    return { point, normal: plane.normal, t };
}

// Shading and lighting
function calculateLighting(point, normal, viewDir) {
    const lightDir = light.position.sub(point).normalize();
    const shadowRay = { origin: point.add(normal.mul(0.001)), direction: lightDir };
    
    // Check for shadows
    const shadowHit = intersectSphere(shadowRay.origin, shadowRay.direction);
    if (shadowHit && shadowHit.t < light.position.sub(point).dot(lightDir)) {
        return new Vec3(0.1, 0.1, 0.1); // Ambient light only
    }

    const diffuse = Math.max(0, normal.dot(lightDir));
    const reflectDir = lightDir.reflect(normal);
    const specular = Math.pow(Math.max(0, reflectDir.dot(viewDir)), 32);

    return new Vec3(
        light.color.x * (diffuse + specular * sphere.specular),
        light.color.y * (diffuse + specular * sphere.specular),
        light.color.z * (diffuse + specular * sphere.specular)
    );
}

// Sample plane texture
function samplePlaneTexture(point) {
    const u = Math.floor(point.x * plane.textureScale) & 255;
    const v = Math.floor(point.z * plane.textureScale) & 255;
    return planeTexture[v * 256 + u];
}

// Main rendering function with antialiasing
function render() {
    const samples = 4; // Anti-aliasing samples per pixel
    const maxDepth = 3; // Maximum reflection depth

    for (let y = 0; y < canvas.height; y++) {
        for (let x = 0; x < canvas.width; x++) {
            let color = new Vec3(0, 0, 0);

            // Super-sampling anti-aliasing
            for (let sy = 0; sy < samples; sy++) {
                for (let sx = 0; sx < samples; sx++) {
                    const u = (x + (sx + 0.5) / samples) / canvas.width * 2 - 1;
                    const v = 1 - (y + (sy + 0.5) / samples) / canvas.height * 2;

                    const direction = new Vec3(
                        u * Math.tan(camera.fov * Math.PI / 360) * camera.aspectRatio,
                        v * Math.tan(camera.fov * Math.PI / 360),
                        1
                    ).normalize();

                    color = color.add(traceRay(camera.position, direction, maxDepth));
                }
            }

            // Average samples and apply gamma correction
            color = color.mul(1 / (samples * samples));
            color = new Vec3(
                Math.pow(color.x, 1/2.2),
                Math.pow(color.y, 1/2.2),
                Math.pow(color.z, 1/2.2)
            );

            const index = (y * canvas.width + x) * 4;
            data[index] = Math.min(255, Math.max(0, Math.floor(color.x * 255)));
            data[index + 1] = Math.min(255, Math.max(0, Math.floor(color.y * 255)));
            data[index + 2] = Math.min(255, Math.max(0, Math.floor(color.z * 255)));
            data[index + 3] = 255;
        }
    }

    ctx.putImageData(imageData, 0, 0);
}

// Recursive ray tracing function
function traceRay(origin, direction, depth) {
    if (depth <= 0) return new Vec3(0, 0, 0);

    const sphereHit = intersectSphere(origin, direction);
    const planeHit = intersectPlane(origin, direction);

    let hit = null;
    let isSphere = false;

    // Determine closest intersection
    if (sphereHit && planeHit) {
        hit = sphereHit.t < planeHit.t ? sphereHit : planeHit;
        isSphere = sphereHit.t < planeHit.t;
    } else {
        hit = sphereHit || planeHit;
        isSphere = !!sphereHit;
    }

    if (!hit) return new Vec3(0.1, 0.1, 0.1); // Background color

    let color;
    if (isSphere) {
        // Sphere shading
        const lighting = calculateLighting(hit.point, hit.normal, direction.mul(-1));
        color = sphere.color.mul(lighting.x);

        // Reflections
        if (sphere.reflectivity > 0) {
            const reflectDir = direction.reflect(hit.normal);
            const reflectOrigin = hit.point.add(hit.normal.mul(0.001));
            const reflectColor = traceRay(reflectOrigin, reflectDir, depth - 1);
            color = color.mul(1 - sphere.reflectivity).add(reflectColor.mul(sphere.reflectivity));
        }

        // Transparency
        if (sphere.transparency > 0) {
            const refractDir = direction; // Simplified refraction
            const refractOrigin = hit.point.sub(hit.normal.mul(0.001));
            const refractColor = traceRay(refractOrigin, refractDir, depth - 1);
            color = color.mul(1 - sphere.transparency).add(refractColor.mul(sphere.transparency));
        }
    } else {
        // Plane shading with texture
        const textureColor = samplePlaneTexture(hit.point);
        const lighting = calculateLighting(hit.point, hit.normal, direction.mul(-1));
        color = textureColor.mul(lighting.x);

        // Mirror-like reflections on plane
        const reflectDir = direction.reflect(hit.normal);
        const reflectOrigin = hit.point.add(hit.normal.mul(0.001));
        const reflectColor = traceRay(reflectOrigin, reflectDir, depth - 1);
        color = color.mul(0.8).add(reflectColor.mul(0.2));
    }

    return color;
}

// Start rendering asynchronously
setTimeout(() => {
    render();
    // document.body.appendChild(canvas);
}, 100);

</script>

<script src="https://arkenidar.com/web/show-source.js" > </script>

</body>
</html>