AI GENERATED

スカイミラーボール

by touyou

PROMPT

明るい空の中煌めく星々

DATE
2026/6/13
SOURCE
AI GENERATED
MODEL
gemini-2.5-flash
LIKES
0
VIEW SHADER CODE
#define PI 3.14159265359

// Hash functions from iq (slightly modified versions)
float hash11(float p) {
    p = fract(p * .1031);
    p *= p + 33.33;
    p *= p + p;
    return fract(p);
}

// Fixed hash21 to correctly handle vector types and assignments
vec2 hash21(float p_in) {
    // p_in is a float. We need to derive a vec2 from it.
    vec2 p = fract(p_in * vec3(.1031, .1030, .0973)).xy;
    
    // The original `p += dot(p, p + 33.33);` had type issues:
    // 1. `p + 33.33` needs `vec2(33.33)` for scalar-vector addition.
    // 2. `dot(vec2, vec2)` returns a float.
    // 3. `vec2 += float` is not allowed in GLSL ES 3.00.
    // We explicitly calculate the dot product and then add it as a vec2.
    float dot_result = dot(p, p + vec2(33.33));
    p = p + vec2(dot_result); // Apply the scalar result to both components of p.
    
    return fract((p.x + p.y) * p);
}

// Cosine palette function
vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
    return a + b * cos(2.0 * PI * (c * t + d));
}

// 2D Value Noise (similar to snoise but simpler to implement inline)
float snoise(vec2 p) {
    vec2 ip = floor(p);
    vec2 fp = fract(p);
    fp = fp * fp * (3.0 - 2.0 * fp); // Smoothstep interpolation curve

    float a = hash11(ip.x + ip.y * 57.0);
    float b = hash11(ip.x + 1.0 + ip.y * 57.0);
    float c = hash11(ip.x + (ip.y + 1.0) * 57.0);
    float d = hash11(ip.x + 1.0 + (ip.y + 1.0) * 57.0);

    return mix(mix(a, b, fp.x), mix(c, d, fp.x), fp.y);
}

// Fractional Brownian Motion (FBM) for sky texture
float fbm_sky(vec2 p, float time) {
    float f = 0.0;
    f += 0.5000 * snoise(p * 1.0 + time * 0.05);
    f += 0.2500 * snoise(p * 2.0 + time * 0.08);
    f += 0.1250 * snoise(p * 4.0 + time * 0.12);
    f += 0.0625 * snoise(p * 8.0 + time * 0.15);
    return f;
}

// Generates sparkling stars using a grid-based approach
float starField(vec2 uv, float time) {
    vec2 grid_uv = uv * 40.0; // Scale UV to create a grid of potential star cells
    vec2 i_uv = floor(grid_uv); // Integer part of grid UV (cell ID)
    vec2 f_uv = fract(grid_uv); // Fractional part within cell

    float star_brightness = 0.0;

    // Iterate over a 3x3 neighborhood of cells around the current pixel
    for (int y = -1; y <= 1; y++) {
        for (int x = -1; x <= 1; x++) {
            vec2 neighbor_cell = i_uv + vec2(float(x), float(y));

            // Generate a random seed for this cell based on its ID
            float seed = hash11(dot(neighbor_cell, vec2(12.9898, 78.233)));

            // Only create a star if the random seed is above a threshold (sparse distribution)
            if (seed < 0.9) continue; // Adjust threshold for star density (higher value = fewer stars)

            // Generate a random position within the cell, with subtle animation
            vec2 star_pos_offset = hash21(seed); // Base offset [0,1)
            // Add a subtle wiggle to star positions over time
            star_pos_offset += 0.05 * sin(time * (0.5 + seed) + seed * PI * 2.0) * vec2(1.0, 1.0);

            // Calculate distance from the current pixel's fractional part to this star's offset
            float d = length(f_uv - star_pos_offset);

            // Twinkling effect: modulate brightness over time
            float twinkle_phase_seed = hash11(seed + time * 0.5); // Use time to animate twinkle phase
            float twinkle = sin(time * (1.0 + twinkle_phase_seed * 2.0) + seed * 10.0) * 0.5 + 0.5;
            twinkle = pow(twinkle, 2.0 + twinkle_phase_seed * 2.0); // Sharpen the twinkle effect

            // Glow profile: inverse smoothstep for falloff from center
            float glow_base = smoothstep(0.1, 0.0, d); // Core glow
            glow_base += smoothstep(0.2, 0.1, d) * 0.3; // Fainter halo
            
            // Accumulate brightness for all nearby stars
            star_brightness += glow_base * twinkle * (0.5 + seed * 0.5) * 1.5; // Vary intensity and apply twinkle
        }
    }
    return star_brightness;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    // Normalize coordinates [-aspect, aspect] or [-1, 1]
    vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;

    // --- Sky Background ---
    // Generate subtle noise for the sky, animated over time
    float background_noise = fbm_sky(uv * 2.0 + iTime * 0.05, iTime);
    background_noise = background_noise * 0.5 + 0.5; // Remap noise to [0,1]
    
    // Define a bright sky color palette: light blues, purples, pinks
    vec3 sky_color = palette(background_noise * 0.5 + uv.y * 0.3 + iTime * 0.02,
                             vec3(0.7, 0.8, 1.0), // Base color: light blue
                             vec3(0.3, 0.2, 0.1), // Amplitude for color variation
                             vec3(0.5, 0.4, 0.6), // Frequency for color cycling (pink/purple range)
                             vec3(0.0, 0.1, 0.2)); // Phase offset

    // --- Stars ---
    float stars = starField(uv, iTime);
    // Define a slightly warm white color for the stars
    vec3 star_base_color = vec3(1.0, 0.95, 0.9); 
    vec3 star_color = star_base_color * stars;
    
    // --- Combine Sky and Stars ---
    vec3 final_color = sky_color + star_color * 1.5; // Add stars to sky, boosting their brightness

    // --- Subtle Vignette ---
    // Darken the edges for better composition
    float vignette = smoothstep(1.0, 0.7, length(uv));
    final_color *= vignette * 0.8 + 0.2; 

    // --- Exposure/Gamma correction ---
    // Slightly adjust overall brightness and contrast
    final_color = pow(final_color, vec3(0.8));

    fragColor = vec4(final_color, 1.0);
}

ZIP を展開して .playground を Xcode でダブルクリックし、Live View を表示して ▶ を押すとシェーダーがアニメーションします。Metal ソースは Resources/Shader.metal に独立ファイルとして入っているので、Xcode 上で直接編集できます。