Please bookmark this page to avoid losing your image tool!

Sphere Map Image Generator

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, size = 0, rotY = 0, rotX = 0, lighting = 0.3, backgroundColor = "transparent") {
    // Determine the size of the output sphere image
    let s = Number(size);
    if (!s || s <= 0) {
        s = Math.min(originalImg.width, originalImg.height);
    }
    s = Math.floor(s);

    // Create the final output canvas
    const canvas = document.createElement('canvas');
    canvas.width = s;
    canvas.height = s;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Draw background
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, s, s);

    // Create a temporary canvas for source image data extraction
    const srcCanvas = document.createElement('canvas');
    const srcW = originalImg.width;
    const srcH = originalImg.height;
    srcCanvas.width = srcW;
    srcCanvas.height = srcH;
    const srcCtx = srcCanvas.getContext('2d', { willReadFrequently: true });
    srcCtx.drawImage(originalImg, 0, 0);
    const srcData = srcCtx.getImageData(0, 0, srcW, srcH).data;

    // Create image data for the sphere mapping
    const destImageData = ctx.createImageData(s, s);
    const destData = destImageData.data;

    // Parse rotations & lighting
    const degToRad = Math.PI / 180;
    const rx = Number(rotX) || 0;
    const ry = Number(rotY) || 0;
    const cosX = Math.cos(rx * degToRad);
    const sinX = Math.sin(rx * degToRad);
    const cosY = Math.cos(ry * degToRad);
    const sinY = Math.sin(ry * degToRad);

    const lightIntensity = isNaN(Number(lighting)) ? 0.3 : Math.max(0, Math.min(1, Number(lighting)));
    const ambientLight = 1.0 - lightIntensity;

    const R = s / 2;
    const inv2PI = 1 / (2 * Math.PI);
    const invPI = 1 / Math.PI;

    for (let py = 0; py < s; py++) {
        let ny = (py - R) / R;
        let ny2 = ny * ny;

        for (let px = 0; px < s; px++) {
            let nx = (px - R) / R;
            let nx2 = nx * nx;
            let r2 = nx2 + ny2;

            let idx = (py * s + px) * 4;

            // If outside the sphere, leave transparent (background handles the rest)
            if (r2 > 1.0) {
                destData[idx + 3] = 0;
                continue;
            }

            let r_dist = Math.sqrt(r2);
            let nz = Math.sqrt(1 - r2); // Unrotated normal z (facing camera)

            // 1. Rotation around X axis
            let ny_r1 = ny * cosX - nz * sinX;
            let nz_r1 = ny * sinX + nz * cosX;

            // 2. Rotation around Y axis
            let nx_f = nx * cosY - nz_r1 * sinY;
            let nz_f = nx * sinY + nz_r1 * cosY;
            let ny_f = ny_r1;

            // 3. Map to spherical coordinates
            // Ensure bounds for asin
            ny_f = Math.max(-1, Math.min(1, ny_f));
            let phi = Math.asin(ny_f); // Latitude: -PI/2 to PI/2
            let theta = Math.atan2(nx_f, nz_f); // Longitude: -PI to PI

            // 4. Map to normalized UV coordinates (0 to 1)
            let u = (theta + Math.PI) * inv2PI;
            let v = (phi + Math.PI / 2) * invPI;

            // 5. Bilinear interpolation of the source image
            let imgX = u * (srcW - 1);
            let imgY = v * (srcH - 1);

            let x1 = Math.floor(imgX);
            let y1 = Math.floor(imgY);
            let x2 = Math.min(x1 + 1, srcW - 1);
            let y2 = Math.min(y1 + 1, srcH - 1);

            let dx = imgX - x1;
            let dy = imgY - y1;
            let invDx = 1 - dx;
            let invDy = 1 - dy;

            let p11 = (y1 * srcW + x1) * 4;
            let p21 = (y1 * srcW + x2) * 4;
            let p12 = (y2 * srcW + x1) * 4;
            let p22 = (y2 * srcW + x2) * 4;

            let wt1 = invDx * invDy;
            let wt2 = dx * invDy;
            let wt3 = invDx * dy;
            let wt4 = dx * dy;

            let red = srcData[p11] * wt1 + srcData[p21] * wt2 + srcData[p12] * wt3 + srcData[p22] * wt4;
            let green = srcData[p11 + 1] * wt1 + srcData[p21 + 1] * wt2 + srcData[p12 + 1] * wt3 + srcData[p22 + 1] * wt4;
            let blue = srcData[p11 + 2] * wt1 + srcData[p21 + 2] * wt2 + srcData[p12 + 2] * wt3 + srcData[p22 + 2] * wt4;
            let sourceAlpha = srcData[p11 + 3] * wt1 + srcData[p21 + 3] * wt2 + srcData[p12 + 3] * wt3 + srcData[p22 + 3] * wt4;

            // Camera-facing illumination (light is attached to the view)
            let illumination = ambientLight + lightIntensity * nz;

            // Anti-aliasing map corresponding to outskirt of the sphere
            let edgeAlpha = Math.min(1, (1 - r_dist) * R);
            
            // Final pixel output
            destData[idx] = red * illumination;
            destData[idx + 1] = green * illumination;
            destData[idx + 2] = blue * illumination;
            destData[idx + 3] = edgeAlpha * sourceAlpha;
        }
    }

    // Since we want standard alpha blending over the requested background, 
    // we put the imageData to an intermediary canvas, then draw it over the primary canvas.
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = s;
    tempCanvas.height = s;
    tempCanvas.getContext('2d').putImageData(destImageData, 0, 0);

    ctx.drawImage(tempCanvas, 0, 0);

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Sphere Map Image Generator is a tool that maps a 2D image onto a 3D sphere projection. It allows users to transform a flat image into a spherical representation, with adjustable controls for rotation on both the X and Y axes, lighting intensity to simulate depth, and custom background colors. This tool is useful for graphic designers, 3D artists, and developers who need to create spherical textures, mockups, or visual assets for digital environments and simulations.

Leave a Reply

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