{"id":20687093,"url":"https://github.com/jolifantobambla/webgpu-sky-atmosphere","last_synced_at":"2026-01-07T12:53:17.414Z","repository":{"id":250477937,"uuid":"816215032","full_name":"JolifantoBambla/webgpu-sky-atmosphere","owner":"JolifantoBambla","description":"A WebGPU implementation of Hillaire's atmosphere model","archived":false,"fork":false,"pushed_at":"2025-04-06T11:51:13.000Z","size":2263,"stargazers_count":14,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-09T12:24:09.470Z","etag":null,"topics":["atmosphere","gpu","graphics","sky","webgpu"],"latest_commit_sha":null,"homepage":"https://jolifantobambla.github.io/webgpu-sky-atmosphere/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JolifantoBambla.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-17T09:22:13.000Z","updated_at":"2025-04-06T11:50:34.000Z","dependencies_parsed_at":"2024-10-26T15:20:52.954Z","dependency_job_id":"a62846c6-63ce-4266-9696-747cd356b63a","html_url":"https://github.com/JolifantoBambla/webgpu-sky-atmosphere","commit_stats":null,"previous_names":["jolifantobambla/webgpu-sky-atmosphere"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fwebgpu-sky-atmosphere","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fwebgpu-sky-atmosphere/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fwebgpu-sky-atmosphere/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fwebgpu-sky-atmosphere/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JolifantoBambla","download_url":"https://codeload.github.com/JolifantoBambla/webgpu-sky-atmosphere/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253453157,"owners_count":21911049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atmosphere","gpu","graphics","sky","webgpu"],"created_at":"2024-11-16T22:55:49.309Z","updated_at":"2026-01-07T12:53:17.380Z","avatar_url":"https://github.com/JolifantoBambla.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebGPU Sky / Atmosphere\nA WebGPU implementation of Hillaire's atmosphere model ([A Scalable and Production Ready\nSky and Atmosphere Rendering Technique](https://sebh.github.io/publications/egsr2020.pdf)).\nRenders the clear sky / atmosphere for both ground and space views as a post process.\n\n\n## Docs\n\nFind the docs [here](https://jolifantobambla.github.io/webgpu-sky-atmosphere/).\n\nOr try the [demo](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/) (requires WebGPU support).\nIt comes in multiple flavors:\n - [Cornette-Shanks for Mie scattering](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/)\n - [Henyey-Greenstein + Draine for Mie scattering](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?hg_draine)\n - [Two suns, Cornette-Shanks](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?two_suns\u0026uniform_sky_view)\n - [Two suns, Henyey-Greenstein + Draine](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?two_suns\u0026uniform_sky_view\u0026hg_draine)\n - [Timings, Cornette-Shanks](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?timestamp_query)\n - [Timings, Henyey-Greenstein + Draine](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?timestamp_query\u0026hg_draine)\n\n\n## Installation\n\n### NPM\n\n```bash\nnpm install webgpu-sky-atmosphere\n```\n\n```js\nimport { SkyAtmosphereLutRenderer } from 'webgpu-sky-atmosphere';\n```\n\n### From GitHub\n\n```js\nimport { SkyAtmosphereLutRenderer } from 'https://jolifantobambla.github.io/webgpu-sky-atmosphere/dist/1.x/webgpu-sky-atmosphere.module.min.js';\n```\n\n## Usage\n\n### Quick Start\n\nTo render the clear sky / atmosphere, use a `SkyAtmosphereComputeRenderer`:\n\n```js\nimport { SkyAtmosphereComputeRenderer } from 'webgpu-sky-atmosphere';\n\n// during setup\nconst skyRenderer = SkyAtmosphereComputeRenderer.create(device, {\n  // configurate the renderer here\n  skyRenderer: {\n    backBuffer: {\n      // the sky will be rendered on top of the contents of this...\n      texture: afterLightingTexture,\n    },\n    renderTarget: {\n      // ... results will be written to this texture\n      texture: withSkyAppliedTexture,\n    },\n    depthBuffer: {\n      // ...using the depth buffer to limit ray marching\n      texture: depthBuffer,\n    },\n  },\n});\n\n// or use the async version that initializes all pipelines asynchronously\nconst skyRenderer = await SkyAtmosphereComputeRenderer.createAsync(device, { /* config */ });\n\n\n// during render loop\nconst skyUniforms = {\n  camera: {\n    position: [ /* world space position */ ],\n    inverseView: [ /* inverse view matrix */ ],\n    inverseProjection: [ /*inverse projection matrix */ ],\n  },\n  screenResolution: [ /* width, height */ ],\n  sun: {\n    direction: [ /* normalized direction to the sun */ ],\n  },\n};\nconst skyPass = commandEncoder.beginComputePass();\nskyRenderer.renderLutsAndSky(skyPass, skyUniforms);\nskyPass.end();\n\n\n// and in case of a resolution change: \nskyRenderer.onResize({\n  depthBuffer,\n  backBuffer,\n  renderTarget,\n});\n```\n\nOr, if you prefer render passes / bundles, use a `SkyAtmosphereRasterRenderer`:\n\n```js\nimport { SkyAtmosphereRasterRenderer } from 'webgpu-sky-atmosphere';\n\n// during setup\nconst renderTargetFormat = 'rgba16float';\nconst skyRenderer = SkyAtmosphereRasterRenderer.create(device, {\n  // configurate the renderer here\n  skyRenderer: {\n    // the format of the render target at location 0\n    renderTargetFormat,\n    // the depth buffer is used to limit the ray marching distance\n    depthBuffer: {\n      texture: depthBuffer,\n    },\n  },\n});\n\n// or use the async version that initializes all pipelines asynchronously\nconst skyRenderer = await SkyAtmosphereRasterRenderer.createAsync(device, { /* config */ });\n\n\n// during render loop\nconst skyUniforms = {\n  // set camera paramters, etc.\n};\n\n// the lookup tables are rendered using a compute pass\nconst lutsPass = commandEncoder.beginComputePass();\nskyRenderer.renderLuts(lutsPass, skyUniforms);\nlutsPass.end();\n\n// the sky is then rendered using a render pass\nconst skyPass = commandEncoder.beginRenderPass({\n  // configure target\n});\nskyRenderer.renderSky(skyPass);\nskyPass.end();\n\n\n// alternatively prepare a render bundle ahead of time, possibly including more post-processes\nconst postProcessEncoder = device.createRenderBundleEncoder({\n  colorFormats: [renderTargetFormat],\n});\nskyRenderer.renderSky(postProcessEncoder);\n// .. encode other post processes that match the bundle's layout\nconst postProcessBundle = postProcessEncoder.finish();\n\n// and during render loop\nconst postProcessPass = commandEncoder.beginRenderPass({ /* ... */ });\npostProcessPass.exectuteBundles([postProcessBundle]);\npostProcessPass.end();\n\n\n// and in case of a resolution change: \nskyRenderer.onResize(depthBuffer);\n```\n\nThe sky rendering post process depends on a couple of internally managed lookup tables.\nIf you only need the lookup tables and want to roll your own sky renderer, use a `SkyAtmosphereLutRenderer`:\n\n```js\nimport { SkyAtmosphereLutRenderer } from 'webgpu-sky-atmosphere';\n\n// during setup\nconst skyRenderer = SkyAtmosphereLutRenderer.create(device, {\n  // configurate the renderer here or use the defaults\n});\n\n// or use the async version that initializes all pipelines asynchronously\nconst skyRenderer = await SkyAtmosphereLutRenderer.createAsync(device, { /* config */ });\n\n\n// during render loop\nconst skyUniforms = {\n  // set camera paramters, etc.\n};\nconst skyPass = commandEncoder.beginComputePass();\nskyRenderer.renderLuts(skyPass, skyUniforms);\nskyPass.end();\n```\n\n### Full-resolution ray marching\n\nThe above renderers default to rendering the clear sky / atmosphere using low-resolution lookup tables. However, it can also be rendered by doing a full-resolution ray marching pass.\nWhile the former method is faster, full-resolution ray marching produces smoother volumetric shadows and allows for colored transmittance.\nIt also produces a much smoother transition when moving from the top layers of the atmosphere to outer space\nA typical scenario would be to switch to full-resolution ray marching if the camera is above a certain altitude threshold by passing the corresponding flag to `renderLutsAndSky` / `renderSky`:\n\n```js\nconst useFullResolutionRayMarch = /* true if camera is above altitude threshold */;\n\nskyRenderer.renderLutsAndSky(computePass, config, null, useFullResolutionRayMarch);\n\nskyRenderer.renderSky(renderPass, useFullResolutionRayMarch);\n```\n\nTo use full-resolution ray marching instead of the faster lookup table-based approach by default, change the default behavior via the config:\n\n```js\nconst config = {\n  skyRenderer: {\n    defaultToPerPixelRayMarch: true,\n  },\n  ...\n};\n```\n\nIn addition to the two sky rendering methods, it is also possible to use a lookup table for the distant sky while doing a per-pixel ray march for each pixel with a valid depth buffer value.\nWhile this is cheaper than doing a full-resolution ray march, volumetric shadows will not be rendered for distant sky pixels.\nTo enable this hybrid mode, set up the config like this:\n\n```js\nconst config = {\n  skyRenderer: {\n    rayMarch: {\n      rayMarchDistantSky: false,\n    },\n    ...\n  },\n  ...\n};\n```\n\n#### Single-pipeline renderers\n\nBoth `SkyAtmosphereComputeRenderer` and `SkyAtmosphereRasterRenderer` internally manage two sky rendering pipelines, one for each sky rendering method.\nTo create a renderer with only one pipeline, use the following variants:\n\n```js\nconst skyRenderer = SkyRayMarchComputeRenderer.create(device, { /* config */ });\nconst skyRenderer = SkyWithLutsComputeRenderer.create(device, { /* config */ });\n\nconst skyRenderer = SkyRayMarchRasterRenderer.create(device, { /* config */ });\nconst skyRenderer = SkyWithLutsRasterRenderer.create(device, { /* config */ });\n```\n\n### Atmosphere model\n\nThe atmosphere of a telluric planet, i.e., a planet with a solid planetery surface, is modelled by three components:\n\n * Rayleigh theory models the wavelength dependent scattering of light interacting with tiny air molecules. In Earth's atmosphere, it is ressponsible for the blue color of the sky.\n * Mie theory models how light is scattered around and absorbed by larger aerosols like dust or pollution. It is almost independent of wavelength and most of the incoming light is scattered in the forward direction. In Earth's atmosphere, it is responsible for the white glare around the sun.\n * Extra absorption layers: On Earth, light is also absorbed by the ozone in the atmosphere contributing to the sky's blue color when the sun is low.\n\nBy default, the sky renderers will use an Earth-like atmosphere with the origin on the planet's top pole, created with...\n\n```js\nconst atmosphere = makeEarthAtmosphere();\n```\n\nTo create a custom atmosphere, adjust the parameters to your liking (read the [docs](https://jolifantobambla.github.io/webgpu-sky-atmosphere/interfaces/Atmosphere) for more information on the indivdual parameters of an `Atmosphere`):\n\n```js\nconst config = {\n  atmosphere: {\n    rayleigh: { /* ... */ },\n    mie: { /* ... */ },\n    absorption: { /* ... */ },\n    ...\n  },\n  ...\n};\n```\n\nAll atmosphere parameters can be updated at runtime:\n\n```js\n// passing an atmosphere to renderLutsAndSky or renderLuts will automatically update the atmosphere and corresponding lookup tables\nskyRenderer.renderLutsAndSky(passEncoder, uniforms, newAtmosphere);\n\nskyRenderer.renderLuts(passEnoder, uniforms, newAtmosphere);\n\n\n// alternatively, update the atmosphere parameters first and re-render the corresponding lookup tables later\nskyRenderer.updateAtmosphere(newAtmosphere);\n// ... later\nskyRenderer.renderConstantLuts(passEncoder);\n```\n\n#### Mie phase approximation\n\nTwo approximations of the Mie phase function are supported:\n - Cornette-Shanks (default) (see it [live](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/))\n - Henyey-Greenstein + Draine as published by [Jendersie and d'Eon](https://research.nvidia.com/labs/rtr/approximate-mie/) (see it [live](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?hg_draine))\n\nTo switch to the Henyey-Greenstein + Draine approximation use the `mieHgDrainePhase` config parameter:\n\n```js\n// use the default constant droplet diameter for the Mie phase approximation\n// in this case, the atmosphere's `mie.phaseParam` is ignored\nconst config = {\n  mieHgDrainePhase: {},\n  ...\n};\n\n// or: override the constant droplet diameter\n// in this case, the atmosphere's `mie.phaseParam` is ignored\nconst config = {\n  mieHgDrainePhase: {\n    constantDropletDiameter: 3.6,\n  },\n  ...\n};\n\n// or: allow changing the droplet diameter at runtime\n// in this case, the atmosphere's `mie.phaseParam` is interpreted as the droplet diameter size\nconst config = {\n  mieHgDrainePhase: {\n    useConstantDropletDiameter: true,\n  },\n  ...\n};\n```\n\n#### Scale\nAll sky renderers use the distance scale 1 = 1km.\n\nTo adjust the scale of the atmosphere to correspond your engine's scale, e.g., 1 = 1m, set\n\n```js\nconst config = {\n  fromKilometersScale: 1000.0,\n  ...\n};\n```\n\n#### Positioning the atmosphere\n\nTo initialize an Earth-like atmosphere to use a different origin, use \n\n```js\n// using a specific center\nconst center = [ /* world space position of the planet's center */ ];\nconst config = {\n  atmosphere: makeEarthAtmosphere(center),\n  ...\n};\n\n// using the default center (origin is on the top pole) but with the z axis pointing up\nconst yUp = false;\nconst config = {\n  atmosphere: makeEarthAtmosphere(null, yUp),\n  ...\n};\n```\n\n### Light sources\n\nTheoretically, an arbitrary number of light sources could influence the atmosphere. However, for performance reasons, only up to two directional light sources are considered.\n\nAt runtime, light source parameters are set through `Uniforms` passed to the renderer:\n\n```js\nconst uniforms = {\n  sun: {\n    direction: [ /* normalized direction to the light source */ ],\n    illuminance: [ /* illuminance at the top of the atmosphere */ ],\n  },\n  moon: {\n    // has same structure as the sun  \n  },\n  ...\n};\nskyRenderer.renderLutsAndSky(passEncoder, uniforms);\n```\n\nBy default, only one light source is used. A second light source can be enabled via the config's `lights.useMoon` property.\n\nWhen using multiple light sources, it is recommended to change the default parameterization of the sky view lookup table.  \nThe default parameterization assumes a single dominant light source with symmetric contributions and covers only one hemisphere.\n\nTo cover the full azimuthal range, set `lookUpTables.skyViewLut.uniformParameterizationConfig`.  \nThis allows multiple light directions to be fully represented but comes at the cost of reduced angular resolution for individual light sources.\n\n```js\nconst config = {\n    ...\n    lights: {\n        useMoon: true,\n    },\n    lookUpTables: {\n        skyViewLut: {\n            uniformParameterizationConfig: {},\n        },\n    },\n    ...\n}\n```\n\nCheck out this [demo with two suns](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?two_suns\u0026uniform_sky_view) for an example.\n\n#### Sun disk rendering\n\nA simple implementation for rendering a sun and a moon disk is provided.\nUse the `Uniforms` to adjust the sun disk's appearance:\n\n```js\nconst uniforms = {\n  sun: {\n    ...\n    diskAngularDiameter: 0.0095, // angular diameter in radians\n    diskLuminanceScale: 20.0, // make the disk appear brighter\n  },\n  ...\n};\n```\n\nThe provided implementation can be disabled using the `lights` property of the config:\n\n```js\nconst config = {\n    ...\n    lights: {\n        renderSunDisk: false,\n        renderMoonDisk: false,\n    },\n    ...\n}\n```\n\n#### Integrating shadows\n\nUser-controlled shadowing can be integrated into a `SkyAtmosphereLutRenderer` by injecting bind groups and WGSL code into the sky / atmosphere rendering pipelines and shaders via the `shadow` property of the `SkyAtmosphereConfig` used to create the renderer.\n\nMost importantly, the WGSL code provided by the config must implement the following function:\n\n```wgsl\nfn get_shadow(world_space_position: vec3\u003cf32\u003e, light_index: u32) -\u003e f32\n```\n\nInternally, `get_shadow` will be called for each ray marching sample.\nIt should return a floating point value in the range [0, 1], where 1 implies that the world space position given (`world_space_position`) is not in shadow.\nThe `light_index` parameter refers to the index of the atmosphere light, where `0` refers to the sun and `1` refers to the moon.\nAdditionally, the WGSL code should also define all external bind groups required by the shadowing implementation.\n\nExcept for the `get_shadow` interface, the `SkyAtmosphereLutRenderer`s are agnostic to the shadowing technique used.\n\nFor example, for a simple shadow map for just the sun, this could look like this:\n```js\nconst config = {\n    ...\n    shadow: {\n        bindGroupLayouts: [shadowBindGroupLayout],\n        bindGroups: [device.createBindGroup({\n            label: 'shadow',\n            layout: shadowBindGroupLayout,\n            entries: [\n                {binding: 0, resource: {buffer: sunViewProjectionBuffer}},\n                {binding: 1, resource: device.createSampler({compare: 'less'})},\n                {binding: 2, resource: shadowMapView},\n            ],\n        })],\n        wgslCode: `\n            @group(1) @binding(0) var\u003cuniform\u003e sun_view_projection: mat4x4\u003cf32\u003e;\n            @group(1) @binding(1) var shadow_sampler: sampler_comparison;\n            @group(1) @binding(2) var shadow_map: texture_depth_2d;\n            \n            fn get_shadow(p: vec3\u003cf32\u003e, light_index: u32) -\u003e f32 {\n                if light_index == 0 {\n                    var shadow_pos = (sun_view_projection * vec4(p, 1.0)).xyz;\n                    shadow_pos = vec3(shadow_pos.xy * vec2(0.5, -0.5) + 0.5, shadow_pos.z);\n                    if all(shadow_pos \u003e= vec3\u003cf32\u003e()) \u0026\u0026 all(shadow_pos \u003c vec3(1.0)) {\n                        return textureSampleCompareLevel(shadow_map, shadow_sampler, shadow_pos.xy, shadow_pos.z);\n                    }\n                }\n                return 1.0;\n            }\n        `\n    },\n    ...\n}\n```\n\n### Custom uniform buffers\n\nIt is likely that some or even all uniforms used by a `SkyAtmosphereLutRenderer` are already available on the GPU in some other buffer(s) in your engine.\nTo replace the `SkyAtmosphereLutRenderer`'s internal uniform buffer by one or more user-controlled uniform buffers, configure the renderer to inject external bind groups and WGSL code, similar to how shadows are integrated into the renderer:\n\n```js\nconst config = {\n    ...\n    customUniformsSource: {\n        bindGroupLayouts: [uniformsBindGroupLayout],\n        bindGroups: [uniformsBindGroup],\n        wgslCode: `\n            @group(2) @binding(0) var\u003cuniform\u003e custom_uniform_buffer: CustomUniforms;\n            \n            fn get_camera_world_position() -\u003e vec3\u003cf32\u003e {\n              return custom_uniform_buffer.camera.position;\n            }\n\n            fn get_ray_march_min_spp() -\u003e f32 {\n              return 16.0;\n            }\n\n            // ... and so on\n            \n            // this needs to implement a larger interface\n            // read the docs for more information\n        `\n    },\n    ...\n}\n```\n\n### Lookup tables\n\nBoth sky rendering methods depend on a couple of cheap-to-compute (see [demo with performance metrics (requires WebGPU and 'timestamp-query' support)](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/?timestamp_query)) lookup tables:\n\n * Transmittance LUT: stores the colored transmittance towards the top of the atmosphere parameterized by the sample height and direction\n * Multiple Scattering LUT: stores the contribution of multiple scattering parameterized by the sample height and sun direction\n * Sky View LUT: stores the view of the distant sky for the current camera position parameterized by latitude and longitude\n * Aerial Perspective LUT: stores the aerial perspective for the current camera frustum as a volume texture (rgb-colored luminance reaching the camera from the froxel's center and grayscale transmittance from the camera to the froxel's center)\n\nTo change the format or size of any of the lookup tables, use the `lookUpTables` property of the config, e.g.:\n\n```js\nconst config = {\n  lookUpTables: {\n    transmittanceLut: {\n      format: 'rgba32float', // note that the use of 'rgba32float' requires the device-feature 'float32-filterable' to be enabled\n    },\n    aerialPerspectiveLut: {\n      size: [64, 64, 32],\n    },\n  },\n  ...\n};\n```\n\nFor more information on the individual options, please refer to the [documentation](https://jolifantobambla.github.io/webgpu-sky-atmosphere/interfaces/SkyAtmosphereLutConfig).\n\nThe transmittance and the multiple scattering lookup table are constant for a given atmosphere. This is why they are rendered during the `SkyAtmosphereLutRenderer`'s constructor by default and re-rendered by `renderLutsAndSky` / `renderLuts` only if the optional `atmopshere` parameter is set.\nTo re-render the two lookup tables outside of these scenarios, call:\n\n```js\nskyRenderer.renderConstantLuts(\n  computePassEncoder,\n  // this is optional\n  // if this is undefined, the internal atmosphere parameters will not be updated but the lookup tables will still be rendered\n  atmosphere,\n);\n```\n\nWhile the constant lookup tables are used by both sky rendering methods, the sky view and aerial perspective lookup tables are not used by the full-resolution ray marching method.\nSince they are view dependent, they are re-rendered whenever new `Uniforms` are passed to `renderLutsAndSky` / `renderLuts` and the lookup table based sky rendering technique is chosen.\nTo only update these two lookup tables, call:\n\n```js\nskyRenderer.renderDynamicLuts(\n  computePassEncoder,\n  // passing the uniforms is optional\n  // if this is undefined, the internal uniform buffer will not be updated\n  uniforms,\n);\n```\n\nAlternatively, each lookup table can be rendered individually.\nSee the [documentation](https://jolifantobambla.github.io/webgpu-sky-atmosphere/classes/SkyAtmosphereLutRenderer) for more details.\n\n\n## Integrating this library into a renderer\n\nThis library makes a couple of assumptions about the render engine that uses it.\nFor a `SkyAtmosphereLutRenderer` to produce nice results, the render engine should...\n\n * ...use some kind of tone-mapping operator\n * ...use either dithering or temporal anti-aliasing to get rid of banding artefacts introduced by the use of low-resolution lookup tables\n * ...use a bloom filter to give the sun disk a nicer look\n * ...use temporal anti-aliasing to get rid of the noise introduced by randomizing ray offsets for full-resolution ray marching\n\nThe [demo](https://jolifantobambla.github.io/webgpu-sky-atmosphere/demo/) uses a hard-coded tonemapping operator and gradient noise-based dithering to address some of these issues.\n\n\n## Contributions\n\nContributions are very welcome. If you find a bug or think some important functionality is missing, please file an issue [here](https://github.com/JolifantoBambla/webgpu-sky-atmosphere/issues). If want to help out yourself, feel free to submit a pull request [here](https://github.com/JolifantoBambla/webgpu-sky-atmosphere/pulls).\n\n\n## Acknowledgements\n\nThis library is originally a WebGPU port of Sébastien Hillaire's [demo implementation](https://github.com/sebh/UnrealEngineSkyAtmosphere) for his paper [A Scalable and Production Ready\nSky and Atmosphere Rendering Technique](https://sebh.github.io/publications/egsr2020.pdf).\nThe original demo was released under the MIT licence by Epic Games, Inc.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjolifantobambla%2Fwebgpu-sky-atmosphere","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjolifantobambla%2Fwebgpu-sky-atmosphere","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjolifantobambla%2Fwebgpu-sky-atmosphere/lists"}