www.xbdev.net
xbdev - software development
Wednesday January 15, 2025
Home | Contact | Support | WebGPU Graphics and Compute ...
     
 

WebGPU/WGSL Tutorials and Articles

Graphics and Compute ...

 


Generating a realistic sunset in less than 50 shader lines (with no comments).
Generating a realistic sunset in less than 50 shader lines (with no comments).


Fake Sky Sunset (Animated)


Very simple but powerful sunset effect using gradients (and a checkerboard for the ground).

If you're new to shaders and ray-tracing concepts - this is a good starting point - as the implementation is less than 50 lines (without all the comments).



Complete Code for the Sexy Sunset


The code has been given lots of comments so you can make out what it does!

@group(0) @binding(0) var  mySamplersampler;
@
group(0) @binding(1) var  myTexturetexture_2d<f32>;
@
group(0) @binding(2) var <uniformmytimer f32;

/*
skyColor combines various optical and atmospheric effects to create a realistic sky shader.

1. Atmospheric Scattering - The reddish tones simulate the scattering of shorter wavelengths (blue/green) near the horizon. The bluish tones simulate Rayleigh scattering, which dominates at higher altitudes.
2. Fog - Below the horizon (yd), the fog effect gradually blends the scene with gray to simulate distance.
3 Sunlight -  A diffuse glow gives the sun a soft appearance. A specular highlight creates the bright central spot of the sun.
4. Exponential Decays - These simulate the attenuation of light due to atmospheric density.
*/
fn skyColor(rdvec3<f32>) -> vec3<f32> {
    
// Define the direction of the sun in the sky, slightly offset above the horizon.
    // Normalized to ensure it is a unit vector.
    
let sundir normalize(vec3<f32>(0.00.11.0));
    
    
// `yd` represents the downward component of the ray's y-axis direction,
    // clamped to the range [negative infinity, 0.0].
    // This is used later to simulate fog and atmospheric effects.
    
let yd min(rd.y0.0);
    
    
// `rd_y_clamped` is the upward component of the ray's y-axis direction,
    // clamped to the range [0.0, positive infinity].
    // This is used for atmospheric color calculations above the horizon.
    
let rd_y_clamped max(rd.y0.0);

    
// Initialize the base color as black (no contribution yet).
    
var col vec3<f32>(0.0);

    
// Add a reddish hue to the sky, primarily contributing to the lower atmosphere.
    // This simulates the red and green scatter near the horizon.
    
col += vec3<f32>(
        
0.4,                                // Red channel
        
0.4 exp(-rd_y_clamped 20.0) * 0.15// Green channel fades with altitude
        
0.0                                 // No contribution to the blue channel
    
) * exp(-rd_y_clamped 9.0);           // Exponential decay simulating atmospheric absorption.

    // Add a bluish hue to the sky, simulating Rayleigh scattering in the upper atmosphere.
    
col += vec3<f32>(
        
0.3// Light contribution to red
        
0.5// Medium contribution to green
        
0.6  // Strong contribution to blue
    
) * (1.0 exp(-rd_y_clamped 8.0))    // Smooth transition effect as rd_y increases.
      
exp(-rd_y_clamped 0.9);           // Exponential decay for realism.

    // Simulate fog by mixing the sky color with a flat gray (vec3(0.3)).
    // The blending factor depends on the downward component of the ray (`yd`).
    
col mix(
        
col 1.2,                         // Enhance sky brightness slightly before mixing.
        
vec3<f32>(0.3),                    // Fog color (gray).
        
1.0 exp(yd 100.0)              // Fog intensity increases below the horizon.
    
);

    
// Add sunlight contributions:
    // 1. A warm, diffuse glow around the sun.
    
col += vec3<f32>(1.00.80.55)       // Sun color (soft yellow-orange).
        
pow(max(dot(rdsundir), 0.0), 15.0// Sun's diffuse intensity (15th power for sharpness).
        
0.6;                             // Scale down the intensity for balance.

    // 2. A sharp specular highlight for the sun itself, with very high power for sharpness.
    
col += pow(max(dot(rdsundir), 0.0), 150.0// Specular highlight intensity (150th power for sharp focus).
        
0.15;                            // Scale down the specular contribution.

    // Return the final computed color for the sky.
    
return col;
}


fn 
mymod(x:f32y:f32) -> f32
{
    return ( 
floor(x/y) );
}


fn 
checker(pvec2<f32>) -> f32 {
    
// Compute the floor of the input vector
    
let floored_p floor(p);
    
    
// Apply modulus operation to wrap the values within 0-2
    
let mod_p vec2<f32>( mymod(floored_p.x,2.0), mymod(floored_p.y,2.0) );
    
    
// Sum the components of the vector
    
let sum mod_p.mod_p.y;
    
    
// Compute the final modulus
    
let checker_value mymod(sum2.0);
    
    
// Return based on the result of the modulus
    
if (checker_value 1.0) {
        return 
0.25;
    } 
    return 
0.1;
}


/*
    SHADER ENTRY POINT
*/
@fragment
fn main(@location(0uvsvec2<f32>) -> @location(0vec4<f32> {
    
// Define the screen resolution. This is a constant that determines the size of the render output.
    // It's used to adjust the aspect ratio and for various calculations in the shader.
    
let resolution vec2<f32>(512.0512.0);

    
// UV coordinates. These are normalized to [0, 1] across the screen space.
    // Convert normalized UVs into a range of [-1, 1], effectively creating clip space coordinates.
    // This is a common step in rendering pipelines to account for camera space calculations.
    
let v vec2<f32>(-1.0) + 2.0 uvs;

    
// Compute the screen's aspect ratio, which is the ratio of width to height.
    // This is used to scale the x-axis so that the image doesn't appear stretched or squished.
    
let aspect_ratio resolution.resolution.y;

    
// Construct the direction vector `dir` for a ray originating from the camera.
    // The x-component is scaled by the aspect ratio, the y-component is offset for a slight tilt,
    // and the z-component points forward into the scene.
    
let dir normalize(vec3<f32>(v.aspect_ratiov.0.51.5));

    
// Compute the color of the checkerboard pattern based on the ray direction.
    // The pattern is scaled by dividing the xz components of `dir` by `dir.y`.
    // A time-based offset (`-mytimer * 2.0`) adds animation to the checkerboard pattern.
    
let checker_col vec3<f32>(checker(dir.xz dir.0.5 vec2<f32>(0.0, -mytimer 2.0)));

    
// Compute the reflection vector for the ray `dir` relative to a flat surface with a normal of (0, 1, 0).
    // This simulates light bouncing off the ground plane into the scene.
    
let reflected_dir reflect(dirvec3<f32>(0.01.00.0));

    
// Combine the checkerboard color and the sky color reflected in the ground.
    // The reflection is scaled down by 0.3 to reduce its intensity.
    
var col checker_col skyColor(reflected_dir) * 0.3;

    
// Add atmospheric blending by interpolating (`mix`) between the current color (`col`)
    // and the sky color along the ray direction (`dir`).
    // The blending factor is controlled by an exponential decay function, simulating atmospheric density.
    
col mix(colskyColor(dir), exp(-max(-v.9.0 4.80.0)));

    
// Apply a vignette effect to darken the corners of the image.
    // The effect is strongest where the UV coordinates are farthest from the center.
    // A smooth transition is achieved using a power function.
    
let vignette 0.7 0.3 pow(uvs.uvs.* (1.0 uvs.x) * (1.0 uvs.y) * 16.00.1);
    
col *= vignette;

    
// Output the final color as a `vec4`, where the alpha value is set to 1.0 for full opacity.
    
return vec4<f32>(col1.0);
}



The sky is animated to give you a feeling of always moving towards the sunset (scrolling the checkered floor).
The sky is animated to give you a feeling of always moving towards the sunset (scrolling the checkered floor).



Things to Try


• Animate the position of the sun - so it either moves up or down or across the sky over time
• Animate the colors (so they gradually become darker and lighter)
• Try changing the ground - instead of a checkerboard something else (other patterns)
• Add user interface (pass parameters via uniform structure) - so you can interactively tinker with the various parameters to create all sorts of sky types
• If you've not noticed - their isn't any randomness in the effect - just gradients - so mixing in a bit of noise can add a new aspect of realism
• Try adding in some simple blobs for clouds (so the sky isn't so clear)
• Add in a second sun! Star Wars or Riddick type worlds....
• Add in a second pass 'blur' to create a heat phase


Resources & Links


• Full Implementation (Source Code and Interactive Demo) LINK




























WebGPU Development Pixels - coding fragment shaders from post processing to ray tracing! WebGPU by Example: Fractals, Image Effects, Ray-Tracing, Procedural Geometry, 2D/3D, Particles, Simulations WebGPU Games WGSL 2d 3d interactive web-based fun learning WebGPU Compute WebGPU API - Owners WebGPU Development Cookbook - coding recipes for all your webgpu needs! WebGPU & WGSL Essentials: A Hands-On Approach to Interactive Graphics, Games, 2D Interfaces, 3D Meshes, Animation, Security and Production Kenwright graphics and animations using the webgpu api 12 week course kenwright learn webgpu api kenwright programming compute and graphics applications with html5 and webgpu api kenwright real-time 3d graphics with webgpu kenwright webgpu for dummies kenwright webgpu api develompent a quick start guide kenwright webgpu by example 2022 kenwright webgpu gems kenwright webgpu interactive compute and graphics visualization cookbook kenwright wgsl webgpu shading language cookbook kenwright WebGPU Shader Language Development: Vertex, Fragment, Compute Shaders for Programmers Kenwright wgsl webgpugems shading language cookbook kenwright WGSL Fundamentals book kenwright WebGPU Data Visualization Cookbook kenwright Special Effects Programming with WebGPU kenwright WebGPU Programming Guide: Interactive Graphics and Compute Programming with WebGPU & WGSL kenwright Ray-Tracing with WebGPU kenwright



 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2024 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.