UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

156 lines (114 loc) 5.1 kB
# Clustered Lighting Specification ## 1. GPU Data structures Data is organized into 3 main textures: - Clusters. `type: UINT, format: RGBA, dimension: 3D, filtering: nearest(none)` - R - Offset into lookup texture for lights - G - number of lights - B - Offset into lookup texture for decals - A - number of decals - Lookup. `type: UINT, format: R, dimensions: 2D, filtering: nearest(none)` - R - encoded reference into data texture, where actual lighting information is stored - Data. `type: FLOAT, format: RGBA, dimensions: 2D, filtering: nearest(none)` - RGBA - single `word` of data, you can think of it as a collection of `VEC4`s Below is a glsl snippet with initialization of uniforms for these textures: ```glsl uniform usampler3D fp_t_light_clusters; uniform usampler2D fp_t_light_lookup; uniform sampler2D fp_t_light_data; ``` ## 2. Light Data Format Each light is represented as a collection of `VEC4`s inside the `Data` texture. - Point Light: - `[ position.x, position.y, position.z, radius ]` - `[ color.r, color.g, color.b, intensity ]` - Directional Light: - `[ direction.x, direction.y, direction.z, UNUSED ]` - `[ color.r, color.g, color.b, intensity ]` ## 3. Light reference encoding Lookup texture contains integers that encode both the address of light data, and the type of light found at that address, this is done by encoding light type into lower 2 bits of a UINT32 Light type codes: - 0 - PointLight - 1 - Directional Light - 2 - Spotlight Encoding snippet in JavaScript: ```js /** * * @param {number} address * @param {AbstractLight} light * @returns {number} */ function encode_light_descriptor(address, light) { const light_type = encode_light_type(light); return light_type | (address << 2); } ``` Decoding snippet in GLSL ```glsl ivec2 address_to_data_texture_coordinates(uint address){ // Lookup texture has 128 width uint lookup_index_x = address % 128u; uint lookup_index_y = address >> 7; return ivec2(int(lookup_index_x),int(lookup_index_y)); } // ... uint light_descriptor = texelFetch(fp_t_light_lookup, address_to_data_texture_coordinates(lookup_index), 0 ).r; uint type = (light_descriptor) & 0x3u; uint light_address = light_descriptor >> 2; ``` ## 4. Auxiliary material Convert projection-space depth to linear space ```glsl float convert_depth_to_linear(in float d){ float d_n = 2.0*d - 1.0; float f = fp_f_camera_far; float n = fp_f_camera_near; float fn = f*n; float z_diff = f - n; float denominator = (f + n - d_n * z_diff ); float z_view = (2.0*fn) / denominator; return (z_view - n) / z_diff; } ``` Fetching cluster information from fragment shader inside a forward pass ```glsl // v3_cluster_resolution is resolution of our cluster 3d texture ivec3 v3_cluster_resolution = textureSize(fp_t_light_tiles, 0); ivec3 v3_cluster_position = ivec3( clip_v.x * float(v3_cluster_resolution.x), clip_v.y*float(v3_cluster_resolution.y), (clip_v.z)*float(v3_cluster_resolution.z) ); uvec4 fp_cluster_metadata = texelFetch( fp_t_light_tiles, v3_cluster_position, 0 ).rgba; ``` Perform lighting (point-light only) ```glsl // read light data for(uint i=0u; i < fp_cluster_metadata.y; i++){ uint lookup_index = fp_cluster_metadata.x + i; uint light_descriptor = texelFetch(fp_t_light_lookup, address_to_data_texture_coordinates(lookup_index), 0 ).r; uint type = (light_descriptor) & 0x3u; uint light_address = light_descriptor >> 2; if(type == 0u){ // point light vec4 light_data_0 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address), 0); vec4 light_data_1 = texelFetch(fp_t_light_data, address_to_data_texture_coordinates(light_address+1u), 0); vec3 light_position = light_data_0.xyz; float light_radius = light_data_0.w; vec3 light_color = light_data_1.xyz; float light_intensity = light_data_1.w; PointLight pointlight; pointlight.position = light_position; pointlight.distance = light_radius; pointlight.color = light_color*light_intensity; pointlight.decay = 1.0; fp_getPointDirectLightIrradiance( pointlight, directLight, vViewPosition ); RE_Direct( directLight, geometry, material, reflectedLight ); } else if(type == 1u){ // directional light // ... } } ``` ## References: - [Dr.Strangelight or: How I learned to Stop Worrying and Love the Cluster](https://discourse.threejs.org/t/dr-strangelight-or-how-i-learned-to-stop-worrying-and-love-the-cluster/23104) - [Practical Clustered Shading by Emil Persson](http://www.humus.name/Articles/PracticalClusteredShading.pdf) --- Author: Alexander Goldring, Company Named Limited Private and confidential, copyright (c) Company Named Limited, 2022